...
This commit is contained in:
parent
c0316937e3
commit
7dabd9394d
205
net/adc_netmsg.h
205
net/adc_netmsg.h
@ -14,7 +14,7 @@ namespace adc
|
|||||||
{
|
{
|
||||||
|
|
||||||
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcGenericNetMessage
|
class AdcNetMessageCommonInterface
|
||||||
{
|
{
|
||||||
virtual bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; }
|
virtual bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; }
|
||||||
|
|
||||||
@ -33,9 +33,7 @@ class AdcGenericNetMessage
|
|||||||
virtual ByteStorageT bytes() const { return bytes<ByteStorageT>(); }
|
virtual ByteStorageT bytes() const { return bytes<ByteStorageT>(); }
|
||||||
|
|
||||||
// get a view of message bytes
|
// get a view of message bytes
|
||||||
// template <std::ranges::range R>
|
template <traits::adc_range_of_view_char_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 bytesView() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
@ -49,13 +47,91 @@ class AdcGenericNetMessage
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
ByteStorageT _bytes;
|
ByteStorageT _bytes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AdcNetMessageCommonInterface() = default;
|
||||||
|
|
||||||
|
virtual ~AdcNetMessageCommonInterface() = default;
|
||||||
|
|
||||||
|
AdcNetMessageCommonInterface(const AdcNetMessageCommonInterface&) = default;
|
||||||
|
AdcNetMessageCommonInterface(AdcNetMessageCommonInterface&&) = default;
|
||||||
|
|
||||||
|
AdcNetMessageCommonInterface& operator=(const AdcNetMessageCommonInterface&) = default;
|
||||||
|
AdcNetMessageCommonInterface& operator=(AdcNetMessageCommonInterface&&) = default;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
void convertToBytes(ByteViewT& res, const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) { // to handle with trailing '\0' in plain char array
|
||||||
|
convertToBytes(std::string_view(v), vs...);
|
||||||
|
} else {
|
||||||
|
if constexpr (traits::adc_input_char_range<T>) {
|
||||||
|
std::ranges::copy(v, std::back_inserter(res));
|
||||||
|
} else if constexpr (std::convertible_to<T, ByteStorageT>) {
|
||||||
|
convertToBytes(static_cast<ByteViewT>(v), vs...);
|
||||||
|
} else if constexpr (traits::formattable<T>) {
|
||||||
|
std::format_to(std::back_inserter(res), "{}", v);
|
||||||
|
} else {
|
||||||
|
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof...(Ts)) {
|
||||||
|
convertToBytes(vs...);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Generic message class
|
||||||
|
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
|
||||||
|
class AdcGenericNetMessage : public AdcNetMessageCommonInterface<ByteStorageT, ByteViewT>
|
||||||
|
{
|
||||||
|
using base_t = AdcNetMessageCommonInterface<ByteStorageT, ByteViewT>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using base_t::base_t;
|
||||||
|
using base_t::bytes;
|
||||||
|
using base_t::byteView;
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
void appendBytes(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
this->convertToBytes(this->_bytes, v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
void setBytes(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
this->_bytes = ByteStorageT();
|
||||||
|
|
||||||
|
appendBytes(v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IT>
|
||||||
|
void appendFromBytes(IT begin, IT end)
|
||||||
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
|
{
|
||||||
|
std::copy(begin, end, std::back_inserter(this->_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IT>
|
||||||
|
void setFromBytes(IT begin, IT end)
|
||||||
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
|
{
|
||||||
|
this->_bytes = ByteStorageT();
|
||||||
|
|
||||||
|
appendFromBytes(begin, end);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace constants
|
namespace constants
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " ";
|
static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " ";
|
||||||
static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " ";
|
static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " ";
|
||||||
|
|
||||||
@ -65,15 +141,30 @@ static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " ";
|
|||||||
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
||||||
traits::adc_output_char_range ByteStorageT = std::string,
|
traits::adc_output_char_range ByteStorageT = std::string,
|
||||||
traits::adc_char_view ByteViewT = std::string_view>
|
traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcTokenNetMessage : public AdcGenericNetMessage<ByteStorageT, ByteViewT>
|
class AdcTokenNetMessage : public AdcNetMessageCommonInterface<ByteStorageT, ByteViewT>
|
||||||
{
|
{
|
||||||
using base_t = AdcGenericNetMessage<ByteStorageT, ByteViewT>;
|
using base_t = AdcNetMessageCommonInterface<ByteStorageT, ByteViewT>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
||||||
|
|
||||||
|
|
||||||
virtual bool empty() const { return _tokens.empty(); }
|
AdcTokenNetMessage() = default;
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
AdcTokenNetMessage(const T& v, const Ts&... vs) : AdcTokenNetMessage()
|
||||||
|
{
|
||||||
|
setTokens(v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~AdcTokenNetMessage() = default;
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool empty() const
|
||||||
|
{
|
||||||
|
//
|
||||||
|
return _tokens.empty();
|
||||||
|
}
|
||||||
|
|
||||||
template <traits::adc_output_char_range R>
|
template <traits::adc_output_char_range R>
|
||||||
R bytes() const
|
R bytes() const
|
||||||
@ -85,22 +176,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
utils::AdcJoinRange(_tokens, tokenDelimiter, r);
|
utils::AdcJoinRange(_tokens, tokenDelimiter, r);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// template <std::ranges::range R>
|
template <traits::adc_range_of_view_char_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 bytesView() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
@ -109,21 +191,13 @@ public:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
utils::AdcReturnRangeElementsView(_tokens, tokenDelimiter, r);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<std::ranges::output_range<ByteStorageT> R>
|
template <std::ranges::output_range<ByteStorageT> R>
|
||||||
R tokens() const
|
R tokens() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
@ -143,6 +217,65 @@ public:
|
|||||||
return tokens<std::vector<ByteStorageT>>();
|
return tokens<std::vector<ByteStorageT>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
void appendTokens(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
if constexpr (traits::adc_input_char_range<T> || traits::formattable<T>) {
|
||||||
|
this->convertToBytes(_tokens.emplace_back(), v);
|
||||||
|
} else if constexpr (std::ranges::input_range<T>) {
|
||||||
|
using el_t = std::ranges::range_value_t<T>;
|
||||||
|
static_assert(traits::adc_input_char_range<el_t> || traits::formattable<el_t>,
|
||||||
|
"INVALID TYPE OF INPUT TOKENS!!!");
|
||||||
|
|
||||||
|
if (std::ranges::distance(v.begin(), v.end())) {
|
||||||
|
for (const auto& el : v) {
|
||||||
|
this->convertToBytes(_tokens.emplace_back(), el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
static_assert(false, "UNSUPPORTED (CANNOT BE SERIALIZED TO BYTES) TYPE OF INPUT TOKENS!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof...(Ts)) {
|
||||||
|
appendTokens(vs...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename... Ts>
|
||||||
|
void setTokens(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
_tokens.clear();
|
||||||
|
|
||||||
|
appendTokens(v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IT>
|
||||||
|
void appendFromBytes(IT begin, IT end)
|
||||||
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
|
{
|
||||||
|
auto it = begin, start_it = begin;
|
||||||
|
|
||||||
|
do {
|
||||||
|
it = std::search(start_it, end, tokenDelimiter.begin(), tokenDelimiter.end());
|
||||||
|
std::copy(start_it, it, std::back_inserter(_tokens.emplace_back()));
|
||||||
|
start_it = it + tokenDelimiter.size();
|
||||||
|
} while (it != end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IT>
|
||||||
|
void setFromBytes(IT begin, IT end)
|
||||||
|
requires std::same_as<std::iter_value_t<IT>, char>
|
||||||
|
{
|
||||||
|
_tokens.clear();
|
||||||
|
|
||||||
|
appendFromBytes(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<ByteStorageT> _tokens;
|
std::vector<ByteStorageT> _tokens;
|
||||||
};
|
};
|
||||||
@ -152,8 +285,8 @@ protected:
|
|||||||
// the first token is keyword
|
// the first token is keyword
|
||||||
// the other - just tokens
|
// the other - just tokens
|
||||||
// delimiter between keyword and other tokens may differ from token-to-token one
|
// 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,
|
template <const char* KEY_TOKEN_DELIM = constants::ADC_DEFAULT_KEY_TOKEN_DELIMITER,
|
||||||
const char *TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
||||||
traits::adc_output_char_range ByteStorageT = std::string,
|
traits::adc_output_char_range ByteStorageT = std::string,
|
||||||
traits::adc_char_view ByteViewT = std::string_view>
|
traits::adc_char_view ByteViewT = std::string_view>
|
||||||
class AdcKeyTokenNetMessage : public AdcTokenNetMessage<TOKEN_DELIM, ByteStorageT, ByteViewT>
|
class AdcKeyTokenNetMessage : public AdcTokenNetMessage<TOKEN_DELIM, ByteStorageT, ByteViewT>
|
||||||
@ -163,8 +296,11 @@ class AdcKeyTokenNetMessage : public AdcTokenNetMessage<TOKEN_DELIM, ByteStorage
|
|||||||
public:
|
public:
|
||||||
static constexpr std::string_view keytokenDelim{KEY_TOKEN_DELIM};
|
static constexpr std::string_view keytokenDelim{KEY_TOKEN_DELIM};
|
||||||
|
|
||||||
|
using base_t::appendTokens;
|
||||||
|
using base_t::setTokens;
|
||||||
using base_t::tokens;
|
using base_t::tokens;
|
||||||
|
|
||||||
|
|
||||||
virtual bool empty() const
|
virtual bool empty() const
|
||||||
{
|
{
|
||||||
auto N = std::distance(this->_bytes.begin(), this->_bytes.end());
|
auto N = std::distance(this->_bytes.begin(), this->_bytes.end());
|
||||||
@ -172,7 +308,7 @@ public:
|
|||||||
return (N == 0) && this->_tokens.empty();
|
return (N == 0) && this->_tokens.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<traits::adc_output_char_range R>
|
template <traits::adc_output_char_range R>
|
||||||
R keyBytes() const
|
R keyBytes() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
@ -190,7 +326,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<traits::adc_char_view R>
|
template <traits::adc_char_view R>
|
||||||
R keyView() const
|
R keyView() const
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@ -198,13 +334,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ByteViewT keyView() const {
|
ByteViewT keyView() const
|
||||||
|
{
|
||||||
//
|
//
|
||||||
return ByteViewT{this->_bytes.begin(), this->_bytes.end()};
|
return ByteViewT{this->_bytes.begin(), this->_bytes.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<traits::adc_output_char_range R>
|
template <traits::adc_output_char_range R>
|
||||||
R bytes() const
|
R bytes() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
@ -223,7 +360,7 @@ public:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<traits::adc_range_of_view_char_range R>
|
template <traits::adc_range_of_view_char_range R>
|
||||||
R bytesView() const
|
R bytesView() const
|
||||||
{
|
{
|
||||||
R r;
|
R r;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user