diff --git a/net/adc_netmsg.h b/net/adc_netmsg.h index 37564e6..64a3ec9 100644 --- a/net/adc_netmsg.h +++ b/net/adc_netmsg.h @@ -14,7 +14,7 @@ namespace adc { template -class AdcGenericNetMessage +class AdcNetMessageCommonInterface { 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(); } // get a view of message bytes - // template - // requires std::ranges::view> - template + template R bytesView() const { R r; @@ -45,17 +43,95 @@ class AdcGenericNetMessage return r; } - virtual std::vector bytesView() const { return bytesView>(); } + virtual std::vector bytesView() const { return bytesView>(); } protected: ByteStorageT _bytes; + + + + AdcNetMessageCommonInterface() = default; + + virtual ~AdcNetMessageCommonInterface() = default; + + AdcNetMessageCommonInterface(const AdcNetMessageCommonInterface&) = default; + AdcNetMessageCommonInterface(AdcNetMessageCommonInterface&&) = default; + + AdcNetMessageCommonInterface& operator=(const AdcNetMessageCommonInterface&) = default; + AdcNetMessageCommonInterface& operator=(AdcNetMessageCommonInterface&&) = default; + + + template + void convertToBytes(ByteViewT& res, const T& v, const Ts&... vs) + { + if constexpr (std::is_array_v>) { // to handle with trailing '\0' in plain char array + convertToBytes(std::string_view(v), vs...); + } else { + if constexpr (traits::adc_input_char_range) { + std::ranges::copy(v, std::back_inserter(res)); + } else if constexpr (std::convertible_to) { + convertToBytes(static_cast(v), vs...); + } else if constexpr (traits::formattable) { + std::format_to(std::back_inserter(res), "{}", v); + } else { + static_assert(false, "UNSUPPORTED TYPE!!!"); + } + } + + if constexpr (sizeof...(Ts)) { + convertToBytes(vs...); + } + } }; +// Generic message class +template +class AdcGenericNetMessage : public AdcNetMessageCommonInterface +{ + using base_t = AdcNetMessageCommonInterface; + +public: + using base_t::base_t; + using base_t::bytes; + using base_t::byteView; + + template + void appendBytes(const T& v, const Ts&... vs) + { + this->convertToBytes(this->_bytes, v, vs...); + } + + template + void setBytes(const T& v, const Ts&... vs) + { + this->_bytes = ByteStorageT(); + + appendBytes(v, vs...); + } + + + template + void appendFromBytes(IT begin, IT end) + requires std::same_as, char> + { + std::copy(begin, end, std::back_inserter(this->_bytes)); + } + + + template + void setFromBytes(IT begin, IT end) + requires std::same_as, char> + { + this->_bytes = ByteStorageT(); + + appendFromBytes(begin, end); + } +}; + namespace constants { - static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " "; @@ -65,15 +141,30 @@ static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " "; template -class AdcTokenNetMessage : public AdcGenericNetMessage +class AdcTokenNetMessage : public AdcNetMessageCommonInterface { - using base_t = AdcGenericNetMessage; + using base_t = AdcNetMessageCommonInterface; public: static constexpr std::string_view tokenDelimiter{TOKEN_DELIM}; - virtual bool empty() const { return _tokens.empty(); } + AdcTokenNetMessage() = default; + + template + AdcTokenNetMessage(const T& v, const Ts&... vs) : AdcTokenNetMessage() + { + setTokens(v, vs...); + } + + virtual ~AdcTokenNetMessage() = default; + + + virtual bool empty() const + { + // + return _tokens.empty(); + } template 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); return r; } - // template - // requires std::ranges::view> - template + template R bytesView() const { R r; @@ -109,21 +191,13 @@ public: return r; } - // std::ranges::for_each(_tokens | std::views::take(_tokens.size()-1), [&r](const auto& el) { - // // std::ranges::range_value_t 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 R> + template R> R tokens() const { R r; @@ -143,6 +217,65 @@ public: return tokens>(); } + + template + void appendTokens(const T& v, const Ts&... vs) + { + if constexpr (traits::adc_input_char_range || traits::formattable) { + this->convertToBytes(_tokens.emplace_back(), v); + } else if constexpr (std::ranges::input_range) { + using el_t = std::ranges::range_value_t; + static_assert(traits::adc_input_char_range || traits::formattable, + "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 + void setTokens(const T& v, const Ts&... vs) + { + _tokens.clear(); + + appendTokens(v, vs...); + } + + + template + void appendFromBytes(IT begin, IT end) + requires std::same_as, 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 + void setFromBytes(IT begin, IT end) + requires std::same_as, char> + { + _tokens.clear(); + + appendFromBytes(begin, end); + } + protected: std::vector _tokens; }; @@ -152,10 +285,10 @@ protected: // the first token is keyword // the other - just tokens // delimiter between keyword and other tokens may differ from token-to-token one -template +template class AdcKeyTokenNetMessage : public AdcTokenNetMessage { using base_t = AdcTokenNetMessage; @@ -163,8 +296,11 @@ class AdcKeyTokenNetMessage : public AdcTokenNetMessage_bytes.begin(), this->_bytes.end()); @@ -172,7 +308,7 @@ public: return (N == 0) && this->_tokens.empty(); } - template + template R keyBytes() const { R r; @@ -190,7 +326,7 @@ public: } - template + template R keyView() const { // @@ -198,13 +334,14 @@ public: } - ByteViewT keyView() const { + ByteViewT keyView() const + { // return ByteViewT{this->_bytes.begin(), this->_bytes.end()}; } - template + template R bytes() const { R r; @@ -213,17 +350,17 @@ public: return r; } - std::ranges::copy(this->_bytes, std::back_inserter(r)); // keyword + 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 + std::ranges::copy(keytokenDelim, std::back_inserter(r)); // keyword-to-tokens delimiter utils::AdcJoinRange(this->_tokens, base_t::tokenDelimiter, r); } return r; } - template + template R bytesView() const { R r; @@ -232,10 +369,10 @@ public: return r; } - std::back_inserter(r) = {this->_bytes.begin(), this->_bytes.end()}; // keyword + 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 + std::back_inserter(r) = {keytokenDelim.begin(), keytokenDelim.end()}; // keyword-to-tokens delimiter utils::AdcReturnRangeElementsView(this->_tokens, base_t::tokenDelimiter, r); }