This commit is contained in:
Timur A. Fatkhullin 2024-06-05 09:35:39 +03:00
parent 2f662b0d79
commit cf543feeb5
4 changed files with 86 additions and 49 deletions

View File

@ -23,7 +23,8 @@ set(ADC_DEVICE_HEADERS
set(ADC_NETWORK_HEADERS set(ADC_NETWORK_HEADERS
net/adc_netmessage.h net/adc_netmsg.h
# net/adc_netmessage.h
net/adc_netproto.h net/adc_netproto.h
net/adc_netservice.h net/adc_netservice.h
) )

View File

@ -448,7 +448,7 @@ public:
template <std::ranges::input_range R, template <std::ranges::input_range R,
std::ranges::input_range RD, std::ranges::input_range RD,
std::ranges::output_range<std::ranges::range_value_t<RD>> RO> std::ranges::output_range<std::ranges::range_value_t<RD>> RO>
static size_t AdcJoinRange(R& r, const RD& delim, RO& ro) static size_t AdcJoinRange(const R& r, const RD& delim, RO& ro)
requires std::ranges::range<std::ranges::range_value_t<R>> && // input R is range of ranges requires std::ranges::range<std::ranges::range_value_t<R>> && // input R is range of ranges
std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<R>>, std::ranges::range_value_t<RD>> std::same_as<std::ranges::range_value_t<std::ranges::range_value_t<R>>, std::ranges::range_value_t<RD>>
{ {

View File

@ -13,13 +13,14 @@
namespace adc namespace adc
{ {
namespace utils { namespace utils
template<typename ByteStorageT, typename T, typename... Ts>
void convertToBytes(ByteStorageT &res, const T &v, const Ts &...vs)
{ {
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) { // to handle with trailing '\0' in plain char array
template <typename ByteStorageT, typename T, typename... Ts>
void convertToBytes(ByteStorageT& res, const T& v, const Ts&... vs)
{
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) { // to handle with trailing '\0' in plain char array
convertToBytes(res, std::string_view(v), vs...); convertToBytes(res, std::string_view(v), vs...);
} else { } else {
if constexpr (traits::adc_input_char_range<T>) { if constexpr (traits::adc_input_char_range<T>) {
@ -39,36 +40,36 @@ void convertToBytes(ByteStorageT &res, const T &v, const Ts &...vs)
} }
} // namespace utils } // namespace utils
namespace traits { namespace traits
{
template<typename T> template <typename T>
concept adc_netmessage_c = requires(const T t) { // const methods concept adc_netmessage_c = requires(const T t) { // const methods
{ t.empty() } -> std::convertible_to<bool>; { t.empty() } -> std::convertible_to<bool>;
{ t.bytes() } -> adc_output_char_range; { t.bytes() } -> adc_output_char_range;
{ t.byteView() } -> adc_range_of_view_char_range; { t.byteView() } -> adc_range_of_view_char_range;
}; };
} // namespace traits } // namespace traits
/* /*
Trivial message interface: Trivial message interface:
byte storage: just a char-range byte storage: just a char-range
*/ */
template<traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view> template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
class AdcNetMessageTrivialInterface class AdcNetMessageTrivialInterface
{ {
public: public:
virtual ~AdcNetMessageTrivialInterface() = default; virtual ~AdcNetMessageTrivialInterface() = default;
bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; } bool empty() const { return std::ranges::distance(_bytes.begin(), _bytes.end()) == 0; }
// get a copy of message bytes // get a copy of message bytes
template<traits::adc_output_char_range R> template <traits::adc_output_char_range R>
R bytes() const R bytes() const
{ {
R r; R r;
@ -85,7 +86,7 @@ public:
} }
// get a view of message bytes // get a view of message bytes
template<traits::adc_range_of_view_char_range R> template <traits::adc_range_of_view_char_range R>
R bytesView() const R bytesView() const
{ {
R r; R r;
@ -113,7 +114,7 @@ protected:
interface for more complex messages: interface for more complex messages:
byte storage: std::vector of char-range (sequence of buffers) byte storage: std::vector of char-range (sequence of buffers)
*/ */
template<traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view> template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
class AdcNetMessageSeqInterface class AdcNetMessageSeqInterface
{ {
public: public:
@ -126,7 +127,7 @@ public:
} }
bool emp = true; bool emp = true;
for (const auto &el : _bytes) { for (const auto& el : _bytes) {
if (std::ranges::distance(el.begin(), el.end())) { if (std::ranges::distance(el.begin(), el.end())) {
emp = false; emp = false;
break; break;
@ -137,14 +138,14 @@ public:
} }
// get a copy of message bytes // get a copy of message bytes
template<traits::adc_output_char_range R> template <traits::adc_output_char_range R>
R bytes() const R bytes() const
{ {
R r; R r;
for (size_t i = 0; i < _bytes.size(); ++i) { for (size_t i = 0; i < _bytes.size(); ++i) {
std::ranges::for_each(storageViewByIndex(i), std::ranges::for_each(storageViewByIndex(i),
[&r](const auto &el) { std::ranges::copy(el, std::back_inserter(r)); }); [&r](const auto& el) { std::ranges::copy(el, std::back_inserter(r)); });
} }
return r; return r;
@ -158,14 +159,15 @@ public:
} }
// get a view of message bytes // get a view of message bytes
template<traits::adc_range_of_view_char_range R> template <traits::adc_range_of_view_char_range R>
R bytesView() const R bytesView() const
{ {
R r; R r;
for (size_t i = 0; i < _bytes.size(); ++i) { for (size_t i = 0; i < _bytes.size(); ++i) {
std::ranges::for_each(storageViewByIndex(i), [&r](const auto &el) { r.emplace_back(el.begin(), el.end()); }); std::ranges::for_each(storageViewByIndex(i),
[&r](const auto& el) { r.emplace_back(el.begin(), el.end()); });
} }
return r; return r;
@ -190,9 +192,6 @@ protected:
// Generic message class // Generic message class
template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view> template <traits::adc_output_char_range ByteStorageT = std::string, traits::adc_char_view ByteViewT = std::string_view>
class AdcGenericNetMessage : public AdcNetMessageTrivialInterface<ByteStorageT, ByteViewT> class AdcGenericNetMessage : public AdcNetMessageTrivialInterface<ByteStorageT, ByteViewT>
@ -206,8 +205,8 @@ public:
using base_t::empty; using base_t::empty;
template<typename T, typename... Ts> template <typename T, typename... Ts>
AdcGenericNetMessage(const T &v, const Ts &...vs) : AdcGenericNetMessage() AdcGenericNetMessage(const T& v, const Ts&... vs) : AdcGenericNetMessage()
{ {
appendBytes(v, vs...); appendBytes(v, vs...);
} }
@ -266,8 +265,8 @@ class AdcTokenNetMessage : public AdcNetMessageSeqInterface<ByteStorageT, ByteVi
public: public:
static constexpr std::string_view tokenDelimiter{TOKEN_DELIM}; static constexpr std::string_view tokenDelimiter{TOKEN_DELIM};
using base_t::bytesView;
using base_t::bytes; using base_t::bytes;
using base_t::bytesView;
using base_t::empty; using base_t::empty;
AdcTokenNetMessage() = default; AdcTokenNetMessage() = default;
@ -302,6 +301,27 @@ public:
} }
template <traits::adc_output_char_range R>
R tokensBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{
R r;
if (empty() || (start >= this->_bytes.size()) || !N) {
return r;
}
utils::AdcJoinRange(this->_bytes | std::views::drop(start) | std::views::take(N), tokenDelimiter, r);
return r;
}
ByteStorageT tokensBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{
return tokensBytes<ByteStorageT>(start, N);
}
template <typename T, typename... Ts> template <typename T, typename... Ts>
void appendTokens(const T& v, const Ts&... vs) void appendTokens(const T& v, const Ts&... vs)
{ {
@ -347,7 +367,7 @@ public:
it = std::search(start_it, end, tokenDelimiter.begin(), tokenDelimiter.end()); it = std::search(start_it, end, tokenDelimiter.begin(), tokenDelimiter.end());
std::copy(start_it, it, std::back_inserter(this->_bytes.emplace_back())); std::copy(start_it, it, std::back_inserter(this->_bytes.emplace_back()));
start_it = it; start_it = it;
std::advance(start_it, tokenDelimiter.size()); // to support not only random-access iterators std::advance(start_it, tokenDelimiter.size()); // to support not only random-access iterators
} while (it != end); } while (it != end);
} }
@ -364,11 +384,11 @@ public:
protected: protected:
virtual std::vector<ByteViewT> storageViewByIndex(size_t idx) const override virtual std::vector<ByteViewT> storageViewByIndex(size_t idx) const override
{ {
const ByteStorageT &el = this->_bytes[idx]; const ByteStorageT& el = this->_bytes[idx];
std::vector<ByteViewT> vw{{el.begin(), el.end()}}; std::vector<ByteViewT> vw{{el.begin(), el.end()}};
auto last_idx = this->_bytes.size() - 1; auto last_idx = this->_bytes.size() - 1;
if (idx < last_idx) { // add delimiter if (idx < last_idx) { // add delimiter
vw.emplace_back(tokenDelimiter.begin(), tokenDelimiter.end()); vw.emplace_back(tokenDelimiter.begin(), tokenDelimiter.end());
} }
@ -392,20 +412,20 @@ class AdcKeyTokenNetMessage : public AdcTokenNetMessage<TOKEN_DELIM, ByteStorage
public: public:
static constexpr std::string_view keytokenDelimiter{KEY_TOKEN_DELIM}; static constexpr std::string_view keytokenDelimiter{KEY_TOKEN_DELIM};
using base_t::appendFromBytes; // append only tokens not keyword
using base_t::appendTokens; using base_t::appendTokens;
using base_t::bytes;
using base_t::bytesView;
using base_t::empty;
using base_t::setTokens; using base_t::setTokens;
using base_t::tokens; using base_t::tokens;
using base_t::appendFromBytes; // append only tokens not keyword
using base_t::bytesView;
using base_t::bytes;
using base_t::empty;
AdcKeyTokenNetMessage() = default; AdcKeyTokenNetMessage() = default;
template<typename KT, typename T, typename... Ts> template <typename KT, typename T, typename... Ts>
AdcKeyTokenNetMessage(const KT &key, const T &tok, const Ts &...toks) AdcKeyTokenNetMessage(const KT& key, const T& tok, const Ts&... toks)
{ {
utils::convertToBytes(this->_bytes.emplace_back(), key); utils::convertToBytes(this->_bytes.emplace_back(), key);
setTokens(tok, toks...); setTokens(tok, toks...);
@ -459,7 +479,7 @@ public:
return ByteViewT{this->_bytes[0].begin(), this->_bytes[0].end()}; return ByteViewT{this->_bytes[0].begin(), this->_bytes[0].end()};
} }
template<std::ranges::output_range<ByteStorageT> R> template <std::ranges::output_range<ByteStorageT> R>
R tokens(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const R tokens(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{ {
// "+1" since the first element is keyword // "+1" since the first element is keyword
@ -472,9 +492,23 @@ public:
return tokens<std::vector<ByteStorageT>>(start, N); return tokens<std::vector<ByteStorageT>>(start, N);
} }
template <traits::adc_output_char_range R>
R tokensBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{
// "+1" since the first element is keyword
return base_t::template tokensBytes<ByteStorageT>(start + 1, N);
}
template<typename KT, typename T, typename... Ts>
void setKeyTokens(const KT &key, const T &tok, const Ts &...toks) ByteStorageT tokensBytes(size_t start = 0, size_t N = std::numeric_limits<size_t>::max()) const
{
return tokensBytes<ByteStorageT>(start, N);
}
template <typename KT, typename T, typename... Ts>
void setKeyTokens(const KT& key, const T& tok, const Ts&... toks)
{ {
this->_bytes.clear(); this->_bytes.clear();
@ -486,13 +520,13 @@ public:
template <typename T, typename... Ts> template <typename T, typename... Ts>
void setTokens(const T& v, const Ts&... vs) void setTokens(const T& v, const Ts&... vs)
{ {
this->_bytes.resize(1); // the first element is keyword this->_bytes.resize(1); // the first element is keyword
appendTokens(v, vs...); appendTokens(v, vs...);
} }
template<std::input_iterator IT> template <std::input_iterator IT>
void setFromBytes(IT begin, IT end) void setFromBytes(IT begin, IT end)
requires std::same_as<std::iter_value_t<IT>, char> requires std::same_as<std::iter_value_t<IT>, char>
{ {
@ -500,23 +534,22 @@ public:
auto it = std::search(begin, end, keytokenDelimiter.begin(), keytokenDelimiter.end()); auto it = std::search(begin, end, keytokenDelimiter.begin(), keytokenDelimiter.end());
std::copy(begin, it, std::back_inserter(this->_bytes.emplace_back())); // keyword std::copy(begin, it, std::back_inserter(this->_bytes.emplace_back())); // keyword
if (it != end) { if (it != end) {
std::advance(it, keytokenDelimiter.size()); std::advance(it, keytokenDelimiter.size());
appendFromBytes(it, end); // tokens appendFromBytes(it, end); // tokens
} }
} }
protected: protected:
virtual std::vector<ByteViewT> storageViewByIndex(size_t idx) const override virtual std::vector<ByteViewT> storageViewByIndex(size_t idx) const override
{ {
if (idx == 0) { // the first element is keyword if (idx == 0) { // the first element is keyword
const ByteStorageT &el = this->_bytes[idx]; const ByteStorageT& el = this->_bytes[idx];
std::vector<ByteViewT> vw{{el.begin(), el.end()}}; std::vector<ByteViewT> vw{{el.begin(), el.end()}};
if (this->_bytes.size() > 1) { // there are tokens, so add keyword-to-tokens delimiter if (this->_bytes.size() > 1) { // there are tokens, so add keyword-to-tokens delimiter
vw.emplace_back(keytokenDelimiter.begin(), keytokenDelimiter.end()); vw.emplace_back(keytokenDelimiter.begin(), keytokenDelimiter.end());
} }

View File

@ -47,6 +47,9 @@ TEST_CASE("[ADC NET MESSAGE]")
msg.setTokens("FILTER", "A1", "B3"); msg.setTokens("FILTER", "A1", "B3");
std::cout << "BYTES: " << msg.bytes() << "\n"; std::cout << "BYTES: " << msg.bytes() << "\n";
std::cout << "TOK BYTES: " << msg.tokensBytes(1, 1) << "\n";
std::cout << "\n\n---------\n\n"; std::cout << "\n\n---------\n\n";