ADC/net/adc_netmessage.h
2024-05-27 18:05:24 +03:00

462 lines
12 KiB
C++

#pragma once
#include <ranges>
#include "../common/adc_traits.h"
#include "../common/adc_utils.h"
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
/* GENERIC NETWORK MESSAGE CLASS */
namespace adc
{
namespace traits
{
// from message view to byte converter concept
template <typename T, typename BT, typename VT>
concept adc_to_bytes_func_c = std::invocable<T, const VT&> && !std::convertible_to<traits::adc_retval_t<T>, BT>;
// from bytes to message view converter concept
template <typename T, typename BT, typename VT>
concept adc_from_bytes_func_c = std::invocable<T, const BT&> && std::convertible_to<traits::adc_retval_t<T>, VT>;
template <typename T, typename BT, typename VT>
concept adc_netmsg_converter_c = requires(T t) {
{
t.template serialize<BT, VT>(std::declval<const VT&>())
} -> std::same_as<BT>;
{
t.template deserialize<VT, BT>(std::declval<const BT&>())
} -> std::same_as<VT>;
};
struct AdcTheSameTypeTag {
};
} // namespace traits
namespace utils
{
template <traits::adc_output_char_range T,
std::ranges::output_range<T> OutR,
traits::adc_input_char_range InR,
traits::adc_input_char_range DelimT = std::string_view>
size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" "))
{
decltype(std::ranges::split_view(input, delim)) vv;
if constexpr (std::is_array_v<DelimT>) {
vv = input | std::views::split(std::string_view(delim));
} else {
vv = input | std::views::split(delim);
}
std::ranges::copy(vv, std::back_inserter(result));
return std::ranges::distance(vv.begin(), vv.end());
}
} // namespace utils
template <std::ranges::output_range<char> ByteStorageT,
std::ranges::output_range<std::reference_wrapper<const ByteStorageT>> StorageSeqT>
class AdcNetMessageInterface
{
protected:
ByteStorageT _byteStorage;
StorageSeqT _storageSequence;
AdcNetMessageInterface() : _byteStorage(), _storageSequence({_byteStorage}){};
template <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
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;
}
template <typename T, typename... Ts>
void appendBytes(const T& v, const Ts&... vs)
{
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {
appendBytes(std::string_view(v), vs...);
} else {
if constexpr (traits::adc_input_char_range<T>) {
std::ranges::copy(v, std::back_inserter(_byteStorage));
} else if constexpr (traits::formattable<T>) {
std::format_to(std::back_inserter(_byteStorage), v);
} else {
static_assert(false, "UNSUPPORTED TYPE!!!");
}
updateState();
}
if constexpr (sizeof...(Ts)) {
appendBytes(vs...);
}
}
template <typename T, typename... Ts>
void setBytes(const T& v, const Ts&... vs)
{
_byteStorage = ByteStorageT();
appendBytes(v, vs...);
}
// template <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
// void appendBytes(const T& v, const Ts&... vs)
// {
// if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {
// appendBytes(std::string_view(v), vs...);
// } else {
// std::ranges::copy(v, std::back_inserter(_byteStorage));
// }
// if constexpr (sizeof...(Ts)) {
// appendBytes(vs...);
// }
// }
// template <traits::formattable T, traits::formattable... Ts>
// void appendBytes(const T& v, const Ts&... vs)
// {
// std::format_to(std::back_inserter(_byteStorage), v);
// if constexpr (sizeof...(Ts)) {
// appendBytes(vs...);
// }
// }
template <std::input_iterator IterT>
void appendBytes(IterT begin, IterT end)
{
std::copy(begin, end, std::back_inserter(_byteStorage));
updateState();
}
// template <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
// void setBytes(const T& v, const Ts&... vs)
// {
// _byteStorage = ByteStorageT();
// appendBytes(v, vs...);
// updateState();
// }
// template <traits::formattable T, traits::formattable... Ts>
// void setBytes(const T& v, const Ts&... vs)
// {
// _byteStorage = ByteStorageT();
// appendBytes(v, vs...);
// updateState();
// }
template <std::input_iterator IterT>
void setBytes(IterT begin, IterT end)
{
_byteStorage = ByteStorageT(begin, end);
appendBytes(begin, end);
updateState();
}
virtual size_t byteSize()
{
auto v = _storageSequence |
std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) |
std::views::join;
return std::ranges::distance(v.begin(), v.end());
}
virtual ByteStorageT bytes()
{
auto v = _storageSequence |
std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) |
std::views::join;
return ByteStorageT{v.begin(), v.end()};
};
virtual const StorageSeqT& storageSeq() = 0;
};
/* GENERIC (NOTHING SPECIAL) NETWORK MESSAGE */
template <std::ranges::output_range<char> ByteStorageT = std::vector<char>>
class AdcGenericNetMessage
: public AdcNetMessageInterface<ByteStorageT, std::array<std::reference_wrapper<const ByteStorageT>, 1>>
{
using base_t = AdcNetMessageInterface<ByteStorageT, std::array<std::reference_wrapper<const ByteStorageT>, 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;
virtual ~AdcGenericNetMessage() = default;
const storage_seq_t& storageSeq() override
{
this->_storageSequence[0] = this->_byteStorage;
return this->_storageSequence;
};
protected:
void updateState() override {}
};
namespace constants
{
static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " ";
static constexpr char ADC_DEFAULT_KEY_PARAM_DELIMITER[] = " ";
static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " ";
} // namespace constants
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
std::ranges::output_range<char> ByteStorageT = std::vector<char>>
class AdcTokenNetMessage : public AdcGenericNetMessage<ByteStorageT>
{
using base_t = AdcGenericNetMessage<ByteStorageT>;
public:
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
using typename base_t::byte_storage_t;
using typename base_t::storage_seq_t;
using base_t::base_t;
virtual ~AdcTokenNetMessage() = default;
template <std::ranges::input_range R>
void appendTokens(const R& r)
{
using el_t = std::ranges::range_value_t<R>;
static_assert(traits::adc_input_char_range<el_t> || traits::formattable<el_t>,
"INVALID TYPE OF INPUT TOKENS!!!");
size_t n_toks = 0;
if ((n_toks = std::ranges::distance(r.begin(), r.end())) == 0) {
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 <std::ranges::input_range R>
void setTokens(const R& r)
{
this->_byteStorage = ByteStorageT();
appendTokens(r);
}
template <std::ranges::output_range<ByteStorageT> R>
void tokens(R& r)
{
if (this->byteStorageEmpty()) {
return;
}
std::ranges::copy(this->_byteStorage | std::views::split(AdcTokenNetMessage::tokenDelimiter),
std::back_inserter(r));
}
protected:
// std::vector<ByteStorageT> _tokens;
void updateState() override {}
};
template <const char* KEY_PARAM_DELIM = constants::ADC_DEFAULT_KEY_PARAM_DELIMITER,
const char* PARAM_PARAM_DELIM = constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER,
std::ranges::output_range<char> ByteStorageT = std::vector<char>>
class AdcKeyParamNetMessage : public AdcGenericNetMessage<ByteStorageT>
{
using base_t = AdcGenericNetMessage<ByteStorageT>;
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;
using base_t::base_t;
virtual ~AdcKeyParamNetMessage() = default;
// key and params
template <typename KeyT, typename... ParamTs>
void setKeyParam(KeyT&& key, ParamTs&&... params)
{
this->_byteStorage = ByteStorageT();
if constexpr (sizeof...(ParamTs)) {
this->setBytes(std::forward<KeyT>(key), keyparamDelimiter);
setKeyParamHelper(std::forward<ParamTs>(params)...);
} else {
this->setBytes(std::forward<KeyT>(key));
}
}
template <traits::adc_output_char_range R>
R key() 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 <std::ranges::output_range<ByteStorageT> R>
R params(size_t start = 0, size_t N = std::numeric_limits<size_t>::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) {
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(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 <traits::adc_output_char_range R>
R paramsBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{
R pars_bytes;
if (this->byteStorageEmpty() || !N) {
return pars_bytes;
}
auto p = params<std::vector<ByteStorageT>>(start, N);
if (std::ranges::distance(p.begin(), p.end())) {
}
return pars_bytes;
}
protected:
template <typename ParamT, typename... ParamTs>
void setKeyParamHelper(ParamT&& param, ParamTs&&... params)
{
this->appendBytes(std::forward<ParamT>(param));
if constexpr (sizeof...(ParamTs)) {
this->appendBytes(paramparamDelimiter);
setKeyParamHelper(std::forward<ParamTs>(params)...);
}
}
};
} // namespace adc