#pragma once #include #include #include #include "../common/adc_traits.h" #include "../common/adc_utils.h" namespace adc { namespace traits { template concept adc_has_clear_c = requires(T t) { t.clear(); }; } // namespace traits namespace utils { template static void convertToBytes(ByteStorageT& res, const T& v, const Ts&... vs) { if constexpr (std::is_array_v>) { // to handle with trailing '\0' in plain char array convertToBytes(res, 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(res, 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(res, vs...); } } template struct AdcTokenManip { AdcTokenManip(R& byte_seq) : _byteSequence(byte_seq) {} template auto tokens(const DR& delimiter, size_t start = 0, size_t num = std::numeric_limits::max()) { std::span dl; if constexpr (std::is_array_v) { dl = std::span(delimiter, sizeof(delimiter) - 1); // remove trailing '\0' } else { dl = std::span(delimiter); } return std::views::split(_byteSequence, dl) | std::views::drop(start) | std::views::take(num); } template auto joinTokens(const DR& delimiter, size_t start = 0, size_t num = std::numeric_limits::max()) { } template AdcTokenManip& addTokens(const DR& delimiter, T&& v, Ts&&... vs) { std::span dl; if constexpr (std::is_array_v) { dl = std::span(delimiter, sizeof(delimiter) - 1); // remove trailing '\0' } else { dl = std::span(delimiter); } if (std::ranges::size(_byteSequence)) { std::ranges::copy(dl, std::back_inserter(_byteSequence)); } convertToBytes(_byteSequence, std::forward(v)); if constexpr (sizeof...(Ts)) { addTokens(dl, std::forward(vs)...); } return *this; } template AdcTokenManip& setTokens(const DR& delimiter, T&& v, Ts&&... vs) { if (std::ranges::size(_byteSequence)) { if constexpr (traits::adc_has_clear_c) { _byteSequence.clear(); } else { _byteSequence = R(); } } return addTokens(delimiter, std::forward(v), std::forward(vs)...); } private: R& _byteSequence; }; } // namespace utils /* */ template class AdcNetMessageInterface { public: typedef ByteStorageT byte_storage_t; typedef ByteViewT byte_view_t; virtual ~AdcNetMessageInterface() = default; bool empty() const { if (_bytes.empty()) { return true; } bool emp = true; for (size_t i = _reservedNum; i < _bytes.size(); ++i) { const auto& el = _bytes[i]; if (std::ranges::distance(el.begin(), el.end())) { emp = false; break; } } return emp; } size_t byteSize() const { size_t sz = 0; for (const auto& el : _bytes | std::views::drop(_reservedNum)) { sz += std::ranges::distance(el.begin(), el.end()); } return sz; } // get a copy of message bytes template R bytes() const { R r; for (size_t i = _reservedNum; i < _bytes.size(); ++i) { std::ranges::for_each(storageViewByIndex(i), [&r](const auto& el) { std::ranges::copy(el, std::back_inserter(r)); }); } return r; } ByteStorageT bytes() const { // return bytes(); } // get a view of message bytes template R bytesView() const { R r; for (size_t i = _reservedNum; i < _bytes.size(); ++i) { std::ranges::for_each(storageViewByIndex(i), [&r](const auto& el) { r.emplace_back(el.begin(), el.end()); }); } return r; } std::vector bytesView() const { // return bytesView>(); } protected: std::vector _bytes; // sequence of byte buffers size_t _reservedNum; AdcNetMessageInterface(size_t reserved = 0) : _reservedNum(reserved), _bytes() { // reserve the "_reservedNum" first elements _bytes.resize(_reservedNum); } // return a sequence of storage element view and possible additional // byte views (e.g. elements delimiter) virtual std::vector storageViewByIndex(size_t) const = 0; }; // Generic message class template class AdcGenericNetMessage : public AdcNetMessageInterface { using base_t = AdcNetMessageInterface; public: using typename base_t::byte_storage_t; using typename base_t::byte_view_t; using base_t::base_t; using base_t::bytes; using base_t::bytesView; using base_t::empty; AdcGenericNetMessage() : base_t() { // just the single buffer this->_bytes.resize(1); } template AdcGenericNetMessage(const T& v, const Ts&... vs) : AdcGenericNetMessage() { appendBytes(v, vs...); } template void appendBytes(const T& v, const Ts&... vs) { utils::convertToBytes(this->_bytes[0], v, vs...); } template void setBytes(const T& v, const Ts&... vs) { this->_bytes[0] = 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[0])); } template void setFromBytes(IT begin, IT end) requires std::same_as, char> { this->_bytes[0] = ByteStorageT(); appendFromBytes(begin, end); } }; namespace constants { static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_KEY_TOKEN_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_KEY_VALUE_DELIMITER[] = " "; } // namespace constants template class AdcTokenNetMessage : public AdcNetMessageInterface { // AdcNetMessageSeqInterface::_bytes - tokens using base_t = AdcNetMessageInterface; public: static constexpr std::string_view tokenDelimiter{TOKEN_DELIM}; using base_t::bytes; using base_t::bytesView; using base_t::empty; AdcTokenNetMessage() = default; template AdcTokenNetMessage(const T& v, const Ts&... vs) : AdcTokenNetMessage() // _reservedNum = 0 { setTokens(v, vs...); } virtual ~AdcTokenNetMessage() = default; template R> R tokens(size_t start = 0, size_t N = std::numeric_limits::max()) const { R r; if (empty()) { return r; } std::ranges::copy(this->_bytes | std::views::drop(start + this->_reservedNum) | std::views::take(N), std::back_inserter(r)); return r; } std::vector tokens(size_t start = 0, size_t N = std::numeric_limits::max()) const { // return tokens>(start, N); } template R tokensBytes(size_t start = 0, size_t N = std::numeric_limits::max()) const { R r; if (empty() || (start >= _tokenNumber) || !N) { return r; } utils::AdcJoinRange(this->_bytes | std::views::drop(start + this->_reservedNum) | std::views::take(N), tokenDelimiter, r); return r; } ByteStorageT tokensBytes(size_t start = 0, size_t N = std::numeric_limits::max()) const { return tokensBytes(start, N); } template void appendTokens(const T& v, const Ts&... vs) { if constexpr (traits::adc_input_char_range || traits::formattable) { utils::convertToBytes(this->_bytes.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) { utils::convertToBytes(this->_bytes.emplace_back(), el); } } } else { static_assert(false, "UNSUPPORTED (CANNOT BE SERIALIZED TO BYTES) TYPE OF INPUT TOKENS!!!"); } if constexpr (sizeof...(Ts)) { appendTokens(vs...); } _tokenNumber = this->_bytes.size() - this->_reservedNum; } template void setTokens(const T& v, const Ts&... vs) { this->_bytes.resize(this->_reservedNum); _tokenNumber = 0; 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(this->_bytes.emplace_back())); ++_tokenNumber; start_it = it; std::advance(start_it, tokenDelimiter.size()); // to support not only random-access iterators } while (it != end); } template void setFromBytes(IT begin, IT end) requires std::same_as, char> { this->_bytes.resize(this->_reservedNum); _tokenNumber = 0; appendFromBytes(begin, end); } protected: size_t _tokenNumber; virtual std::vector storageViewByIndex(size_t idx) const override { const ByteStorageT& el = this->_bytes[idx]; std::vector vw{{el.begin(), el.end()}}; auto last_idx = this->_bytes.size() - 1; if ((idx < last_idx) && (_tokenNumber > 1)) { // add delimiter vw.emplace_back(tokenDelimiter.begin(), tokenDelimiter.end()); } return vw; } }; // 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 class AdcKeyTokenNetMessage : public AdcTokenNetMessage { using base_t = AdcTokenNetMessage; public: static constexpr std::string_view keytokenDelimiter{KEY_TOKEN_DELIM}; using base_t::appendFromBytes; // append only tokens not keyword using base_t::appendTokens; using base_t::bytes; using base_t::bytesView; using base_t::empty; using base_t::setTokens; using base_t::tokens; AdcKeyTokenNetMessage() : base_t() { this->_reservedNum = 1; // reserve the first element for keyword this->_bytes.resize(this->_reservedNum); }; template AdcKeyTokenNetMessage(const KT& key, const T& tok, const Ts&... toks) : AdcKeyTokenNetMessage() { utils::convertToBytes(this->_bytes[0], key); setTokens(tok, toks...); } virtual ~AdcKeyTokenNetMessage() = default; size_t byteSize() const { size_t sz = base_t::template byteSize(); return sz + std::distance(this->_bytesbyte[0].begin(), this->_bytes[0].end()); } // get a copy of message bytes template R bytes() const { R r; std::ranges::copy(this->_bytes[0], std::back_inserter(r)); // keyword if (this->_tokenNumber) { std::ranges::copy(keytokenDelimiter, std::back_inserter(r)); // keyword-to-token delimiter } // std::ranges::for_each(base_t::template bytesView(), [&r](const auto& el) { // std::ranges::copy(el, std::back_inserter(r)); // token // }); return r; } ByteStorageT bytes() const { // return bytes(); } // get a view of message bytes template R bytesView() const { R r; const auto& key = this->_bytes[0]; std::back_inserter(r) = {key.begin(), key.end()}; // keyword if (this->_tokenNumber) { std::back_inserter(r) = {keytokenDelimiter.begin(), keytokenDelimiter.end()}; // keyword-to-token delimiter } // std::ranges::for_each(base_t::template bytesView(), [&r](const auto& el) { // std::back_inserter(r) = {el.begin(), el.end()}; // token // }); return r; } std::vector bytesView() const { // return bytesView>(); } template R keyBytes() const { R r; const auto& key = this->_bytes[0]; if (!std::distance(key.begin(), key.end())) { return r; } std::ranges::copy(key, std::back_inserter(r)); return r; } ByteStorageT keyBytes() const { // return keyBytes(); } template R keyView() const { const auto& key = this->_bytes[0]; if (!std::distance(key.begin(), key.end())) { return R(); } return R{this->_bytes[0].begin(), this->_bytes[0].end()}; } ByteViewT keyView() const { // return keyView(); } template void setKeyTokens(const KT& key, const T& tok, const Ts&... toks) { setTokens(tok, toks...); utils::convertToBytes(this->_bytes[0], key); } template void setFromBytes(IT begin, IT end) requires std::same_as, char> { this->_bytes.clear(); auto it = std::search(begin, end, keytokenDelimiter.begin(), keytokenDelimiter.end()); std::copy(begin, it, std::back_inserter(this->_bytes.emplace_back())); // keyword if (it != end) { std::advance(it, keytokenDelimiter.size()); appendFromBytes(it, end); // tokens } } }; template class AdcTokenMessage : utils::AdcTokenManip { using base_t = utils::AdcTokenManip; public: static constexpr std::span tokenDelimiter{DELIM, sizeof(DELIM) - 1}; // "-1" to remove trailing '\0' AdcTokenMessage(R& byte_seq) : base_t(byte_seq) {} template auto tokens(size_t start = 0, size_t num = std::numeric_limits::max()) { RT res; std::ranges::for_each(base_t::tokens(tokenDelimiter, start, num), [&res](const auto& el) { res.emplace_back(el.begin(), el.end()); }); return res; } auto tokens(size_t start = 0, size_t num = std::numeric_limits::max()) { return tokens>>(start, num); } template AdcTokenMessage& addTokens(TokT&& token, TokTs&&... tokens) { base_t::addTokens(tokenDelimiter, std::forward(token), std::forward(tokens)...); return *this; } template AdcTokenMessage& setTokens(TokT&& token, TokTs&&... tokens) { base_t::setTokens(tokenDelimiter, std::forward(token), std::forward(tokens)...); return *this; } protected: R& _byteSequence; }; template class AdcKeyValueMessage { public: static constexpr std::span keyvalueDelimiter{KEY_VALUE_DELIM, sizeof(KEY_VALUE_DELIM) - 1}; AdcKeyValueMessage(R& byte_seq) : _byteSequence(byte_seq) {} template auto key() const { auto r = std::ranges::search(_byteSequence, keyvalueDelimiter); if (r.empty()) { return VT(); } return VT(_byteSequence.begin(), r.begin()); } auto key() const { return key(); } template auto value() const { auto r = std::ranges::search(_byteSequence, keyvalueDelimiter); if (r.empty()) { return VT(); } return VT(r.end(), _byteSequence.end()); } auto value() const { return value(); } template AdcKeyValueMessage& setKeyValue(KeyT&& key, ValueT&& value) { if (std::ranges::size(_byteSequence)) { if constexpr (traits::adc_has_clear_c) { _byteSequence.clear(); } else { _byteSequence = R(); } } utils::convertToBytes(_byteSequence, std::forward(key)); std::ranges::copy(keyvalueDelimiter, std::back_inserter(_byteSequence)); utils::convertToBytes(_byteSequence, std::forward(value)); return *this; } template AdcKeyValueMessage& setValue(ValueT&& value) { if (std::ranges::size(_byteSequence)) { if constexpr (traits::adc_has_clear_c) { _byteSequence.clear(); } else { _byteSequence = R(); } } std::vector kw; std::ranges::copy(key>(), std::back_inserter(kw)); return setKeyValue(kw, std::forward(value)); } protected: R& _byteSequence; }; namespace traits { template concept adc_netmessage_c = requires { typename T::byte_storage_t; typename T::byte_view_t; requires std::derived_from>; }; // template // concept adc_netmessage_c = requires(const T t) { // const methods // requires std::same_as, char>; // { t.empty() } -> std::convertible_to; // { t.byteSize() } -> std::convertible_to; // { t.bytes() } -> adc_output_char_range; // { t.byteView() } -> adc_range_of_view_char_range; // { t.setFromBytes(std::input_iterator) } -> std::same_as; // }; } // namespace traits } // namespace adc