#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 /* SESSION-LEVEL PROTOCOLS */ template struct AdcStopSeqSessionProto { static constexpr std::string_view STOP_SEQ{STOPSEQ}; static constexpr size_t STOP_SEQ_SIZE = STOP_SEQ.size(); static_assert(STOP_SEQ_SIZE, "STOP BYTE SEQUENCE MUST NOT BE AN EMPTY ONE!!!"); typedef std::string proto_ident_t; proto_ident_t ident() const { return "STOP SEQUENCE PROTO"; } // template // auto search(const R& r) // { // std::tuple, std::ranges::iterator_t, bool> res{r.begin(), r.end(), false}; // if (!r.size()) { // return res; // } // // std::get<1>(res) = std::search(r.begin(), r.end(), STOP_SEQ.begin(), STOP_SEQ.end()); // auto found = std::ranges::search(r, STOP_SEQ); // // if (std::get<1>(res) != r.end()) { // move iterator to the one-past-the-end position // if (!found.empty()) { // move iterator to the one-past-the-end position // // std::advance(std::get<1>(res), STOP_SEQ_SIZE); // // std::get<1>(res) = found.begin() + STOP_SEQ_SIZE; // std::get<1>(res) = found.end(); // std::get<2>(res) = true; // } // return res; // } template auto search(const R& r) { auto found = std::ranges::search(r, STOP_SEQ); if constexpr (std::ranges::viewable_range) { return found.empty() ? std::span(r.begin(), r.begin()) : std::span(r.begin(), found.end()); } else { std::vector res; // to guaranty adc_output_char_range if (!found.empty()) { std::copy(r.begin(), found.end(), std::back_inserter(res)); } return res; } } // template // auto search(IT begin, IT end) // { // std::tuple res{begin, end, false}; // if (begin == end) { // return res; // } // auto it = std::search(begin, end, STOP_SEQ.begin(), STOP_SEQ.end()); // if (it != end) { // // std::advance(it, STOP_SEQ_SIZE); // move iterator to the one-past-the-end position // std::get<1>(res) = it + STOP_SEQ_SIZE; // std::get<2>(res) = true; // } else { // // may be only a part of valid byte sequence was received, // // so start next matching from previous begin-iterator // std::get<1>(res) = begin; // } // return res; // } template auto toProto(const R& r) { // return 2-element array with the first element as a view of the input range and // the second one - a view of the stop sequence if constexpr (std::ranges::viewable_range) { auto res = std::array{std::span(r.begin(), r.end()), std::span(STOP_SEQ.begin(), STOP_SEQ.end())}; // auto res = std::array{std::ranges::subrange(r.begin(), r.end()), // std::ranges::subrange(STOP_SEQ.begin(), STOP_SEQ.end())}; return res; } else { // return a copy of input range with appended stop sequence auto res = r; std::ranges::copy(STOP_SEQ, std::back_inserter(res)); return res; } } template auto fromProto(const R& r) { size_t N = std::distance(r.begin(), r.end()); if (N < STOP_SEQ_SIZE) { // one must ensure for input range size correctness // return std::span>(); return std::ranges::subrange(r.begin(), r.begin()); } if constexpr (std::ranges::viewable_range) { return std::ranges::subrange(r.begin(), r.end() - STOP_SEQ_SIZE); } else { R res; std::ranges::copy(r | std::views::take(N - STOP_SEQ_SIZE), std::back_inserter(res)); return res; } } }; 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