....
This commit is contained in:
parent
65cd65b2d8
commit
c0316937e3
@ -46,6 +46,10 @@ template <typename R>
|
||||
concept adc_char_view = std::ranges::view<R> && std::same_as<std::ranges::range_value_t<R>, char>;
|
||||
|
||||
|
||||
template <typename R>
|
||||
concept adc_range_of_view_char_range = std::ranges::range<R> && std::ranges::view<std::ranges::range_value_t<R>> &&
|
||||
std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<R>>, char>;
|
||||
|
||||
// deduce returned type of callable
|
||||
// template <typename T>
|
||||
// using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
|
||||
|
||||
@ -441,4 +441,62 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* join range elements using delimiter between its elements */
|
||||
|
||||
// NOTE: C++23 has std::views::join_with adapter but here I use upto C++20!!!
|
||||
template <std::ranges::input_range R,
|
||||
std::ranges::input_range RD,
|
||||
std::ranges::output_range<std::ranges::range_value_t<RD>> RO>
|
||||
static size_t AdcJoinRange(R& r, const RD& delim, RO& ro)
|
||||
requires std::ranges::range<std::ranges::range_value_t<R>> && // input R is range of ranges
|
||||
std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<R>>, std::ranges::range_value_t<RD>>
|
||||
{
|
||||
auto N = std::ranges::distance(r.begin(), r.end());
|
||||
|
||||
if (!N) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
std::ranges::for_each(r, [&](const auto& el) {
|
||||
std::ranges::copy(el, std::back_inserter(ro));
|
||||
if (++i < N) {
|
||||
std::ranges::copy(delim, std::back_inserter(ro));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
|
||||
// create a range with views of elements of input range and insert a view of input delimiter between them
|
||||
|
||||
template <std::ranges::input_range R, std::ranges::input_range RD, std::ranges::range RO>
|
||||
static size_t AdcReturnRangeElementsView(const R& r, const RD& delim, RO& ro)
|
||||
requires std::ranges::range<std::ranges::range_value_t<R>> && // input R is range of ranges
|
||||
std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<R>>, std::ranges::range_value_t<RD>> &&
|
||||
std::ranges::view<std::ranges::range_value_t<RO>> && // output RO is range of views
|
||||
std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<RO>>, std::ranges::range_value_t<RD>>
|
||||
{
|
||||
auto N = std::ranges::distance(r.begin(), r.end());
|
||||
|
||||
if (!N) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
std::ranges::for_each(r, [&](const auto& el) {
|
||||
std::back_inserter(ro) = {el.begin(), el.end()};
|
||||
if (++i < N) {
|
||||
std::back_inserter(ro) = {delim.begin(), delim.end()};
|
||||
}
|
||||
});
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
} // namespace adc::utils
|
||||
|
||||
177
net/adc_netmsg.h
177
net/adc_netmsg.h
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include "../common/adc_traits.h"
|
||||
#include "../common/adc_utils.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
@ -15,6 +16,9 @@ namespace adc
|
||||
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
||||
class AdcGenericNetMessage
|
||||
{
|
||||
virtual bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; }
|
||||
|
||||
|
||||
// get a copy of message bytes
|
||||
template <traits::adc_output_char_range R>
|
||||
R bytes() const
|
||||
@ -29,13 +33,19 @@ class AdcGenericNetMessage
|
||||
virtual ByteStorageT bytes() const { return bytes<ByteStorageT>(); }
|
||||
|
||||
// get a view of message bytes
|
||||
template <traits::adc_char_view R>
|
||||
// template <std::ranges::range R>
|
||||
// requires std::ranges::view<std::ranges::range_value_t<R>>
|
||||
template<traits::adc_range_of_view_char_range R>
|
||||
R bytesView() const
|
||||
{
|
||||
return R{_bytes.begin(), _bytes.end()};
|
||||
R r;
|
||||
|
||||
r.emplace_back(_bytes.begin(), _bytes.end());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual ByteViewT bytesView() const { return bytesView<ByteViewT>(); }
|
||||
virtual std::vector<ByteViewT> bytesView() const { return bytesView<std::vector<ByteViewT>>(); }
|
||||
|
||||
protected:
|
||||
ByteStorageT _bytes;
|
||||
@ -47,8 +57,7 @@ namespace constants
|
||||
{
|
||||
|
||||
static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " ";
|
||||
static constexpr char ADC_DEFAULT_KEY_PARAM_DELIMITER[] = " ";
|
||||
static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " ";
|
||||
static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " ";
|
||||
|
||||
} // namespace constants
|
||||
|
||||
@ -63,6 +72,9 @@ class AdcTokenNetMessage : public AdcGenericNetMessage<ByteStorageT, ByteViewT>
|
||||
public:
|
||||
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
||||
|
||||
|
||||
virtual bool empty() const { return _tokens.empty(); }
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R bytes() const
|
||||
{
|
||||
@ -73,37 +85,166 @@ public:
|
||||
}
|
||||
|
||||
|
||||
std::ranges::for_each(_tokens | std::views::take(_tokens.size()), [&r](const auto& el) {
|
||||
std::ranges::copy(el, std::back_inserter(r));
|
||||
std::ranges::copy(tokenDelimiter, std::back_inserter(r));
|
||||
});
|
||||
// std::ranges::for_each(_tokens | std::views::take(_tokens.size()-1), [&r](const auto& el) {
|
||||
// std::ranges::copy(el, std::back_inserter(r));
|
||||
// std::ranges::copy(tokenDelimiter, std::back_inserter(r));
|
||||
// });
|
||||
|
||||
std::ranges::copy(_tokens.back(), std::back_inserter(r));
|
||||
// std::ranges::copy(_tokens.back(), std::back_inserter(r));
|
||||
|
||||
utils::AdcJoinRange(_tokens, tokenDelimiter, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
template <std::ranges::range R>
|
||||
requires std::ranges::view<std::ranges::range_value_t<R>>
|
||||
// template <std::ranges::range R>
|
||||
// requires std::ranges::view<std::ranges::range_value_t<R>>
|
||||
template<traits::adc_range_of_view_char_range R>
|
||||
R bytesView() const
|
||||
{
|
||||
R r;
|
||||
|
||||
std::ranges::for_each(_tokens | std::views::take(_tokens.size()), [&r](const auto& el) {
|
||||
std::ranges::range_value_t<R> v{el.begin(), el.end()};
|
||||
std::back_inserter(r) = {el.begin(), el.end()};
|
||||
std::back_inserter(r) = {tokenDelimiter.begin(), tokenDelimiter.end()};
|
||||
});
|
||||
if (_tokens.empty()) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::back_inserter(r) = {_tokens.back().begin(), _tokens.back().end()};
|
||||
// std::ranges::for_each(_tokens | std::views::take(_tokens.size()-1), [&r](const auto& el) {
|
||||
// // std::ranges::range_value_t<R> v{el.begin(), el.end()};
|
||||
// std::back_inserter(r) = {el.begin(), el.end()};
|
||||
// std::back_inserter(r) = {tokenDelimiter.begin(), tokenDelimiter.end()};
|
||||
// });
|
||||
|
||||
// std::back_inserter(r) = {_tokens.back().begin(), _tokens.back().end()};
|
||||
|
||||
utils::AdcReturnRangeElementsView(_tokens, tokenDelimiter, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
template<std::ranges::output_range<ByteStorageT> R>
|
||||
R tokens() const
|
||||
{
|
||||
R r;
|
||||
|
||||
if (_tokens.empty()) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(_tokens, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::vector<ByteStorageT> tokens() const
|
||||
{
|
||||
//
|
||||
return tokens<std::vector<ByteStorageT>>();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<ByteStorageT> _tokens;
|
||||
};
|
||||
|
||||
|
||||
// special type of tokenized message:
|
||||
// the first token is keyword
|
||||
// the other - just tokens
|
||||
// delimiter between keyword and other tokens may differ from token-to-token one
|
||||
template<const char *KEY_TOKEN_DELIM = constants::ADC_DEFAULT_KEY_TOKEN_DELIMITER,
|
||||
const char *TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
||||
traits::adc_output_char_range ByteStorageT = std::string,
|
||||
traits::adc_char_view ByteViewT = std::string_view>
|
||||
class AdcKeyTokenNetMessage : public AdcTokenNetMessage<TOKEN_DELIM, ByteStorageT, ByteViewT>
|
||||
{
|
||||
using base_t = AdcTokenNetMessage<TOKEN_DELIM, ByteStorageT, ByteViewT>;
|
||||
|
||||
public:
|
||||
static constexpr std::string_view keytokenDelim{KEY_TOKEN_DELIM};
|
||||
|
||||
using base_t::tokens;
|
||||
|
||||
virtual bool empty() const
|
||||
{
|
||||
auto N = std::distance(this->_bytes.begin(), this->_bytes.end());
|
||||
|
||||
return (N == 0) && this->_tokens.empty();
|
||||
}
|
||||
|
||||
template<traits::adc_output_char_range R>
|
||||
R keyBytes() const
|
||||
{
|
||||
R r;
|
||||
|
||||
std::ranges::copy(this->_bytes, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
ByteStorageT keyBytes() const
|
||||
{
|
||||
//
|
||||
return this->_bytes;
|
||||
}
|
||||
|
||||
|
||||
template<traits::adc_char_view R>
|
||||
R keyView() const
|
||||
{
|
||||
//
|
||||
return R{this->_bytes.begin(), this->_bytes.end()};
|
||||
}
|
||||
|
||||
|
||||
ByteViewT keyView() const {
|
||||
//
|
||||
return ByteViewT{this->_bytes.begin(), this->_bytes.end()};
|
||||
}
|
||||
|
||||
|
||||
template<traits::adc_output_char_range R>
|
||||
R bytes() const
|
||||
{
|
||||
R r;
|
||||
|
||||
if (this->_bytes.empty() && this->_tokens.empty()) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(this->_bytes, std::back_inserter(r)); // keyword
|
||||
|
||||
if (!this->_tokens.empty()) {
|
||||
std::ranges::copy(keytokenDelim, std::back_inserter(r)); // keyword-to-tokens delimiter
|
||||
utils::AdcJoinRange(this->_tokens, base_t::tokenDelimiter, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template<traits::adc_range_of_view_char_range R>
|
||||
R bytesView() const
|
||||
{
|
||||
R r;
|
||||
|
||||
if (this->_bytes.empty() && this->_tokens.empty()) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::back_inserter(r) = {this->_bytes.begin(), this->_bytes.end()}; // keyword
|
||||
|
||||
if (!this->_tokens.empty()) {
|
||||
std::back_inserter(r) = {keytokenDelim.begin(), keytokenDelim.end()}; // keyword-to-tokens delimiter
|
||||
utils::AdcReturnRangeElementsView(this->_tokens, base_t::tokenDelimiter, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
protected:
|
||||
// _bytes: keyword
|
||||
// _tokens: tokens
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <doctest/doctest.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "../common/adc_utils.h"
|
||||
#include "../net/adc_netmessage.h"
|
||||
|
||||
using namespace adc;
|
||||
@ -54,4 +55,21 @@ TEST_CASE("[ADC NET MESSAGE]")
|
||||
for (auto& el : ls) {
|
||||
std::cout << "PAR: [" << el << "]\n";
|
||||
}
|
||||
|
||||
|
||||
ls = {"AAA", "BBB", "CCC"};
|
||||
std::string sr{"RES: "};
|
||||
std::vector<std::string_view> vsv;
|
||||
|
||||
|
||||
auto N = utils::AdcReturnRangeElementsView(ls, std::string_view("<>"), vsv);
|
||||
|
||||
std::cout << "\n\nN = " << N << "\n";
|
||||
for (auto& el : vsv) {
|
||||
std::cout << el << "\n";
|
||||
}
|
||||
|
||||
N = utils::AdcJoinRange(ls, std::string_view("*"), sr);
|
||||
std::cout << "\n\nN = " << N << "\n";
|
||||
std::cout << sr << "\n";
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user