diff --git a/include/iris/x4/numeric/bool.hpp b/include/iris/x4/numeric/bool.hpp index 07261a751..26c1a13cc 100644 --- a/include/iris/x4/numeric/bool.hpp +++ b/include/iris/x4/numeric/bool.hpp @@ -16,6 +16,7 @@ #include #include +#include #include @@ -27,23 +28,6 @@ namespace iris::x4 { -template -struct bool_token; - -template<> -struct bool_token -{ - static constexpr auto true_ = "true"; - static constexpr auto false_ = "false"; -}; - -template<> -struct bool_token -{ - static constexpr auto true_ = U"true"; - static constexpr auto false_ = U"false"; -}; - // Default boolean policies template struct bool_policies @@ -53,8 +37,8 @@ struct bool_policies parse_true(It& first, Se const& last, Attr& attr_, CaseCompare const& compare) noexcept(noexcept(x4::move_to(T(true), attr_))) { - using CharT = std::remove_const_t>; - if (detail::string_parse(std::basic_string_view{bool_token::true_}, first, last, unused_container, compare)) { + using token_def = traits::numeric_token>; + if (detail::string_parse(std::basic_string_view{token_def::true_}, first, last, unused_container, compare)) { x4::move_to(T(true), attr_); return true; } @@ -66,8 +50,8 @@ struct bool_policies parse_false(It& first, Se const& last, Attr& attr_, CaseCompare const& compare) noexcept(noexcept(x4::move_to(T(false), attr_))) { - using CharT = std::remove_const_t>; - if (detail::string_parse(std::basic_string_view{bool_token::false_}, first, last, unused_container, compare)) { + using token_def = traits::numeric_token>; + if (detail::string_parse(std::basic_string_view{token_def::false_}, first, last, unused_container, compare)) { x4::move_to(T(false), attr_); return true; } diff --git a/include/iris/x4/numeric/real.hpp b/include/iris/x4/numeric/real.hpp index 20b785ca7..26c58f45a 100644 --- a/include/iris/x4/numeric/real.hpp +++ b/include/iris/x4/numeric/real.hpp @@ -16,11 +16,11 @@ #include #include +#include #include #include -#include #include #include #include @@ -58,7 +58,8 @@ struct ureal_policies parse_dot(It& first, Se const& last) noexcept(noexcept(*first) && noexcept(++first)) { - if (first == last || *first != '.') { + using CharT = std::iter_value_t; + if (first == last || *first != traits::numeric_token::dot) { return false; } ++first; @@ -78,7 +79,8 @@ struct ureal_policies parse_exp(It& first, Se const& last) noexcept(noexcept(*first) && noexcept(++first)) { - if (first == last || (*first != 'e' && *first != 'E')) { + using token_def = traits::numeric_token>; + if (first == last || (*first != token_def::e && *first != token_def::E)) { return false; } ++first; @@ -109,21 +111,23 @@ struct ureal_policies [[nodiscard]] static constexpr bool parse_nan(It& first, Se const& last, Attr& attr_) { - using namespace std::string_view_literals; + using token_def = traits::numeric_token>; - if (first == last) return false; // end of input reached - if (*first != 'n' && *first != 'N') return false; // not "nan" + if (first == last) return false; // end of input reached + if (*first != token_def::n && *first != token_def::N) { + return false; // not "nan" + } // nan[(...)] ? - if (detail::string_parse("nan"sv, "NAN"sv, first, last, unused_container)) { - if (first != last && *first == '(') { + if (detail::string_parse(token_def::nan, token_def::NAN_, first, last, unused_container)) { + if (first != last && *first == token_def::lparen) { // skip trailing (...) part It i = first; - while (++i != last && *i != ')') + while (++i != last && *i != token_def::rparen) /* loop */; - if (i == last) return false; // no trailing ')' found, give up + if (i == last) return false; // no trailing ')' found, give up first = ++i; } @@ -137,15 +141,15 @@ struct ureal_policies [[nodiscard]] static constexpr bool parse_inf(It& first, Se const& last, Attr& attr_) { - using namespace std::string_view_literals; + using token_def = traits::numeric_token>; if (first == last) return false; // end of input reached - if (*first != 'i' && *first != 'I') return false; // not "inf" + if (*first != token_def::i && *first != token_def::I) return false; // not "inf" // inf or infinity ? - if (detail::string_parse("inf"sv, "INF"sv, first, last, unused_container)) { + if (detail::string_parse(token_def::inf, token_def::INF, first, last, unused_container)) { // skip allowed 'inity' part of infinity - (void)detail::string_parse("inity"sv, "INITY"sv, first, last, unused_container); + (void)detail::string_parse(token_def::inity, token_def::INITY, first, last, unused_container); attr_ = std::numeric_limits::infinity(); return true; } diff --git a/include/iris/x4/numeric/utils/extract_int.hpp b/include/iris/x4/numeric/utils/extract_int.hpp index 9520d7ddb..57eba19d7 100644 --- a/include/iris/x4/numeric/utils/extract_int.hpp +++ b/include/iris/x4/numeric/utils/extract_int.hpp @@ -98,21 +98,23 @@ struct digits_traits template struct radix_traits { - template - [[nodiscard]] static constexpr bool is_valid(Char ch) noexcept + template + [[nodiscard]] static constexpr bool is_valid(CharT ch) noexcept { - return (ch >= '0' && ch <= (Radix > 10 ? '9' : static_cast('0' + Radix -1))) - || (Radix > 10 && ch >= 'a' && ch <= static_cast('a' + Radix -10 -1)) - || (Radix > 10 && ch >= 'A' && ch <= static_cast('A' + Radix -10 -1)); + using token_def = traits::numeric_token; + return (ch >= token_def::_0 && ch <= (Radix > 10 ? token_def::_9 : static_cast(token_def::_0 + Radix -1))) + || (Radix > 10 && ch >= token_def::a && ch <= static_cast(token_def::a + Radix -10 -1)) + || (Radix > 10 && ch >= token_def::A && ch <= static_cast(token_def::A + Radix -10 -1)); } - template - [[nodiscard]] static constexpr unsigned digit(Char ch) - noexcept(noexcept(traits::char_encoding_traits::encoding_type::tolower(ch))) + template + [[nodiscard]] static constexpr unsigned digit(CharT ch) + noexcept(noexcept(traits::char_encoding_traits::encoding_type::tolower(ch))) { - return (Radix <= 10 || (ch >= '0' && ch <= '9')) - ? ch - '0' - : traits::char_encoding_traits::encoding_type::tolower(ch) - 'a' + 10; + using token_def = traits::numeric_token; + return (Radix <= 10 || (ch >= token_def::_0 && ch <= token_def::_9)) + ? ch - token_def::_0 + : traits::char_encoding_traits::encoding_type::tolower(ch) - token_def::a + 10; } }; @@ -120,15 +122,15 @@ struct radix_traits template struct positive_accumulator { - template - static constexpr void unchecked_add(T& n, Char ch) + template + static constexpr void unchecked_add(T& n, CharT ch) noexcept(noexcept(radix_traits::digit(ch))) { n = n * T(Radix) + T(radix_traits::digit(ch)); } - template - [[nodiscard]] static constexpr bool checked_add(T& n, Char ch) + template + [[nodiscard]] static constexpr bool checked_add(T& n, CharT ch) noexcept(noexcept(radix_traits::digit(ch))) { // Ensure n *= Radix will not overflow @@ -151,15 +153,15 @@ struct positive_accumulator template struct negative_accumulator { - template - static constexpr void unchecked_add(T& n, Char ch) + template + static constexpr void unchecked_add(T& n, CharT ch) noexcept(noexcept(radix_traits::digit(ch))) { n = n * T(Radix) - T(radix_traits::digit(ch)); } - template - [[nodiscard]] static constexpr bool checked_add(T& n, Char ch) + template + [[nodiscard]] static constexpr bool checked_add(T& n, CharT ch) noexcept(noexcept(radix_traits::digit(ch))) { // Ensure n *= Radix will not underflow @@ -190,10 +192,10 @@ struct int_extractor ) && traits::check_overflow::value; - template + template requires need_check_overflow [[nodiscard]] static constexpr bool - call(Char ch, std::size_t count, T& n) + call(CharT ch, std::size_t count, T& n) noexcept( noexcept(Accumulator::unchecked_add(n, ch)) && noexcept(Accumulator::checked_add(n, ch)) @@ -211,19 +213,19 @@ struct int_extractor return true; } - template + template requires (!need_check_overflow) [[nodiscard]] static constexpr bool - call(Char ch, std::size_t /*count*/, T& n) + call(CharT ch, std::size_t /*count*/, T& n) noexcept(noexcept(Accumulator::unchecked_add(n, ch))) { Accumulator::unchecked_add(n, ch); return true; } - template + template [[nodiscard]] static constexpr bool - call(Char /*ch*/, std::size_t /*count*/, unused_type const&) noexcept + call(CharT /*ch*/, std::size_t /*count*/, unused_type const&) noexcept { return true; } @@ -274,11 +276,13 @@ struct extract_int using extractor = int_extractor; using char_type = std::iter_value_t; + using token_def = traits::numeric_token>; + It it = first; std::size_t leading_zeros = 0; if constexpr (!Accumulate) { // skip leading zeros - while (it != last && *it == '0' && leading_zeros < static_cast(MaxDigits)) { + while (it != last && *it == token_def::_0 && leading_zeros < static_cast(MaxDigits)) { ++it; ++leading_zeros; } @@ -359,11 +363,13 @@ struct extract_int using extractor = int_extractor; using char_type = std::iter_value_t; + using token_def = traits::numeric_token>; + It it = first; std::size_t count = 0; if constexpr (!Accumulate) { // skip leading zeros - while (it != last && *it == '0') { + while (it != last && *it == token_def::_0) { ++it; ++count; } @@ -443,12 +449,14 @@ extract_sign(It& first, Se const& last) noexcept(++first) ) { + using token_def = traits::numeric_token>; + (void)last; assert(first != last); // precondition // Extract the sign - bool const neg = *first == '-'; - if (neg || *first == '+') { + bool const neg = *first == token_def::minus; + if (neg || *first == token_def::plus) { ++first; return neg; } diff --git a/include/iris/x4/numeric/utils/extract_real.hpp b/include/iris/x4/numeric/utils/extract_real.hpp index e87b0b6fa..50c2f1c6a 100644 --- a/include/iris/x4/numeric/utils/extract_real.hpp +++ b/include/iris/x4/numeric/utils/extract_real.hpp @@ -140,7 +140,7 @@ struct extract_real // Start by parsing the sign. neg will be true if // we got a "-" sign, false otherwise. - bool neg = Policy::parse_sign(first, last); + bool const neg = Policy::parse_sign(first, last); // Now attempt to parse an integer T n = 0; diff --git a/include/iris/x4/string/detail/string_parse.hpp b/include/iris/x4/string/detail/string_parse.hpp index e985172c8..9f138c3ff 100644 --- a/include/iris/x4/string/detail/string_parse.hpp +++ b/include/iris/x4/string/detail/string_parse.hpp @@ -34,6 +34,7 @@ string_parse( static_assert(std::same_as, traits::container_attr>); using value_type = traits::container_value::type; static_assert(!CharLike || !CharIncompatibleWith, "Mixing incompatible char types is not allowed"); + static_assert(!CharIncompatibleWith, CharT>, "Mixing incompatible char types is not allowed"); It it = first; auto stri = str.begin(); @@ -81,6 +82,7 @@ string_parse( static_assert(std::same_as, traits::container_attr>); using value_type = traits::container_value::type; static_assert(!CharLike || !CharIncompatibleWith, "Mixing incompatible char types is not allowed"); + static_assert(!CharIncompatibleWith, CharT>, "Mixing incompatible char types is not allowed"); auto uc_it = ucstr.begin(); auto uc_last = ucstr.end(); diff --git a/include/iris/x4/traits/numeric_traits.hpp b/include/iris/x4/traits/numeric_traits.hpp index 3f624a160..141e081cc 100644 --- a/include/iris/x4/traits/numeric_traits.hpp +++ b/include/iris/x4/traits/numeric_traits.hpp @@ -10,6 +10,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ +#include #include #include @@ -17,6 +18,55 @@ namespace iris::x4::traits { // Customization points for numeric operations +template +struct numeric_token; + +#define IRIS_X4_DEF(CharT, XSTR) \ + template<> \ + struct numeric_token \ + { \ + inline static constexpr CharT a = XSTR('a'); \ + inline static constexpr CharT A = XSTR('A'); \ + inline static constexpr CharT e = XSTR('e'); \ + inline static constexpr CharT E = XSTR('E'); \ + inline static constexpr CharT n = XSTR('n'); \ + inline static constexpr CharT N = XSTR('N'); \ + inline static constexpr CharT i = XSTR('i'); \ + inline static constexpr CharT I = XSTR('I'); \ + \ + inline static constexpr CharT _0 = XSTR('0'); \ + inline static constexpr CharT _9 = XSTR('9'); \ + \ + inline static constexpr CharT minus = XSTR('-'); \ + inline static constexpr CharT plus = XSTR('+'); \ + inline static constexpr CharT dot = XSTR('.'); \ + inline static constexpr CharT lparen = XSTR('('); \ + inline static constexpr CharT rparen = XSTR(')'); \ + \ + inline static constexpr std::basic_string_view nan = XSTR("nan"); \ + inline static constexpr std::basic_string_view NAN_ = XSTR("NAN"); \ + inline static constexpr std::basic_string_view inf = XSTR("inf"); \ + inline static constexpr std::basic_string_view inity = XSTR("inity"); \ + inline static constexpr std::basic_string_view INF = XSTR("INF"); \ + inline static constexpr std::basic_string_view INITY = XSTR("INITY"); \ + \ + inline static constexpr std::basic_string_view true_ = XSTR("true"); \ + inline static constexpr std::basic_string_view false_ = XSTR("false"); \ + }; + +#define IRIS_X4_XSTR_char(str) str +IRIS_X4_DEF(char, IRIS_X4_XSTR_char) +#undef IRIS_X4_XSTR_char + +#ifdef IRIS_X4_UNICODE +# define IRIS_X4_XSTR_u32(str) U##str +IRIS_X4_DEF(char32_t, IRIS_X4_XSTR_u32) +# undef IRIS_X4_XSTR_u32 +#endif + +#undef IRIS_X4_DEF + + template struct pow10_helper;