#pragma once #include "../common/adc_traits.h" namespace adc { namespace traits { template concept adc_netproto_c = adc_range_of_view_char_range && requires(T t, const R& r) { { t.toLowLevel(r) } -> std::same_as; { t.fromLowLevel(r) } -> std::same_as; }; } // namespace traits namespace constants { static constexpr char ADC_DEFAULT_NETPROTO_STOPSEQ[] = "\n"; static constexpr char ADC_DEFAULT_NETPROTO_STARTMARK[] = "\n\t\r\v\r\t\n"; } // namespace constants template struct AdcNetProtoStopSeq : InetT { static constexpr std::string_view stopSeq{STOPSEQ}; static constexpr size_t stopSeqSize = stopSeq.size(); static_assert(stopSeqSize, "STOP BYTE SEQUENCE MUST NOT BE AN EMPTY ONE!!!"); using socket_t = typename InetT::socket; template std::pair matchCondition(IT begin, IT end) { auto res = std::make_pair(begin, false); if (begin == end) { return res; } res.first = std::search(begin, end, stopSeq.begin(), stopSeq.end()); if (res.first != end) { std::advance(res.first, stopSeqSize); // move iterator to the one-past-the-end position res.second = true; } else { // may be only a part of valid byte sequence was received, // so start next matching from previous begin-iterator res.first = begin; } return res; } /* range of char range's views */ template R toLowLevel(const R& r) { R res = r; // just add to the back of the range "stop sequence" element std::back_inserter(res) = {stopSeq.begin(), stopSeq.end()}; return res; } template R fromLowLevel(const R& r) { R res; auto N = std::distance(r.begin(), r.end()); if (!N) { return res; } // just remove the last element (it is assumed the last element is the stop sequence) std::ranges::copy(r | std::views::take(N - 1), std::back_inserter(res)); return res; } /* range of char */ template R toLowLevel(const R& r) { R res = r; // just add to the back of the "stop sequence" std::ranges::copy(stopSeq, std::back_inserter(res)); return res; } template R fromLowLevel(const R& r) { R res; auto N = std::distance(r.begin(), r.end()); if (N <= stopSeq) { // !!!!!!!!!!! return res; } // remove stopSeqSize bytes from the back of the input range std::ranges::copy(r | std::views::take(N - stopSeqSize), std::back_inserter(res)); return res; } /* from iterators to the input range */ template std::pair fromLowLevel(IT begin, IT end) { auto N = std::distance(begin, end); if (N <= stopSeqSize) { // !!!!!!!! return std::make_pair(end, end); } std::advance(end, -stopSeqSize); return std::make_pair(begin, end); } }; template struct AdcNetProtoSizedBlob { static constexpr std::string_view startMark{START_MARK}; static constexpr size_t sizeFieldLen = SIZE_FIELD_LEN; template std::pair matchCondition(IT begin, IT end) { auto res = std::make_pair(begin, false); if (std::distance(begin, end) <= (startMark.size() + sizeFieldLen)) { // still unusefull part return res; } res.first = std::search(begin, end, startMark.begin(), startMark.end()); if (res.first != end) { std::advance(res.first, startMark); auto it = res.first; std::advance(it, sizeFieldLen); std::string sz_str{res.first, it}; size_t blob_size = 0; auto end_ptr = sz_str.data() + sizeFieldLen; auto [ptr, ec] = std::from_chars(sz_str.data(), end_ptr, blob_size, 16); // heximal!!! if ((ec != std::errc()) || (ptr != end_ptr)) { return {begin, false}; } std::advance(res.first, sizeFieldLen); if (std::distance(res.first, end) >= blob_size) { // still partially received message?! std::advance(res.first, blob_size); // move output iterator to the one-past-the-end position res.second = true; } else { // still partially received message?! res.first = begin; } } else { // may be only a part of message was received, // so start next matching from previous begin-iterator res.first = begin; } return res; } }; } // namespace adc