#pragma once #include "type_traits.hpp" #include #include #include #include #include #include #include #ifndef SSP_DISABLE_FAST_FLOAT #include #else #include #include #endif namespace ss { //////////////// // number converters //////////////// #ifndef SSP_DISABLE_FAST_FLOAT template std::enable_if_t, std::optional> to_num( const char* const begin, const char* const end) { T ret; auto [ptr, ec] = fast_float::from_chars(begin, end, ret); if (ec != std::errc() || ptr != end) { return std::nullopt; } return ret; } #else template std::enable_if_t, std::optional> to_num( const char* const begin, const char* const end) { static_assert(!std::is_same_v, "Conversion to long double is disabled"); constexpr static auto buff_max = 64; char short_buff[buff_max]; size_t string_range = std::distance(begin, end); std::string long_buff; char* buff; if (string_range > buff_max) { long_buff = std::string{begin, end}; buff = long_buff.data(); } else { buff = short_buff; buff[string_range] = '\0'; std::copy_n(begin, string_range, buff); } T ret; char* parse_end = nullptr; if constexpr (std::is_same_v) { ret = std::strtof(buff, &parse_end); } else if constexpr (std::is_same_v) { ret = std::strtod(buff, &parse_end); } if (parse_end != buff + string_range) { return std::nullopt; } return ret; } #endif //////////////// // numeric_wrapper //////////////// template struct numeric_wrapper { using type = T; numeric_wrapper() = default; numeric_wrapper(numeric_wrapper&&) = default; numeric_wrapper(const numeric_wrapper&) = default; numeric_wrapper& operator=(numeric_wrapper&&) = default; numeric_wrapper& operator=(const numeric_wrapper&) = default; numeric_wrapper(T other) : value{other} { } operator T() { return value; } operator T() const { return value; } T value; }; using int8 = numeric_wrapper; using uint8 = numeric_wrapper; template std::enable_if_t, std::optional> to_num( const char* const begin, const char* const end) { T ret; auto [ptr, ec] = std::from_chars(begin, end, ret); if (ec != std::errc() || ptr != end) { return std::nullopt; } return ret; } template std::enable_if_t, std::optional> to_num( const char* const begin, const char* const end) { T ret; auto [ptr, ec] = std::from_chars(begin, end, ret.value); if (ec != std::errc() || ptr != end) { return std::nullopt; } return ret; } //////////////// // extract //////////////// namespace error { template struct unsupported_type { constexpr static bool value = false; }; } /* namespace */ template std::enable_if_t && !std::is_floating_point_v && !is_instance_of_v && !is_instance_of_v && !is_instance_of_v, bool> extract(const char*, const char*, T&) { static_assert(error::unsupported_type::value, "Conversion for given type is not defined, an " "\'extract\' function needs to be defined!"); } template std::enable_if_t || std::is_floating_point_v || is_instance_of_v, bool> extract(const char* begin, const char* end, T& value) { auto optional_value = to_num(begin, end); if (!optional_value) { return false; } value = optional_value.value(); return true; } template std::enable_if_t, bool> extract( const char* begin, const char* end, T& value) { typename T::value_type raw_value; if (extract(begin, end, raw_value)) { value = raw_value; } else { value = std::nullopt; } return true; } template bool extract_variant(const char* begin, const char* end, T& value) { using IthType = std::variant_alternative_t>; IthType ithValue; if (extract(begin, end, ithValue)) { value = ithValue; return true; } else if constexpr (I + 1 < std::variant_size_v) { return extract_variant(begin, end, value); } return false; } template std::enable_if_t, bool> extract( const char* begin, const char* end, T& value) { return extract_variant(begin, end, value); } //////////////// // extract specialization //////////////// template <> inline bool extract(const char* begin, const char* end, bool& value) { if (end == begin + 1) { if (*begin == '1') { value = true; } else if (*begin == '0') { value = false; } else { return false; } } else { size_t size = end - begin; if (size == 4 && std::strncmp(begin, "true", size) == 0) { value = true; } else if (size == 5 && std::strncmp(begin, "false", size) == 0) { value = false; } else { return false; } } return true; } template <> inline bool extract(const char* begin, const char* end, char& value) { value = *begin; return (end == begin + 1); } template <> inline bool extract(const char* begin, const char* end, std::string& value) { value = std::string{begin, end}; return true; } template <> inline bool extract(const char* begin, const char* end, std::string_view& value) { value = std::string_view{begin, static_cast(end - begin)}; return true; } } /* ss */