From f2d7d7d6e0323254a49a439e145a22a78df445ba Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 6 Nov 2024 10:23:27 -0700 Subject: [PATCH 1/2] :bug: Allow UDL to work with digit separators Problem: - The `_c` UDL doesn't deal with digit separators. Solution: - Fix it. --- include/stdx/udls.hpp | 20 +++++++++++++++++--- test/udls.cpp | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/stdx/udls.hpp b/include/stdx/udls.hpp index c4c76fb..0788281 100644 --- a/include/stdx/udls.hpp +++ b/include/stdx/udls.hpp @@ -11,12 +11,26 @@ namespace stdx { inline namespace v1 { namespace detail { +template +constexpr static bool is_decimal_digit_v = C >= '0' and C <= '9'; +template constexpr static bool is_digit_sep_v = C == '\''; + +template CONSTEVAL auto maybe_add_digit(Sum s) { + if constexpr (is_decimal_digit_v) { + s *= 10; + s += C - '0'; + } + return s; +} + template CONSTEVAL auto decimal() -> T { - static_assert((... and (Chars >= '0' and Chars <= '9')), - "decimal numbers only are supported"); + static_assert( + (... and (is_decimal_digit_v or is_digit_sep_v)), + "decimal numbers only are supported"); using U = decltype(stdx::to_underlying(std::declval())); + auto x = U{}; - ((x *= 10, x += Chars - '0'), ...); + ((x = maybe_add_digit(x)), ...); return T{x}; } } // namespace detail diff --git a/test/udls.cpp b/test/udls.cpp index a128488..e21aead 100644 --- a/test/udls.cpp +++ b/test/udls.cpp @@ -50,6 +50,9 @@ TEST_CASE("compile-time constant", "[units]") { std::integral_constant const>); static_assert(std::is_same_v>); + static_assert( + std::is_same_v>); } namespace { From 42d66a7c445aed96b063d06d1d01a4f1478dd963 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Fri, 8 Nov 2024 08:51:53 -0700 Subject: [PATCH 2/2] :sparkles: Allow `_c` UDL to work with hex, octal, binary literals --- include/stdx/tuple.hpp | 2 +- include/stdx/udls.hpp | 69 +++++++++++++++++++++++++++++++++--------- test/udls.cpp | 41 ++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/include/stdx/tuple.hpp b/include/stdx/tuple.hpp index 3303993..ec06b88 100644 --- a/include/stdx/tuple.hpp +++ b/include/stdx/tuple.hpp @@ -19,7 +19,7 @@ template constexpr static index_constant index{}; inline namespace literals { template CONSTEVAL auto operator""_idx() { - return index()>; + return index()>; } } // namespace literals diff --git a/include/stdx/udls.hpp b/include/stdx/udls.hpp index 0788281..11e673d 100644 --- a/include/stdx/udls.hpp +++ b/include/stdx/udls.hpp @@ -11,36 +11,75 @@ namespace stdx { inline namespace v1 { namespace detail { +template constexpr static bool is_digit_sep_v = C == '\''; template constexpr static bool is_decimal_digit_v = C >= '0' and C <= '9'; -template constexpr static bool is_digit_sep_v = C == '\''; +template +constexpr static bool is_octal_digit_v = C >= '0' and C <= '7'; +template +constexpr static bool is_binary_digit_v = C >= '0' and C <= '1'; -template CONSTEVAL auto maybe_add_digit(Sum s) { - if constexpr (is_decimal_digit_v) { - s *= 10; - s += C - '0'; +template +constexpr static char force_lower_case = static_cast(C) | 32u; +template +constexpr static bool is_hex_digit_v = + (C >= '0' and C <= '9') or + (force_lower_case >= 'a' and force_lower_case <= 'f'); + +template +constexpr static auto integral_value_v = + is_decimal_digit_v ? C - '0' : force_lower_case - 'a' + 10; + +template +CONSTEVAL auto maybe_add_digit(Sum s) { + if constexpr (not is_digit_sep_v) { + s *= Base; + s += integral_value_v; } return s; } -template CONSTEVAL auto decimal() -> T { - static_assert( - (... and (is_decimal_digit_v or is_digit_sep_v)), - "decimal numbers only are supported"); - using U = decltype(stdx::to_underlying(std::declval())); +template struct raw_parser { + template CONSTEVAL static auto parse() { + using U = decltype(stdx::to_underlying(std::declval())); + auto x = U{}; + ((x = maybe_add_digit(x)), ...); + return T{x}; + } +}; + +template struct parser : raw_parser<10, Cs...> { + static_assert((... and (is_decimal_digit_v or is_digit_sep_v))); +}; + +template struct parser<'0', Cs...> : raw_parser<8, Cs...> { + static_assert((... and (is_octal_digit_v or is_digit_sep_v))); +}; + +template struct parser<'0', 'x', Cs...> : raw_parser<16, Cs...> { + static_assert((... and (is_hex_digit_v or is_digit_sep_v))); +}; +template +struct parser<'0', 'X', Cs...> : parser<'0', 'x', Cs...> {}; + +template struct parser<'0', 'b', Cs...> : raw_parser<2, Cs...> { + static_assert((... and (is_binary_digit_v or is_digit_sep_v))); +}; +template +struct parser<'0', 'B', Cs...> : parser<'0', 'b', Cs...> {}; +} // namespace detail - auto x = U{}; - ((x = maybe_add_digit(x)), ...); - return T{x}; +template CONSTEVAL auto parse_literal() -> T { + using parser_t = detail::parser; + return parser_t::template parse(); } -} // namespace detail template using constant = std::integral_constant; template constexpr static constant _c{}; inline namespace literals { template CONSTEVAL auto operator""_c() { - return _c()>; + return _c()>; } } // namespace literals diff --git a/test/udls.cpp b/test/udls.cpp index e21aead..26609df 100644 --- a/test/udls.cpp +++ b/test/udls.cpp @@ -42,19 +42,52 @@ TEST_CASE("compile-time named small indices", "[units]") { } TEST_CASE("compile-time constant", "[units]") { - using namespace stdx; - static_assert( - std::is_same_v), std::integral_constant const>); + static_assert(std::is_same_v), + std::integral_constant const>); static_assert( - std::is_same_v), + std::is_same_v), std::integral_constant const>); +} + +TEST_CASE("compile-time literal (decimal)", "[units]") { + using namespace stdx::literals; static_assert(std::is_same_v>); +} + +TEST_CASE("compile-time literal supports digit separators", "[units]") { + using namespace stdx::literals; static_assert( std::is_same_v>); } +TEST_CASE("compile-time literal (octal)", "[units]") { + using namespace stdx::literals; + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); +} + +TEST_CASE("compile-time literal (binary)", "[units]") { + using namespace stdx::literals; + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); +} + +TEST_CASE("compile-time literal (hex)", "[units]") { + using namespace stdx::literals; + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); +} + namespace { enum UnscopedEnum { Value3 = 3 }; enum struct ScopedEnum : char { Value5 = 5 };