diff --git a/net/adc_netmessage.h b/net/adc_netmessage.h index 346e4dd..c617559 100644 --- a/net/adc_netmessage.h +++ b/net/adc_netmessage.h @@ -23,28 +23,12 @@ namespace adc namespace traits { -// from message view to byte converter concept -template -concept adc_to_bytes_func_c = std::invocable && !std::convertible_to, BT>; - - -// from bytes to message view converter concept -template -concept adc_from_bytes_func_c = std::invocable && std::convertible_to, VT>; - - -template -concept adc_netmsg_converter_c = requires(T t) { - { - t.template serialize(std::declval()) - } -> std::same_as; - { - t.template deserialize(std::declval()) - } -> std::same_as; +template +concept adc_output_range_of_char_range_c = requires { + requires std::ranges::output_range>; + requires std::ranges::output_range, char>; }; -struct AdcTheSameTypeTag { -}; } // namespace traits @@ -52,11 +36,10 @@ struct AdcTheSameTypeTag { namespace utils { -template OutR, +template -size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" ")) +size_t AdcSplitCharRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" ")) { decltype(std::ranges::split_view(input, delim)) vv; @@ -68,62 +51,30 @@ size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim std::ranges::copy(vv, std::back_inserter(result)); + // return number of tokens return std::ranges::distance(vv.begin(), vv.end()); } } // namespace utils -template ByteStorageT, - std::ranges::output_range> StorageSeqT> class AdcNetMessageInterface { -protected: - ByteStorageT _byteStorage; - StorageSeqT _storageSequence; - - AdcNetMessageInterface() : _byteStorage(), _storageSequence({_byteStorage}){}; - - template - AdcNetMessageInterface(const T& v, const Ts&... vs) : AdcNetMessageInterface() - { - appendBytes(v, vs...); - } - - virtual ~AdcNetMessageInterface() = default; - - AdcNetMessageInterface(const AdcNetMessageInterface&) = default; - AdcNetMessageInterface(AdcNetMessageInterface&&) = default; - - AdcNetMessageInterface& operator=(const AdcNetMessageInterface&) = default; - AdcNetMessageInterface& operator=(AdcNetMessageInterface&&) = default; - - - virtual void updateState() = 0; - public: - typedef ByteStorageT byte_storage_t; - typedef StorageSeqT storage_seq_t; - - bool messageEmpty() const { return byteSize() == 0; } - - bool byteStorageEmpty() const - { - size_t sz = std::ranges::distance(_byteStorage.begin(), _byteStorage.end()); - return sz == 0; - } + typedef std::vector output_seq_t; + bool messageEmpty() const { return _outputSequence.empty(); } template void appendBytes(const T& v, const Ts&... vs) { - if constexpr (std::is_array_v>) { + if constexpr (std::is_array_v>) { // to handle with trailing '\0' in plain char array appendBytes(std::string_view(v), vs...); } else { if constexpr (traits::adc_input_char_range) { - std::ranges::copy(v, std::back_inserter(_byteStorage)); + std::ranges::copy(v, std::back_inserter(_storageSequence.emplace_back())); } else if constexpr (traits::formattable) { - std::format_to(std::back_inserter(_byteStorage), v); + std::format_to(std::back_inserter(_storageSequence.emplace_back()), v); } else { static_assert(false, "UNSUPPORTED TYPE!!!"); } @@ -139,128 +90,113 @@ public: template void setBytes(const T& v, const Ts&... vs) { - _byteStorage = ByteStorageT(); + _storageSequence.clear(); + _outputSequence.clear(); + appendBytes(v, vs...); } - // template - // void appendBytes(const T& v, const Ts&... vs) - // { - // if constexpr (std::is_array_v>) { - // appendBytes(std::string_view(v), vs...); - // } else { - // std::ranges::copy(v, std::back_inserter(_byteStorage)); - // } - // if constexpr (sizeof...(Ts)) { - // appendBytes(vs...); - // } - // } - - - // template - // void appendBytes(const T& v, const Ts&... vs) - // { - // std::format_to(std::back_inserter(_byteStorage), v); - - // if constexpr (sizeof...(Ts)) { - // appendBytes(vs...); - // } - // } - template void appendBytes(IterT begin, IterT end) { - std::copy(begin, end, std::back_inserter(_byteStorage)); + static_assert(std::is_same_v, char>, "INVALID ITERATOR VALUE TYPE!!!"); + + std::ranges::copy(begin, end, std::back_inserter(_storageSequence.emplace_back())); updateState(); } - // template - // void setBytes(const T& v, const Ts&... vs) - // { - // _byteStorage = ByteStorageT(); - // appendBytes(v, vs...); - - // updateState(); - // } - - - // template - // void setBytes(const T& v, const Ts&... vs) - // { - // _byteStorage = ByteStorageT(); - // appendBytes(v, vs...); - - // updateState(); - // } - - template void setBytes(IterT begin, IterT end) { - _byteStorage = ByteStorageT(begin, end); + _storageSequence.clear(); + _outputSequence.clear(); appendBytes(begin, end); - - updateState(); } - - virtual size_t byteSize() + virtual size_t byteSize() const { - auto v = _storageSequence | - std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) | - std::views::join; + if (_outputSequence.empty()) { + return 0; + } + + auto v = _outputSequence | std::views::join; return std::ranges::distance(v.begin(), v.end()); } - virtual ByteStorageT bytes() + template + size_t bytes(R& r) { - auto v = _storageSequence | - std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) | - std::views::join; + if (_outputSequence.empty()) { + return 0; + } - return ByteStorageT{v.begin(), v.end()}; + auto v = _outputSequence | std::views::join; + + std::ranges::copy(v, std::back_inserter(r)); + + return std::ranges::distance(v.begin(), v.end()); }; - virtual const StorageSeqT& storageSeq() = 0; + virtual const output_seq_t& storageSeq() = 0; + +protected: + std::vector _storageSequence; + + output_seq_t _outputSequence; + + AdcNetMessageInterface() : _storageSequence(), _outputSequence() {}; + + template + AdcNetMessageInterface(const T& v, const Ts&... vs) : AdcNetMessageInterface() + { + appendBytes(v, vs...); + } + + virtual ~AdcNetMessageInterface() = default; + + AdcNetMessageInterface(const AdcNetMessageInterface&) = default; + AdcNetMessageInterface(AdcNetMessageInterface&&) = default; + + AdcNetMessageInterface& operator=(const AdcNetMessageInterface&) = default; + AdcNetMessageInterface& operator=(AdcNetMessageInterface&&) = default; + + virtual bool byteStorageEmpty() const + { + for (const auto& el : _storageSequence) { + if (!el.empty()) { + return false; + }; + } + + return true; + } + + virtual void updateState() + { + // just add view to byte data + _outputSequence.emplace_back(_storageSequence.back()); + }; }; /* GENERIC (NOTHING SPECIAL) NETWORK MESSAGE */ -template ByteStorageT = std::vector> -class AdcGenericNetMessage - : public AdcNetMessageInterface, 1>> +class AdcGenericNetMessage : public AdcNetMessageInterface { - using base_t = AdcNetMessageInterface, 1>>; - public: - using typename base_t::byte_storage_t; - using typename base_t::storage_seq_t; - - // using base_t::appendBytes; - // using base_t::setBytes; - - using base_t::base_t; + using AdcNetMessageInterface::AdcNetMessageInterface; virtual ~AdcGenericNetMessage() = default; - const storage_seq_t& storageSeq() override - { - this->_storageSequence[0] = this->_byteStorage; - - return this->_storageSequence; - }; - -protected: - void updateState() override {} + const output_seq_t& storageSeq() override { return _outputSequence; }; }; @@ -274,187 +210,222 @@ static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " "; } // namespace constants -template ByteStorageT = std::vector> -class AdcTokenNetMessage : public AdcGenericNetMessage +template +class AdcTokenNetMessage : protected AdcNetMessageInterface // (hide setBytes/appendBytes) { - using base_t = AdcGenericNetMessage; + using base_t = AdcNetMessageInterface; public: static constexpr std::string_view tokenDelimiter{TOKEN_DELIM}; - using typename base_t::byte_storage_t; - using typename base_t::storage_seq_t; + AdcTokenNetMessage() = default; - using base_t::base_t; + template + AdcTokenNetMessage(const T& v, const Ts&... vs) : AdcTokenNetMessage() + { + appendTokens(v, vs...); + } virtual ~AdcTokenNetMessage() = default; - template - void appendTokens(const R& r) - { - using el_t = std::ranges::range_value_t; - static_assert(traits::adc_input_char_range || traits::formattable, - "INVALID TYPE OF INPUT TOKENS!!!"); - size_t n_toks = 0; - if ((n_toks = std::ranges::distance(r.begin(), r.end())) == 0) { + template + void appendTokens(const T& v, const Ts&... vs) + { + if constexpr (traits::adc_input_char_range || traits::formattable) { + this->appendBytes(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->appendBytes(el); + } + } + + } else { + static_assert(false, "INVALID TYPE OF INPUT TOKENS!!!"); + } + + if constexpr (sizeof...(Ts)) { + appendTokens(vs...); + } + } + + template + void setTokens(const T& v, const Ts&... vs) + { + _storageSequence.clear(); + _outputSequence.clear(); + + appendTokens(v, vs...); + } + + template + void tokens(R& r, size_t start = 0, size_t N = std::numeric_limits::max()) const + { + if (byteStorageEmpty()) { return; } - if (!this->byteStorageEmpty()) { - this->appendBytes(tokenDelimiter); - } - - auto v_start = r | std::views::take(n_toks - 1); - for (const auto& el : v_start) { - this->appendBytes(el); - this->appendBytes(tokenDelimiter); - } - - this->appendBytes(*(r.end()--)); // last element - } - - - template - void setTokens(const R& r) - { - this->_byteStorage = ByteStorageT(); - appendTokens(r); - } - - template R> - void tokens(R& r) - { - if (this->byteStorageEmpty()) { + if ((start >= _storageSequence.size()) || !N) { return; } - std::ranges::copy(this->_byteStorage | std::views::split(AdcTokenNetMessage::tokenDelimiter), - std::back_inserter(r)); + std::ranges::copy(_storageSequence | std::views ::drop(start) | std::views::take(N), std::back_inserter(r)); } + + template + void tokensBytes(R& r, size_t start = 0, size_t N = std::numeric_limits::max()) const + { + if (byteStorageEmpty()) { + return; + } + + if ((start >= _storageSequence.size()) || !N) { + return; + } + + auto max_el = _storageSequence.size() - start; + N >= max_el ? max_el * 2 - 1 : N * 2 - 1; + + std::ranges::copy(_outputSequence | std::views::drop(start * 2) | std::views::take(N), std::back_inserter(r)); + } + + const output_seq_t& storageSeq() override + { + // nothing special, just returns the reference + return _outputSequence; + } + + + template + void appendFromBytes(IterT begin, IterT end) + { + static_assert(std::is_same_v, char>, "INVALID ITERATOR VALUE TYPE!!!"); + + auto curr_n_toks = _storageSequence.size(); + auto n_toks = utils::AdcSplitCharRangeToTokens(_storageSequence, std::span(begin, end), tokenDelimiter); + + if (n_toks) { + n_toks += curr_n_toks; + + if (curr_n_toks) { + _outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence + } + _outputSequence.emplace_back(_storageSequence[curr_n_toks]); + + for (auto i = curr_n_toks + 1; i < n_toks; ++i) { + _outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence + _outputSequence.emplace_back(_storageSequence[i]); + } + } + } + + + template + void setFromBytes(IterT begin, IterT end) + { + _storageSequence.clear(); + _outputSequence.clear(); + + appendFromBytes(begin, end); + } + + + protected: - // std::vector _tokens; - - void updateState() override {} + void updateState() override + { + if (_outputSequence.size()) { + _outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence + } + _outputSequence.emplace_back(_storageSequence.back()); + } }; template ByteStorageT = std::vector> -class AdcKeyParamNetMessage : public AdcGenericNetMessage + const char* PARAM_PARAM_DELIM = constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER> +class AdcKeyParamNetMessage : protected AdcTokenNetMessage { - using base_t = AdcGenericNetMessage; - public: static constexpr std::string_view keyparamDelimiter{KEY_PARAM_DELIM}; static constexpr std::string_view paramparamDelimiter{PARAM_PARAM_DELIM}; - using typename base_t::byte_storage_t; - using typename base_t::storage_seq_t; + AdcKeyParamNetMessage() = default; - using base_t::base_t; + template + AdcKeyParamNetMessage(const KeyT& key, const ParamTs&... params) : AdcKeyParamNetMessage() + { + setKeyParam(key, params...); + } virtual ~AdcKeyParamNetMessage() = default; // key and params template - void setKeyParam(KeyT&& key, ParamTs&&... params) + void setKeyParam(const KeyT& key, const ParamTs&... params) { - this->_byteStorage = ByteStorageT(); + _key.clear(); + this->_storageSequence.clear(); + this->_outputSequence.clear(); + + if constexpr (traits::adc_input_char_range || traits::formattable) { + std::ranges::copy(key, std::back_inserter(_key)); + } else if constexpr (traits::formattable) { + std::format_to(std::back_inserter(_key), "{}", key); + } else { + static_assert(false, "INVALID KEY-VALUE TYPE!!!"); + } + + this->_outputSequence.emplace_back(_key); if constexpr (sizeof...(ParamTs)) { - this->setBytes(std::forward(key), keyparamDelimiter); - setKeyParamHelper(std::forward(params)...); - } else { - this->setBytes(std::forward(key)); + this->setTokens(params...); } } template - R key() const + void key(R& r) const { - R val; - - if (this->byteStorageEmpty()) { - return val; - } - - auto v = this->_byteStorage | std::views::split(keyparamDelimiter); - - std::ranges::copy(v | std::views::take(1), std::back_inserter(val)); - - return val; - } - - template R> - R params(size_t start = 0, size_t N = std::numeric_limits::max()) const - { - R pars; - - if (this->byteStorageEmpty() || !N) { - return pars; - } - - auto v = this->_byteStorage | std::views::split(keyparamDelimiter); - - size_t k, num = N, n_pars = std::ranges::distance(v.begin(), v.end()) - 1; - if (!n_pars) { + if constexpr (std::is_convertible_v) { return; } - n_pars = 0; - for (auto& p : v | std::views::drop(1)) { - auto pv = p | std::views::split(paramparamDelimiter); - n_pars += std::ranges::distance(pv.begin(), pv.end()); - if (n_pars < start) { - k = start - n_pars; - continue; - } else { - k = 0; - } + std::ranges::copy(_key, std::back_inserter(r)); + } - std::ranges::copy(pv | std::views::drop(k) | std::views::take(num), std::back_inserter(pars)); - num -= std::ranges::distance(pars.begin(), pars.end()); - if (!num) { - break; - } - } - - return pars; + template + void params(R& r, size_t start = 0, size_t N = std::numeric_limits::max()) const + { + this->tokens(r, start, N); } template - R paramsBytes(size_t start = 0, size_t N = std::numeric_limits::max()) const + void paramsBytes(R& r, size_t start = 0, size_t N = std::numeric_limits::max()) const { - R pars_bytes; - - if (this->byteStorageEmpty() || !N) { - return pars_bytes; - } - - auto p = params>(start, N); - - if (std::ranges::distance(p.begin(), p.end())) { - } - - return pars_bytes; + this->tokensBytes(r, start, N); } protected: - template - void setKeyParamHelper(ParamT&& param, ParamTs&&... params) - { - this->appendBytes(std::forward(param)); + std::string _key; + // _outputSequence will store parameters - if constexpr (sizeof...(ParamTs)) { - this->appendBytes(paramparamDelimiter); - setKeyParamHelper(std::forward(params)...); + void updateState() override + { + if (this->_outputSequence.size()) { + this->_outputSequence.emplace_back(paramparamDelimiter); // add param-param delimiter in output sequence + } else { + this->_outputSequence.emplace_back(keyparamDelimiter); // add key-param delimiter in output sequence } + + this->_outputSequence.emplace_back(this->_storageSequence.back()); } };