From 8bcc8edbb0f9cb62ced686b7ac134b1c4328d0cc Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Sun, 6 Oct 2024 23:12:22 +0300 Subject: [PATCH] ... --- common/adc_utils.h | 43 +++++++++ net/adc_device_netmsg.h | 198 ++++++++++++++++++++++++++++++++++++-- tests/adc_netmsg_test.cpp | 13 +++ 3 files changed, 244 insertions(+), 10 deletions(-) diff --git a/common/adc_utils.h b/common/adc_utils.h index 7362b14..9e5d7f2 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -27,6 +27,49 @@ static auto AdcTrimSpaces(R&& r) } +enum class AdcTrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH }; + +template + requires std::ranges::contiguous_range +static auto AdcTrimSpacesView(R&& r, AdcTrimType type = AdcTrimType::TRIM_BOTH) +{ + auto is_space = [](const auto& ch) { return ch == ' '; }; + + auto end = std::forward(r).end(); + + auto f1 = std::forward(r).begin(); + + if (type != AdcTrimType::TRIM_RIGHT) { + // look for the first non-space symbol + f1 = std::ranges::find_if_not(std::forward(r), is_space); + if (f1 == end) { // all are spaces! + return VR(); + } + } + + auto f2 = end; + + if (type != AdcTrimType::TRIM_LEFT) { + auto f3 = f1; + + do { + f2 = std::ranges::find_if(++f3, end, is_space); + if (f2 == end) + break; + f3 = std::ranges::find_if_not(f2 + 1, end, is_space); + } while (f3 != end); + } + + return VR(f1, f2); +} + +template +static auto AdcTrimSpacesView(R&& r, AdcTrimType type = AdcTrimType::TRIM_BOTH) +{ + return AdcTrimSpacesView(std::forward(r), type); +} + + template static ValueT AdcFromChars(R&& range) { diff --git a/net/adc_device_netmsg.h b/net/adc_device_netmsg.h index aad5c34..d1a9bab 100644 --- a/net/adc_device_netmsg.h +++ b/net/adc_device_netmsg.h @@ -1,7 +1,7 @@ #pragma once #include "../common/adc_utils.h" -#include "adc_netmsg.h" +// #include "adc_netmsg.h" namespace adc { @@ -11,23 +11,160 @@ namespace adc namespace constants { +static constexpr char ADC_DEFAULT_KEY_VALUE_DELIMITER1[] = " "; static constexpr char ADC_DEFAULT_KEY_PARAM_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " "; +static constexpr char ADC_DEFAULT_COMPOSITE_PARAM_DELIMITER[] = ","; } // namespace constants -template -class AdcDeviceNetMessage : protected AdcKeyValueMessage + +template +class AdcKeyValueMessage1 { - using base_t = AdcKeyValueMessage; +public: + static constexpr std::span keyValueDelimiter{KEY_VALUE_DELIM, sizeof(KEY_VALUE_DELIM) - 1}; + static constexpr std::span valueDelimiter{VALUE_DELIM, sizeof(VALUE_DELIM) - 1}; + + AdcKeyValueMessage1(ByteSeqT& byte_seq) : _byteSequence(byte_seq) {} + + virtual ~AdcKeyValueMessage1() = default; + + template + requires(traits::adc_char_view && std::ranges::contiguous_range) || + traits::adc_output_char_range + auto key() const + { + if constexpr (traits::adc_char_view && std::ranges::contiguous_range) { + auto bs = utils::AdcTrimSpacesView(_byteSequence, utils::AdcTrimType::TRIM_LEFT); + auto found = std::ranges::search(bs, keyValueDelimiter); + + // if (found.empty) { // no value + // return bs; + // } + + return utils::AdcTrimSpacesView(std::span(bs.begin(), found.begin()), + utils::AdcTrimType::TRIM_RIGHT); + } else { + T res; + + auto bs = _byteSequence | std::views::drop_while([](const auto& ch) { return ch = ' '; }); + + auto found = std::ranges::search(bs, keyValueDelimiter); + std::ranges::copy(bs.begin(), found.begin(), std::back_inserter(res)); + // if (found.empty()) { // no value + // std::ranges::copy(bs, std::back_inserter(res)); + // } else { + // std::ranges::copy(bs.begin(), found.begin(), std::back_inserter(res)); + // } + + return res; + } + } + + + auto key() const + { + if constexpr (std::ranges::contiguous_range) { + return key(); + } else { + return key(); + } + } + + + template + requires(traits::adc_char_view && std::ranges::contiguous_range) || + traits::adc_output_char_range + auto value() const + { + if constexpr (traits::adc_char_view && std::ranges::contiguous_range) { + auto bs = utils::AdcTrimSpacesView(_byteSequence, utils::AdcTrimType::TRIM_LEFT); + auto found = std::ranges::search(bs, keyValueDelimiter); + + // if (found.empty()) { // no value + // return T(); + // } + + return T(found.end(), _byteSequence.end()); + } else { + T res; + + auto bs = _byteSequence | std::views::drop_while([](const auto& ch) { return ch = ' '; }); + + auto found = std::ranges::search(bs, keyValueDelimiter); + if (!found.empty()) { + std::ranges::copy(found.end(), _byteSequence.end(), std::back_inserter(res)); + } + + return res; + } + } + + auto value() const + { + if constexpr (std::ranges::contiguous_range) { + return value(); + } else { + return value(); + } + } + + + template + requires traits::adc_output_char_range + AdcKeyValueMessage1& setKeyValue(KeyT&& key, ValueT&& value) + { + if (std::ranges::size(_byteSequence)) { + _byteSequence = _byteSequence(); + } + + std::ranges::copy( + utils::AdcDefaultValueConverter::template serialize(std::forward(key)), + std::back_inserter(_byteSequence)); + + std::ranges::copy(keyValueDelimiter, std::back_inserter(_byteSequence)); + + std::ranges::copy( + utils::AdcDefaultValueConverter::template serialize(std::forward(value)), + std::back_inserter(_byteSequence)); + + return *this; + } + + + template + AdcKeyValueMessage1& setValue(ValueT&& value) + { + std::vector kw; + std::ranges::copy(key>(), std::back_inserter(kw)); + + return setKeyValue(kw, std::forward(value)); + } + +protected: + ByteSeqT& _byteSequence; +}; + + + +template +class AdcDeviceNetMessage : public AdcKeyValueMessage1 +{ + using base_t = AdcKeyValueMessage1; public: - static constexpr std::span keyParamDelimiter{constants::ADC_DEFAULT_KEY_PARAM_DELIMITER, - sizeof(constants::ADC_DEFAULT_KEY_PARAM_DELIMITER)}; + static constexpr std::span keyParamDelimiter{KEY_PARAM_DELIM, sizeof(KEY_PARAM_DELIM) - 1}; - static constexpr std::span paramParamDelimiter{constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER, - sizeof(constants::ADC_DEFAULT_PARAM_PARAM_DELIMITER)}; + static constexpr std::span paramParamDelimiter{PARAM_PARAM_DELIM, sizeof(PARAM_PARAM_DELIM) - 1}; + + static constexpr std::span compParamDelimiter{COMPOSITE_PARAM_DELIM, sizeof(COMPOSITE_PARAM_DELIM) - 1}; AdcDeviceNetMessage(ByteSeqT& byte_seq) : base_t(byte_seq) {} @@ -35,8 +172,22 @@ public: template VT keyword() const { - auto v = utils::AdcTrimSpaces(base_t::template key()); - return VT(v.begin(), v.end()); + // auto v = utils::AdcTrimSpaces(base_t::template key()); + // return VT(std::begin(v), std::end(v)); + + std::span key; + // first, remove spaces at the beginning and end of byte sequence + auto bs = utils::AdcTrimSpacesView>(this->_byteSequence); + + auto found = std::ranges::search(bs, keyParamDelimiter); + if (found.empty()) { // only keyword + return VT(bs.begin(), bs.end()); + } + + key = std::span(bs.begin(), found.begin()); + + + return utils::AdcTrimSpacesView(key); } auto keyword() const @@ -49,6 +200,33 @@ public: auto params(size_t start = 0, size_t N = std::numeric_limits::max()) { auto val = base_t::template value>(); + + // auto p = utils::AdcTokenManip(val).tokens(start, N); + + R res; + std::ranges::for_each(std::views::split(val, keyParamDelimiter) | std::views::drop(start) | std::views::take(N), + [&res](const auto& el) { + // remove spaces + std::back_inserter(res) = utils::AdcTrimSpacesView>(el); + // std::ranges::copy(utils::AdcTrimSpaces(el), std::back_inserter(res)); + }); + + return res; + } + + auto params(size_t start = 0, size_t N = std::numeric_limits::max()) + { + return params>(start, N); + } + + + template + auto joinParams(size_t start = 0, size_t N = std::numeric_limits::max()) + { + R res; + utils::AdcJoinRange(params>>(start, N), paramParamDelimiter, res); + + return res; } }; diff --git a/tests/adc_netmsg_test.cpp b/tests/adc_netmsg_test.cpp index ceb65c3..458e477 100644 --- a/tests/adc_netmsg_test.cpp +++ b/tests/adc_netmsg_test.cpp @@ -6,6 +6,7 @@ // #include "../common/adc_utils.h" // #include "../net/adc_netmessage.h" +#include "../net/adc_device_netmsg.h" #include "../net/adc_endpoint.h" #include "../net/adc_netmsg.h" @@ -80,6 +81,18 @@ TEST_CASE("[ADC NET MESSAGE]") ept.setEndpoint(ee); std::cout << "EPT: [" << ept.endpoint() << "]\n"; + + + std::string bs = " SET EXP 1.24 0.23652 9.765432 "; + std::cout << "BS: {" << bs << "}\n"; + + AdcDeviceNetMessage md(bs); + + std::cout << "KEY = {" << md.keyword() << "}\n"; + std::cout << "KEY = {" << md.key() << "}\n"; + for (auto& pp : md.params(1, 2)) { + std::cout << "PAR: " << pp << "\n"; + } } /*