...
This commit is contained in:
parent
41a9c70e70
commit
fa0cfea8fe
@ -3,6 +3,7 @@
|
|||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -15,9 +16,17 @@
|
|||||||
namespace adc::traits
|
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<typename T>
|
||||||
|
concept formattable = requires (T& v, std::format_context ctx) {
|
||||||
|
std::formatter<std::remove_cvref_t<T>>().format(v, ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// range of char/const char
|
// range of char/const char
|
||||||
template <typename R>
|
template <typename R, typename CharT = char>
|
||||||
concept adc_char_range = std::ranges::range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, char>;
|
concept adc_char_range = std::ranges::range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, CharT>;
|
||||||
|
|
||||||
// deduce returned type of callable
|
// deduce returned type of callable
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@ -12,15 +12,15 @@
|
|||||||
namespace adc::utils
|
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; });
|
return std::ranges::any_of(ws, [in](auto p) { return p == in; });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <traits::adc_char_range R>
|
template <traits::adc_char_range R>
|
||||||
auto AdcTrimSpaces(R&& r)
|
static auto AdcTrimSpaces(R&& r)
|
||||||
{
|
{
|
||||||
return r | std::views::drop_while(AdcIsSpace) | std::views::reverse | std::views::drop_while(AdcIsSpace) |
|
return r | std::views::drop_while(AdcIsSpace) | std::views::reverse | std::views::drop_while(AdcIsSpace) |
|
||||||
std::views::reverse;
|
std::views::reverse;
|
||||||
@ -28,32 +28,44 @@ auto AdcTrimSpaces(R&& r)
|
|||||||
|
|
||||||
|
|
||||||
template <typename ValueT, traits::adc_char_range R>
|
template <typename ValueT, traits::adc_char_range R>
|
||||||
ValueT AdcFromChars(R&& range)
|
static ValueT AdcFromChars(R&& range)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_arithmetic_v<ValueT>) {
|
if constexpr (std::is_arithmetic_v<ValueT>) {
|
||||||
ValueT 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<R>) {
|
||||||
|
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.ec == std::errc()) {
|
||||||
if (res.ptr != &*range.end()) {
|
if (res.ptr != end_ptr) {
|
||||||
throw std::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)");
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
} else if (res.ec == std::errc::invalid_argument) {
|
} else if (res.ec == std::errc::invalid_argument) {
|
||||||
throw std::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) {
|
} else if (res.ec == std::errc::result_out_of_range) {
|
||||||
throw std::invalid_argument(
|
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<ValueT, std::ranges::iterator_t<R>, std::ranges::iterator_t<R>>) {
|
} else if (std::is_constructible_v<ValueT, std::ranges::iterator_t<R>, std::ranges::iterator_t<R>>) {
|
||||||
return ValueT(range.begin(), range.end());
|
return ValueT(range.begin(), range.end());
|
||||||
} else {
|
} else {
|
||||||
throw std::invalid_argument(
|
static_assert(false, "AdcFromChars: CANNOT CONVERT CHAR-RANGE TO USER-TYPE VALUE (UNSUPPORTED USER-VALUE TYPE)");
|
||||||
"adc_from_chars: 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 AdcIntegerRegex("^ *[+-]?\\d+\\d* *$", std::regex::ECMAScript);
|
||||||
static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript);
|
static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript);
|
||||||
|
|
||||||
template <typename VT, typename SerializedT = std::string>
|
template <traits::formattable VT, typename SerializedT = std::string>
|
||||||
static SerializedT AdcTrivialSerializer(VT&& value)
|
static SerializedT AdcTrivialSerializer(VT&& value)
|
||||||
{
|
{
|
||||||
using v_t = std::decay_t<VT>;
|
using v_t = std::decay_t<VT>;
|
||||||
|
|
||||||
if constexpr (std::is_convertible_v<v_t, SerializedT>) {
|
if constexpr (std::is_convertible_v<v_t, SerializedT>) {
|
||||||
return static_cast<SerializedT>(std::forward<VT>(value));
|
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>) {
|
} else if (traits::adc_char_range<SerializedT>) {
|
||||||
auto s = std::to_string(std::forward<VT>(value));
|
SerializedT s_val;
|
||||||
return SerializedT(s.begin(), s.end());
|
std::format_to(std::back_inserter(s_val), "{}", std::forward<VT>(value));
|
||||||
|
return s_val;
|
||||||
} else {
|
} else {
|
||||||
// throw std::invalid_argument("trivial serializer: cannot serialize value");
|
// throw std::invalid_argument("trivial serializer: cannot serialize value");
|
||||||
static_assert(false, "TRIVIAL SERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!");
|
static_assert(false, "TRIVIAL SERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!");
|
||||||
@ -85,45 +96,33 @@ static SerializedT AdcTrivialSerializer(VT&& value)
|
|||||||
template <typename VT, typename SerializedT = std::string>
|
template <typename VT, typename SerializedT = std::string>
|
||||||
static VT AdcTrivialDeserializer(SerializedT&& s_value)
|
static VT AdcTrivialDeserializer(SerializedT&& s_value)
|
||||||
{
|
{
|
||||||
static_assert(std::is_convertible_v<SerializedT, std::string> || traits::adc_char_range<SerializedT>,
|
return AdcFromChars<VT>(std::forward<SerializedT>(s_value));
|
||||||
"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>
|
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 AdcRangeFromCharRange(InputR&& input_r, DelimR&& delim, size_t max_len = std::numeric_limits<size_t>::max())
|
||||||
{
|
{
|
||||||
OutputR out_r;
|
OutputR res;
|
||||||
|
|
||||||
|
if (max_len == 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
using value_t = std::ranges::range_value_t<OutputR>;
|
||||||
|
|
||||||
|
if constexpr (std::is_array_v<std::remove_cvref_t<DelimR>>) {
|
||||||
|
std::ranges::copy(std::views::split(std::forward<InputR>(input_r), std::string_view(delim)) |
|
||||||
|
std::views::filter([](const auto& r) { return !std::ranges::empty(r); }) |
|
||||||
|
std::views::transform([](auto vl) { return convFunc<value_t>(vl); }) | std::views::take(max_len),
|
||||||
|
std::back_inserter(res));
|
||||||
|
} else {
|
||||||
|
std::ranges::copy(std::views::split(std::forward<InputR>(input_r), std::forward<DelimR>(delim)) |
|
||||||
|
std::views::filter([](const auto& r) { return !std::ranges::empty(r); }) |
|
||||||
|
std::views::transform([](auto vl) { return convFunc<value_t>(vl); }) | std::views::take(max_len),
|
||||||
|
std::back_inserter(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace adc::utils
|
} // namespace adc::utils
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user