Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/stdx/tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ template <std::size_t I> constexpr static index_constant<I> index{};

inline namespace literals {
template <char... Chars> CONSTEVAL auto operator""_idx() {
return index<detail::decimal<std::size_t, Chars...>()>;
return index<parse_literal<std::size_t, Chars...>()>;
}
} // namespace literals

Expand Down
69 changes: 61 additions & 8 deletions include/stdx/udls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,75 @@ namespace stdx {
inline namespace v1 {

namespace detail {
template <typename T, char... Chars> CONSTEVAL auto decimal() -> T {
static_assert((... and (Chars >= '0' and Chars <= '9')),
"decimal numbers only are supported");
using U = decltype(stdx::to_underlying(std::declval<T>()));
auto x = U{};
((x *= 10, x += Chars - '0'), ...);
return T{x};
template <char C> constexpr static bool is_digit_sep_v = C == '\'';
template <char C>
constexpr static bool is_decimal_digit_v = C >= '0' and C <= '9';
template <char C>
constexpr static bool is_octal_digit_v = C >= '0' and C <= '7';
template <char C>
constexpr static bool is_binary_digit_v = C >= '0' and C <= '1';

template <char C>
constexpr static char force_lower_case = static_cast<unsigned char>(C) | 32u;
template <char C>
constexpr static bool is_hex_digit_v =
(C >= '0' and C <= '9') or
(force_lower_case<C> >= 'a' and force_lower_case<C> <= 'f');

template <char C>
constexpr static auto integral_value_v =
is_decimal_digit_v<C> ? C - '0' : force_lower_case<C> - 'a' + 10;

template <auto Base, char C, typename Sum>
CONSTEVAL auto maybe_add_digit(Sum s) {
if constexpr (not is_digit_sep_v<C>) {
s *= Base;
s += integral_value_v<C>;
}
return s;
}

template <auto Base, char... Cs> struct raw_parser {
template <typename T> CONSTEVAL static auto parse() {
using U = decltype(stdx::to_underlying(std::declval<T>()));
auto x = U{};
((x = maybe_add_digit<Base, Cs>(x)), ...);
return T{x};
}
};

template <char... Cs> struct parser : raw_parser<10, Cs...> {
static_assert((... and (is_decimal_digit_v<Cs> or is_digit_sep_v<Cs>)));
};

template <char... Cs> struct parser<'0', Cs...> : raw_parser<8, Cs...> {
static_assert((... and (is_octal_digit_v<Cs> or is_digit_sep_v<Cs>)));
};

template <char... Cs> struct parser<'0', 'x', Cs...> : raw_parser<16, Cs...> {
static_assert((... and (is_hex_digit_v<Cs> or is_digit_sep_v<Cs>)));
};
template <char... Cs>
struct parser<'0', 'X', Cs...> : parser<'0', 'x', Cs...> {};

template <char... Cs> struct parser<'0', 'b', Cs...> : raw_parser<2, Cs...> {
static_assert((... and (is_binary_digit_v<Cs> or is_digit_sep_v<Cs>)));
};
template <char... Cs>
struct parser<'0', 'B', Cs...> : parser<'0', 'b', Cs...> {};
} // namespace detail

template <typename T, char... Chars> CONSTEVAL auto parse_literal() -> T {
using parser_t = detail::parser<Chars...>;
return parser_t::template parse<T>();
}

template <auto I> using constant = std::integral_constant<decltype(I), I>;
template <auto I> constexpr static constant<I> _c{};

inline namespace literals {
template <char... Chars> CONSTEVAL auto operator""_c() {
return _c<detail::decimal<std::uint32_t, Chars...>()>;
return _c<parse_literal<std::uint32_t, Chars...>()>;
}
} // namespace literals

Expand Down
44 changes: 40 additions & 4 deletions test/udls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +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<decltype(_c<0>), std::integral_constant<int, 0> const>);
static_assert(std::is_same_v<decltype(stdx::_c<0>),
std::integral_constant<int, 0> const>);
static_assert(
std::is_same_v<decltype(_c<0u>),
std::is_same_v<decltype(stdx::_c<0u>),
std::integral_constant<unsigned int, 0> const>);
}

TEST_CASE("compile-time literal (decimal)", "[units]") {
using namespace stdx::literals;
static_assert(std::is_same_v<decltype(0_c),
std::integral_constant<std::uint32_t, 0>>);
}

TEST_CASE("compile-time literal supports digit separators", "[units]") {
using namespace stdx::literals;
static_assert(
std::is_same_v<decltype(123'456_c),
std::integral_constant<std::uint32_t, 123'456>>);
}

TEST_CASE("compile-time literal (octal)", "[units]") {
using namespace stdx::literals;
static_assert(std::is_same_v<decltype(010_c),
std::integral_constant<std::uint32_t, 8>>);
static_assert(std::is_same_v<decltype(0'10_c),
std::integral_constant<std::uint32_t, 8>>);
}

TEST_CASE("compile-time literal (binary)", "[units]") {
using namespace stdx::literals;
static_assert(std::is_same_v<decltype(0b11_c),
std::integral_constant<std::uint32_t, 3>>);
static_assert(std::is_same_v<decltype(0b1'1_c),
std::integral_constant<std::uint32_t, 3>>);
}

TEST_CASE("compile-time literal (hex)", "[units]") {
using namespace stdx::literals;
static_assert(std::is_same_v<decltype(0xaa_c),
std::integral_constant<std::uint32_t, 170>>);
static_assert(std::is_same_v<decltype(0xAA_c),
std::integral_constant<std::uint32_t, 170>>);
static_assert(std::is_same_v<decltype(0xA'a_c),
std::integral_constant<std::uint32_t, 170>>);
}

namespace {
enum UnscopedEnum { Value3 = 3 };
enum struct ScopedEnum : char { Value5 = 5 };
Expand Down