ADC/net/adc_netproto.h
2024-06-13 18:24:52 +03:00

189 lines
5.1 KiB
C++

#pragma once
#include "../common/adc_traits.h"
namespace adc
{
namespace traits
{
template <typename T, typename R>
concept adc_netproto_c = adc_range_of_view_char_range<R> && requires(T t, const R& r) {
{ t.toLowLevel(r) } -> std::same_as<R>;
{ t.fromLowLevel(r) } -> std::same_as<R>;
};
} // 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 <typename InetT, const char* STOPSEQ = constants::ADC_DEFAULT_NETPROTO_STOPSEQ>
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::input_iterator IT>
std::pair<IT, bool> 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 <traits::adc_range_of_view_char_range R>
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 <traits::adc_range_of_view_char_range R>
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 <traits::adc_output_char_range R>
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 <traits::adc_output_char_range R>
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::input_iterator IT>
std::pair<IT, IT> 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 <typename InetT, const char* START_MARK = constants::ADC_DEFAULT_NETPROTO_STARTMARK, size_t SIZE_FIELD_LEN = 8>
struct AdcNetProtoSizedBlob {
static constexpr std::string_view startMark{START_MARK};
static constexpr size_t sizeFieldLen = SIZE_FIELD_LEN;
template <std::input_iterator IT>
std::pair<IT, bool> 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