This commit is contained in:
Timur A. Fatkhullin
2024-01-21 01:57:15 +03:00
parent 096e74c099
commit 41a9c70e70
5 changed files with 224 additions and 43 deletions

129
common/adc_utils.h Normal file
View File

@@ -0,0 +1,129 @@
#pragma once
#include <algorithm>
#include <charconv>
#include <limits>
#include <ranges>
#include <regex>
#include "../common/adc_traits.h"
namespace adc::utils
{
bool AdcIsSpace(char in) noexcept
{
static auto ws = {' ', '\t', '\n', '\v', '\r', '\f'};
return std::ranges::any_of(ws, [in](auto p) { return p == in; });
};
template <traits::adc_char_range R>
auto AdcTrimSpaces(R&& r)
{
return r | std::views::drop_while(AdcIsSpace) | std::views::reverse | std::views::drop_while(AdcIsSpace) |
std::views::reverse;
}
template <typename ValueT, traits::adc_char_range R>
ValueT AdcFromChars(R&& range)
{
if constexpr (std::is_arithmetic_v<ValueT>) {
ValueT v;
auto res = std::from_chars(&*range.begin(), &*range.end(), v);
if (res.ec == std::errc()) {
if (res.ptr != &*range.end()) {
throw std::invalid_argument(
"adc_from_chars: 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)");
} 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)");
}
} else if (std::is_constructible_v<ValueT, std::ranges::iterator_t<R>, std::ranges::iterator_t<R>>) {
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)");
}
}
/* TRIVIAL SERIALIZER/DESERIALIZER */
static const std::regex AdcIntegerRegex("^ *[+-]?\\d+\\d* *$", std::regex::ECMAScript);
static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript);
template <typename VT, typename SerializedT = std::string>
static SerializedT AdcTrivialSerializer(VT&& value)
{
using v_t = std::decay_t<VT>;
if constexpr (std::is_convertible_v<v_t, SerializedT>) {
return static_cast<SerializedT>(std::forward<VT>(value));
} else if (std::is_convertible_v<std::string, SerializedT>) {
return static_cast<SerializedT>(std::to_string(std::forward<VT>(value)));
} else if (traits::adc_char_range<SerializedT>) {
auto s = std::to_string(std::forward<VT>(value));
return SerializedT(s.begin(), s.end());
} else {
// throw std::invalid_argument("trivial serializer: cannot serialize value");
static_assert(false, "TRIVIAL SERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!");
}
}
template <typename VT, typename SerializedT = std::string>
static VT AdcTrivialDeserializer(SerializedT&& s_value)
{
static_assert(std::is_convertible_v<SerializedT, std::string> || traits::adc_char_range<SerializedT>,
"TRIVIAL DESERIALIZER: UNSUPPORTED TYPE OF SERIALIZED VALUE!!!");
if constexpr (std::is_arithmetic_v<VT>) {
if constexpr (traits::adc_char_range<SerializedT>) {
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<SerializedT>(s_value));
}
if (std::regex_match(s_value, AdcRealRegex)) { // floating-point value
return std::stod(std::forward<SerializedT>(s_value));
}
}
throw std::invalid_argument("trivial deserializer: unsupported serialized value");
} else if (std::is_convertible_v<SerializedT, VT>) {
return static_cast<VT>(std::forward<SerializedT>(s_value));
} else if (std::is_convertible_v<std::string, VT>) { // SerializedT is char range
return static_cast<VT>(s_v(s_value.begin(), s_value.end()));
}
throw std::invalid_argument("trivial deserializer: unsupported serialized value");
}
template <std::ranges::range OutputR, traits::adc_char_range InputR, traits::adc_char_range DelimR>
OutputR AdcRangeFromCharRange(InputR&& input_r, DelimR&& delim_r, size_t max_len = std::numeric_limits<size_t>::max())
{
OutputR out_r;
}
} // namespace adc::utils