From fa0cfea8feb822ad515e7c8dd4bbb501c841a782 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Mon, 22 Jan 2024 00:34:49 +0300 Subject: [PATCH] ... --- common/adc_traits.h | 13 +++++- common/adc_utils.h | 99 ++++++++++++++++++++++----------------------- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/common/adc_traits.h b/common/adc_traits.h index 7411f86..a79b91b 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -3,6 +3,7 @@ #include #include #include +#include /* @@ -15,9 +16,17 @@ namespace adc::traits { +// check if type can be used with std::format_to +// (from https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts) +template +concept formattable = requires (T& v, std::format_context ctx) { + std::formatter>().format(v, ctx); +}; + + // range of char/const char -template -concept adc_char_range = std::ranges::range && std::is_same_v>, char>; +template +concept adc_char_range = std::ranges::range && std::is_same_v>, CharT>; // deduce returned type of callable template diff --git a/common/adc_utils.h b/common/adc_utils.h index 756beeb..f46b239 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -12,15 +12,15 @@ namespace adc::utils { -bool AdcIsSpace(char in) noexcept +static bool AdcIsSpace(char in) noexcept { - static auto ws = {' ', '\t', '\n', '\v', '\r', '\f'}; + static constexpr auto ws = {' ', '\t', '\n', '\v', '\r', '\f'}; return std::ranges::any_of(ws, [in](auto p) { return p == in; }); }; template -auto AdcTrimSpaces(R&& r) +static auto AdcTrimSpaces(R&& r) { return r | std::views::drop_while(AdcIsSpace) | std::views::reverse | std::views::drop_while(AdcIsSpace) | std::views::reverse; @@ -28,32 +28,44 @@ auto AdcTrimSpaces(R&& r) template -ValueT AdcFromChars(R&& range) +static ValueT AdcFromChars(R&& range) { if constexpr (std::is_arithmetic_v) { ValueT v; - auto res = std::from_chars(&*range.begin(), &*range.end(), v); + std::from_chars_result res; + const char* end_ptr; + + // std::from_chars needs random-access container!!! + if constexpr (std::ranges::random_access_range) { + res = std::from_chars(&*range.begin(), &*range.end(), v); + end_ptr = &*range.end(); + } else { + std::string s(range.begin(), range.end()); + end_ptr = s.data() + s.size(); + res = std::from_chars(s.data(), s.data() + s.size(), v); + } if (res.ec == std::errc()) { - if (res.ptr != &*range.end()) { + if (res.ptr != end_ptr) { throw std::invalid_argument( - "adc_from_chars: cannot convert char-range to user-type value (invalid argument)"); + "AdcFromChars: cannot convert char-range to user-type value (invalid argument)"); } return v; } else if (res.ec == std::errc::invalid_argument) { throw std::invalid_argument( - "adc_from_chars: cannot convert char-range to user-type value (invalid argument)"); + "AdcFromChars: cannot convert char-range to user-type value (invalid argument)"); } else if (res.ec == std::errc::result_out_of_range) { throw std::invalid_argument( - "adc_from_chars: cannot convert char-range to user-type value (result out of range)"); + "AdcFromChars: cannot convert char-range to user-type value (result out of range)"); } } else if (std::is_constructible_v, std::ranges::iterator_t>) { return ValueT(range.begin(), range.end()); } else { - throw std::invalid_argument( - "adc_from_chars: cannot convert char-range to user-type value (unsupported user-value type)"); + static_assert(false, "AdcFromChars: CANNOT CONVERT CHAR-RANGE TO USER-TYPE VALUE (UNSUPPORTED USER-VALUE TYPE)"); + // throw std::invalid_argument( + // "AdcFromChars: cannot convert char-range to user-type value (unsupported user-value type)"); } } @@ -63,18 +75,17 @@ ValueT AdcFromChars(R&& range) static const std::regex AdcIntegerRegex("^ *[+-]?\\d+\\d* *$", std::regex::ECMAScript); static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript); -template +template static SerializedT AdcTrivialSerializer(VT&& value) { using v_t = std::decay_t; if constexpr (std::is_convertible_v) { return static_cast(std::forward(value)); - } else if (std::is_convertible_v) { - return static_cast(std::to_string(std::forward(value))); } else if (traits::adc_char_range) { - auto s = std::to_string(std::forward(value)); - return SerializedT(s.begin(), s.end()); + SerializedT s_val; + std::format_to(std::back_inserter(s_val), "{}", std::forward(value)); + return s_val; } else { // throw std::invalid_argument("trivial serializer: cannot serialize value"); static_assert(false, "TRIVIAL SERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!"); @@ -85,45 +96,33 @@ static SerializedT AdcTrivialSerializer(VT&& value) template static VT AdcTrivialDeserializer(SerializedT&& s_value) { - static_assert(std::is_convertible_v || traits::adc_char_range, - "TRIVIAL DESERIALIZER: UNSUPPORTED TYPE OF SERIALIZED VALUE!!!"); - - if constexpr (std::is_arithmetic_v) { - if constexpr (traits::adc_char_range) { - if (std::regex_match(s_value.begin(), s_value.end(), AdcIntegerRegex)) { // integer value - return std::stoll({s_value.begin(), s_value.end()}); - } - - if (std::regex_match(s_value.begin(), s_value.end(), AdcRealRegex)) { // floating-point value - return std::stod({s_value.begin(), s_value.end()}); - } - } else { // SerializedT may be converted to std::string - if (std::regex_match(s_value, AdcIntegerRegex)) { // integer value - return std::stoll(std::forward(s_value)); - } - - if (std::regex_match(s_value, AdcRealRegex)) { // floating-point value - return std::stod(std::forward(s_value)); - } - } - - - throw std::invalid_argument("trivial deserializer: unsupported serialized value"); - - } else if (std::is_convertible_v) { - return static_cast(std::forward(s_value)); - } else if (std::is_convertible_v) { // SerializedT is char range - return static_cast(s_v(s_value.begin(), s_value.end())); - } - - throw std::invalid_argument("trivial deserializer: unsupported serialized value"); + return AdcFromChars(std::forward(s_value)); } template -OutputR AdcRangeFromCharRange(InputR&& input_r, DelimR&& delim_r, size_t max_len = std::numeric_limits::max()) +OutputR AdcRangeFromCharRange(InputR&& input_r, DelimR&& delim, size_t max_len = std::numeric_limits::max()) { - OutputR out_r; + OutputR res; + + if (max_len == 0) + return res; + + using value_t = std::ranges::range_value_t; + + if constexpr (std::is_array_v>) { + std::ranges::copy(std::views::split(std::forward(input_r), std::string_view(delim)) | + std::views::filter([](const auto& r) { return !std::ranges::empty(r); }) | + std::views::transform([](auto vl) { return convFunc(vl); }) | std::views::take(max_len), + std::back_inserter(res)); + } else { + std::ranges::copy(std::views::split(std::forward(input_r), std::forward(delim)) | + std::views::filter([](const auto& r) { return !std::ranges::empty(r); }) | + std::views::transform([](auto vl) { return convFunc(vl); }) | std::views::take(max_len), + std::back_inserter(res)); + } + + return res; } } // namespace adc::utils