...
This commit is contained in:
parent
0f42246ec2
commit
d7ed4fac6c
@ -23,28 +23,12 @@ namespace adc
|
|||||||
namespace traits
|
namespace traits
|
||||||
{
|
{
|
||||||
|
|
||||||
// from message view to byte converter concept
|
template <typename T>
|
||||||
template <typename T, typename BT, typename VT>
|
concept adc_output_range_of_char_range_c = requires {
|
||||||
concept adc_to_bytes_func_c = std::invocable<T, const VT&> && !std::convertible_to<traits::adc_retval_t<T>, BT>;
|
requires std::ranges::output_range<T, std::ranges::range_value_t<T>>;
|
||||||
|
requires std::ranges::output_range<std::ranges::range_value_t<T>, char>;
|
||||||
|
|
||||||
// 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 traits
|
||||||
|
|
||||||
@ -52,11 +36,10 @@ struct AdcTheSameTypeTag {
|
|||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
|
|
||||||
template <traits::adc_output_char_range T,
|
template <traits::adc_output_range_of_char_range_c OutR,
|
||||||
std::ranges::output_range<T> OutR,
|
|
||||||
traits::adc_input_char_range InR,
|
traits::adc_input_char_range InR,
|
||||||
traits::adc_input_char_range DelimT = std::string_view>
|
traits::adc_input_char_range DelimT = std::string_view>
|
||||||
size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" "))
|
size_t AdcSplitCharRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" "))
|
||||||
{
|
{
|
||||||
decltype(std::ranges::split_view(input, delim)) vv;
|
decltype(std::ranges::split_view(input, delim)) vv;
|
||||||
|
|
||||||
@ -68,62 +51,30 @@ size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim
|
|||||||
|
|
||||||
std::ranges::copy(vv, std::back_inserter(result));
|
std::ranges::copy(vv, std::back_inserter(result));
|
||||||
|
|
||||||
|
// return number of tokens
|
||||||
return std::ranges::distance(vv.begin(), vv.end());
|
return std::ranges::distance(vv.begin(), vv.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
||||||
|
|
||||||
template <std::ranges::output_range<char> ByteStorageT,
|
|
||||||
std::ranges::output_range<std::reference_wrapper<const ByteStorageT>> StorageSeqT>
|
|
||||||
class AdcNetMessageInterface
|
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:
|
public:
|
||||||
typedef ByteStorageT byte_storage_t;
|
typedef std::vector<std::string_view> output_seq_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool messageEmpty() const { return _outputSequence.empty(); }
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
void appendBytes(const T& v, const Ts&... vs)
|
void appendBytes(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {
|
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) { // to handle with trailing '\0' in plain char array
|
||||||
appendBytes(std::string_view(v), vs...);
|
appendBytes(std::string_view(v), vs...);
|
||||||
} else {
|
} else {
|
||||||
if constexpr (traits::adc_input_char_range<T>) {
|
if constexpr (traits::adc_input_char_range<T>) {
|
||||||
std::ranges::copy(v, std::back_inserter(_byteStorage));
|
std::ranges::copy(v, std::back_inserter(_storageSequence.emplace_back()));
|
||||||
} else if constexpr (traits::formattable<T>) {
|
} else if constexpr (traits::formattable<T>) {
|
||||||
std::format_to(std::back_inserter(_byteStorage), v);
|
std::format_to(std::back_inserter(_storageSequence.emplace_back()), v);
|
||||||
} else {
|
} else {
|
||||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||||
}
|
}
|
||||||
@ -139,128 +90,113 @@ public:
|
|||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
void setBytes(const T& v, const Ts&... vs)
|
void setBytes(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
_byteStorage = ByteStorageT();
|
_storageSequence.clear();
|
||||||
|
_outputSequence.clear();
|
||||||
|
|
||||||
appendBytes(v, vs...);
|
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>
|
template <std::input_iterator IterT>
|
||||||
void appendBytes(IterT begin, IterT end)
|
void appendBytes(IterT begin, IterT end)
|
||||||
{
|
{
|
||||||
std::copy(begin, end, std::back_inserter(_byteStorage));
|
static_assert(std::is_same_v<std::iter_value_t<IterT>, char>, "INVALID ITERATOR VALUE TYPE!!!");
|
||||||
|
|
||||||
|
std::ranges::copy(begin, end, std::back_inserter(_storageSequence.emplace_back()));
|
||||||
|
|
||||||
updateState();
|
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>
|
template <std::input_iterator IterT>
|
||||||
void setBytes(IterT begin, IterT end)
|
void setBytes(IterT begin, IterT end)
|
||||||
{
|
{
|
||||||
_byteStorage = ByteStorageT(begin, end);
|
_storageSequence.clear();
|
||||||
|
_outputSequence.clear();
|
||||||
|
|
||||||
appendBytes(begin, end);
|
appendBytes(begin, end);
|
||||||
|
|
||||||
updateState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual size_t byteSize() const
|
||||||
virtual size_t byteSize()
|
|
||||||
{
|
{
|
||||||
auto v = _storageSequence |
|
if (_outputSequence.empty()) {
|
||||||
std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) |
|
return 0;
|
||||||
std::views::join;
|
}
|
||||||
|
|
||||||
|
auto v = _outputSequence | std::views::join;
|
||||||
|
|
||||||
return std::ranges::distance(v.begin(), v.end());
|
return std::ranges::distance(v.begin(), v.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual ByteStorageT bytes()
|
template <traits::adc_output_char_range R>
|
||||||
|
size_t bytes(R& r)
|
||||||
{
|
{
|
||||||
auto v = _storageSequence |
|
if (_outputSequence.empty()) {
|
||||||
std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) |
|
return 0;
|
||||||
std::views::join;
|
}
|
||||||
|
|
||||||
return ByteStorageT{v.begin(), v.end()};
|
auto v = _outputSequence | std::views::join;
|
||||||
|
|
||||||
|
std::ranges::copy(v, std::back_inserter(r));
|
||||||
|
|
||||||
|
return std::ranges::distance(v.begin(), v.end());
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual const StorageSeqT& storageSeq() = 0;
|
virtual const output_seq_t& storageSeq() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::string> _storageSequence;
|
||||||
|
|
||||||
|
output_seq_t _outputSequence;
|
||||||
|
|
||||||
|
AdcNetMessageInterface() : _storageSequence(), _outputSequence() {};
|
||||||
|
|
||||||
|
template <typename T, typename... 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 bool byteStorageEmpty() const
|
||||||
|
{
|
||||||
|
for (const auto& el : _storageSequence) {
|
||||||
|
if (!el.empty()) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateState()
|
||||||
|
{
|
||||||
|
// just add view to byte data
|
||||||
|
_outputSequence.emplace_back(_storageSequence.back());
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* GENERIC (NOTHING SPECIAL) NETWORK MESSAGE */
|
/* GENERIC (NOTHING SPECIAL) NETWORK MESSAGE */
|
||||||
|
|
||||||
template <std::ranges::output_range<char> ByteStorageT = std::vector<char>>
|
class AdcGenericNetMessage : public AdcNetMessageInterface
|
||||||
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:
|
public:
|
||||||
using typename base_t::byte_storage_t;
|
using AdcNetMessageInterface::AdcNetMessageInterface;
|
||||||
using typename base_t::storage_seq_t;
|
|
||||||
|
|
||||||
// using base_t::appendBytes;
|
|
||||||
// using base_t::setBytes;
|
|
||||||
|
|
||||||
using base_t::base_t;
|
|
||||||
|
|
||||||
virtual ~AdcGenericNetMessage() = default;
|
virtual ~AdcGenericNetMessage() = default;
|
||||||
|
|
||||||
const storage_seq_t& storageSeq() override
|
const output_seq_t& storageSeq() override { return _outputSequence; };
|
||||||
{
|
|
||||||
this->_storageSequence[0] = this->_byteStorage;
|
|
||||||
|
|
||||||
return this->_storageSequence;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void updateState() override {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -274,187 +210,222 @@ static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " ";
|
|||||||
} // namespace constants
|
} // namespace constants
|
||||||
|
|
||||||
|
|
||||||
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER,
|
template <const char* TOKEN_DELIM = constants::ADC_DEFAULT_TOKEN_DELIMITER>
|
||||||
std::ranges::output_range<char> ByteStorageT = std::vector<char>>
|
class AdcTokenNetMessage : protected AdcNetMessageInterface // (hide setBytes/appendBytes)
|
||||||
class AdcTokenNetMessage : public AdcGenericNetMessage<ByteStorageT>
|
|
||||||
{
|
{
|
||||||
using base_t = AdcGenericNetMessage<ByteStorageT>;
|
using base_t = AdcNetMessageInterface;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
|
||||||
|
|
||||||
using typename base_t::byte_storage_t;
|
AdcTokenNetMessage() = default;
|
||||||
using typename base_t::storage_seq_t;
|
|
||||||
|
|
||||||
using base_t::base_t;
|
template <typename T, typename... Ts>
|
||||||
|
AdcTokenNetMessage(const T& v, const Ts&... vs) : AdcTokenNetMessage()
|
||||||
|
{
|
||||||
|
appendTokens(v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~AdcTokenNetMessage() = default;
|
virtual ~AdcTokenNetMessage() = default;
|
||||||
|
|
||||||
template <std::ranges::input_range R>
|
|
||||||
void appendTokens(const R& r)
|
template <typename T, typename... Ts>
|
||||||
|
void appendTokens(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
using el_t = std::ranges::range_value_t<R>;
|
if constexpr (traits::adc_input_char_range<T> || traits::formattable<T>) {
|
||||||
|
this->appendBytes(v);
|
||||||
|
} else if constexpr (std::ranges::input_range<T>) {
|
||||||
|
using el_t = std::ranges::range_value_t<T>;
|
||||||
static_assert(traits::adc_input_char_range<el_t> || traits::formattable<el_t>,
|
static_assert(traits::adc_input_char_range<el_t> || traits::formattable<el_t>,
|
||||||
"INVALID TYPE OF INPUT TOKENS!!!");
|
"INVALID TYPE OF INPUT TOKENS!!!");
|
||||||
|
|
||||||
size_t n_toks = 0;
|
if (std::ranges::distance(v.begin(), v.end())) {
|
||||||
if ((n_toks = std::ranges::distance(r.begin(), r.end())) == 0) {
|
for (const auto& el : v) {
|
||||||
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(el);
|
||||||
this->appendBytes(tokenDelimiter);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->appendBytes(*(r.end()--)); // last element
|
} else {
|
||||||
|
static_assert(false, "INVALID TYPE OF INPUT TOKENS!!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof...(Ts)) {
|
||||||
|
appendTokens(vs...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <std::ranges::input_range R>
|
template <typename T, typename... Ts>
|
||||||
void setTokens(const R& r)
|
void setTokens(const T& v, const Ts&... vs)
|
||||||
{
|
{
|
||||||
this->_byteStorage = ByteStorageT();
|
_storageSequence.clear();
|
||||||
appendTokens(r);
|
_outputSequence.clear();
|
||||||
|
|
||||||
|
appendTokens(v, vs...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::ranges::output_range<ByteStorageT> R>
|
template <traits::adc_output_range_of_char_range_c R>
|
||||||
void tokens(R& r)
|
void tokens(R& r, size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
|
||||||
{
|
{
|
||||||
if (this->byteStorageEmpty()) {
|
if (byteStorageEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ranges::copy(this->_byteStorage | std::views::split(AdcTokenNetMessage::tokenDelimiter),
|
if ((start >= _storageSequence.size()) || !N) {
|
||||||
std::back_inserter(r));
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ranges::copy(_storageSequence | std::views ::drop(start) | std::views::take(N), std::back_inserter(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_output_char_range R>
|
||||||
|
void tokensBytes(R& r, size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
|
||||||
|
{
|
||||||
|
if (byteStorageEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((start >= _storageSequence.size()) || !N) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto max_el = _storageSequence.size() - start;
|
||||||
|
N >= max_el ? max_el * 2 - 1 : N * 2 - 1;
|
||||||
|
|
||||||
|
std::ranges::copy(_outputSequence | std::views::drop(start * 2) | std::views::take(N), std::back_inserter(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
const output_seq_t& storageSeq() override
|
||||||
|
{
|
||||||
|
// nothing special, just returns the reference
|
||||||
|
return _outputSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IterT>
|
||||||
|
void appendFromBytes(IterT begin, IterT end)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<std::iter_value_t<IterT>, char>, "INVALID ITERATOR VALUE TYPE!!!");
|
||||||
|
|
||||||
|
auto curr_n_toks = _storageSequence.size();
|
||||||
|
auto n_toks = utils::AdcSplitCharRangeToTokens(_storageSequence, std::span(begin, end), tokenDelimiter);
|
||||||
|
|
||||||
|
if (n_toks) {
|
||||||
|
n_toks += curr_n_toks;
|
||||||
|
|
||||||
|
if (curr_n_toks) {
|
||||||
|
_outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence
|
||||||
|
}
|
||||||
|
_outputSequence.emplace_back(_storageSequence[curr_n_toks]);
|
||||||
|
|
||||||
|
for (auto i = curr_n_toks + 1; i < n_toks; ++i) {
|
||||||
|
_outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence
|
||||||
|
_outputSequence.emplace_back(_storageSequence[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IterT>
|
||||||
|
void setFromBytes(IterT begin, IterT end)
|
||||||
|
{
|
||||||
|
_storageSequence.clear();
|
||||||
|
_outputSequence.clear();
|
||||||
|
|
||||||
|
appendFromBytes(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// std::vector<ByteStorageT> _tokens;
|
void updateState() override
|
||||||
|
{
|
||||||
void updateState() override {}
|
if (_outputSequence.size()) {
|
||||||
|
_outputSequence.emplace_back(tokenDelimiter); // add delimiter in output sequence
|
||||||
|
}
|
||||||
|
_outputSequence.emplace_back(_storageSequence.back());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <const char* KEY_PARAM_DELIM = constants::ADC_DEFAULT_KEY_PARAM_DELIMITER,
|
template <const char* KEY_PARAM_DELIM = constants::ADC_DEFAULT_KEY_PARAM_DELIMITER,
|
||||||
const char* PARAM_PARAM_DELIM = constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER,
|
const char* PARAM_PARAM_DELIM = constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER>
|
||||||
std::ranges::output_range<char> ByteStorageT = std::vector<char>>
|
class AdcKeyParamNetMessage : protected AdcTokenNetMessage<PARAM_PARAM_DELIM>
|
||||||
class AdcKeyParamNetMessage : public AdcGenericNetMessage<ByteStorageT>
|
|
||||||
{
|
{
|
||||||
using base_t = AdcGenericNetMessage<ByteStorageT>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr std::string_view keyparamDelimiter{KEY_PARAM_DELIM};
|
static constexpr std::string_view keyparamDelimiter{KEY_PARAM_DELIM};
|
||||||
static constexpr std::string_view paramparamDelimiter{PARAM_PARAM_DELIM};
|
static constexpr std::string_view paramparamDelimiter{PARAM_PARAM_DELIM};
|
||||||
|
|
||||||
using typename base_t::byte_storage_t;
|
AdcKeyParamNetMessage() = default;
|
||||||
using typename base_t::storage_seq_t;
|
|
||||||
|
|
||||||
using base_t::base_t;
|
template <typename KeyT, typename... ParamTs>
|
||||||
|
AdcKeyParamNetMessage(const KeyT& key, const ParamTs&... params) : AdcKeyParamNetMessage()
|
||||||
|
{
|
||||||
|
setKeyParam(key, params...);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~AdcKeyParamNetMessage() = default;
|
virtual ~AdcKeyParamNetMessage() = default;
|
||||||
|
|
||||||
// key and params
|
// key and params
|
||||||
template <typename KeyT, typename... ParamTs>
|
template <typename KeyT, typename... ParamTs>
|
||||||
void setKeyParam(KeyT&& key, ParamTs&&... params)
|
void setKeyParam(const KeyT& key, const ParamTs&... params)
|
||||||
{
|
{
|
||||||
this->_byteStorage = ByteStorageT();
|
_key.clear();
|
||||||
|
this->_storageSequence.clear();
|
||||||
|
this->_outputSequence.clear();
|
||||||
|
|
||||||
|
if constexpr (traits::adc_input_char_range<KeyT> || traits::formattable<KeyT>) {
|
||||||
|
std::ranges::copy(key, std::back_inserter(_key));
|
||||||
|
} else if constexpr (traits::formattable<KeyT>) {
|
||||||
|
std::format_to(std::back_inserter(_key), "{}", key);
|
||||||
|
} else {
|
||||||
|
static_assert(false, "INVALID KEY-VALUE TYPE!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_outputSequence.emplace_back(_key);
|
||||||
|
|
||||||
if constexpr (sizeof...(ParamTs)) {
|
if constexpr (sizeof...(ParamTs)) {
|
||||||
this->setBytes(std::forward<KeyT>(key), keyparamDelimiter);
|
this->setTokens(params...);
|
||||||
setKeyParamHelper(std::forward<ParamTs>(params)...);
|
|
||||||
} else {
|
|
||||||
this->setBytes(std::forward<KeyT>(key));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <traits::adc_output_char_range R>
|
template <traits::adc_output_char_range R>
|
||||||
R key() const
|
void key(R& r) const
|
||||||
{
|
{
|
||||||
R val;
|
if constexpr (std::is_convertible_v<std::string, R>) {
|
||||||
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
n_pars = 0;
|
std::ranges::copy(_key, std::back_inserter(r));
|
||||||
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));
|
template <traits::adc_output_range_of_char_range_c R>
|
||||||
num -= std::ranges::distance(pars.begin(), pars.end());
|
void params(R& r, size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
|
||||||
if (!num) {
|
{
|
||||||
break;
|
this->tokens(r, start, N);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <traits::adc_output_char_range R>
|
template <traits::adc_output_char_range R>
|
||||||
R paramsBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
|
void paramsBytes(R& r, size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
|
||||||
{
|
{
|
||||||
R pars_bytes;
|
this->tokensBytes(r, start, N);
|
||||||
|
|
||||||
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:
|
protected:
|
||||||
template <typename ParamT, typename... ParamTs>
|
std::string _key;
|
||||||
void setKeyParamHelper(ParamT&& param, ParamTs&&... params)
|
// _outputSequence will store parameters
|
||||||
{
|
|
||||||
this->appendBytes(std::forward<ParamT>(param));
|
|
||||||
|
|
||||||
if constexpr (sizeof...(ParamTs)) {
|
void updateState() override
|
||||||
this->appendBytes(paramparamDelimiter);
|
{
|
||||||
setKeyParamHelper(std::forward<ParamTs>(params)...);
|
if (this->_outputSequence.size()) {
|
||||||
|
this->_outputSequence.emplace_back(paramparamDelimiter); // add param-param delimiter in output sequence
|
||||||
|
} else {
|
||||||
|
this->_outputSequence.emplace_back(keyparamDelimiter); // add key-param delimiter in output sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->_outputSequence.emplace_back(this->_storageSequence.back());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user