221#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
224 : std::false_type {};
227template <auto V,
typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>,
int> = 0>
230template <
typename... T>
233template <
typename T,
typename =
void>
237struct has_is_flags<T, std::void_t<decltype(customize::enum_range<T>::is_flags)>> : std::bool_constant<std::is_same_v<bool, std::decay_t<decltype(customize::enum_range<T>::is_flags)>>> {};
239template <
typename T,
typename =
void>
240struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
243struct range_min<T, std::void_t<decltype(customize::enum_range<T>::min)>> : std::integral_constant<decltype(customize::enum_range<T>::min), customize::enum_range<T>::min> {};
245template <
typename T,
typename =
void>
246struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
249struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};
256template <std::u
int16_t N>
269 constexpr std::uint16_t
size() const noexcept {
return N; }
271 constexpr operator string_view() const noexcept {
return {
data(),
size()}; }
274 template <std::uint16_t... I>
277 template <std::uint16_t... I>
278 constexpr static_str(string_view str, std::integer_sequence<std::uint16_t, I...>) noexcept :
chars_{str[I]...,
static_cast<char_type>(
'\0')} {}
294 constexpr std::uint16_t
size() const noexcept {
return 0; }
296 constexpr operator string_view() const noexcept {
return {}; }
299template <
typename Op = std::equal_to<>>
306 template <
typename L,
typename R>
307 constexpr auto operator()(L lhs, R rhs)
const noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<L>,
char_type> && std::is_same_v<std::decay_t<R>,
char_type>,
bool> {
313#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
316 constexpr bool workaround =
true;
318 constexpr bool workaround =
false;
321 if constexpr (workaround) {
322 for (std::size_t i = 0; i < str.size(); ++i) {
328 return string_view::npos;
334template <
typename BinaryPredicate>
336 return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
337 std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
340template <
typename BinaryPredicate>
342 return is_default_predicate<BinaryPredicate>() ||
343 std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
346template <
typename BinaryPredicate>
347constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p)
noexcept(is_nothrow_invocable<BinaryPredicate>()) {
348#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
351 constexpr bool workaround =
true;
353 constexpr bool workaround =
false;
356 if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {
357 if (lhs.size() != rhs.size()) {
361 const auto size = lhs.size();
362 for (std::size_t i = 0; i < size; ++i) {
363 if (!p(lhs[i], rhs[i])) {
374template <
typename L,
typename R>
376 static_assert(std::is_integral_v<L> && std::is_integral_v<R>,
"magic_enum::detail::cmp_less requires integral type.");
378 if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
381 }
else if constexpr (std::is_same_v<L, bool>) {
382 return static_cast<R
>(lhs) < rhs;
383 }
else if constexpr (std::is_same_v<R, bool>) {
384 return lhs < static_cast<L>(rhs);
385 }
else if constexpr (std::is_signed_v<R>) {
387 return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);
390 return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;
396 static_assert(std::is_integral_v<I>,
"magic_enum::detail::log2 requires integral type.");
398 if constexpr (std::is_same_v<I, bool>) {
402 for (;
value > I{1};
value >>= I{1}, ++ret) {}
408#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
409# define MAGIC_ENUM_ARRAY_CONSTEXPR 1
411template <
typename T, std::size_t N, std::size_t... I>
412constexpr std::array<std::remove_cv_t<T>, N>
to_array(T (&a)[N], std::index_sequence<I...>)
noexcept {
418inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
421constexpr auto n() noexcept {
422 static_assert(is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
425#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
426 constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
427 constexpr auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} :
str_view{};
428#elif defined(__clang__)
430 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
431 static_assert(always_false_v<E>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
434 name.
size_ =
sizeof(__PRETTY_FUNCTION__) - 36;
435 name.
str_ = __PRETTY_FUNCTION__ + 34;
437#elif defined(__GNUC__)
438 auto name =
str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
439 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
440 static_assert(always_false_v<E>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
442 }
else if (name.
str_[name.
size_ - 1] ==
']') {
449#elif defined(_MSC_VER)
452 name.
str_ = __FUNCSIG__;
454 name.
size_ +=
sizeof(__FUNCSIG__) - 57;
459 for (std::size_t i = name.
size_; i > 0; --i) {
460 if (name.
str_[i] ==
':') {
477 [[maybe_unused]]
constexpr auto custom = customize::enum_type_name<E>();
478 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
480 constexpr auto name = custom.second;
481 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
486 constexpr auto name = n<E>();
489 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
497constexpr auto n() noexcept {
498 static_assert(
is_enum_v<
decltype(V)>,
"magic_enum::detail::n requires enum type.");
501#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
502 constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
503 auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
504#elif defined(__clang__)
506 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
507 static_assert(
always_false_v<
decltype(V)>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
510 name.
size_ =
sizeof(__PRETTY_FUNCTION__) - 36;
511 name.str_ = __PRETTY_FUNCTION__ + 34;
513 if (name.size_ > 22 && name.str_[0] ==
'(' && name.str_[1] ==
'a' && name.str_[10] ==
' ' && name.str_[22] ==
':') {
517 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
520#elif defined(__GNUC__)
521 auto name = str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
522 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
523 static_assert(
always_false_v<
decltype(V)>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
525 }
else if (name.str_[name.size_ - 1] ==
']') {
532 if (name.str_[0] ==
'(') {
535#elif defined(_MSC_VER)
537 if ((__FUNCSIG__[5] ==
'_' && __FUNCSIG__[35] !=
'(') || (__FUNCSIG__[5] ==
'c' && __FUNCSIG__[41] !=
'(')) {
539 name.str_ = __FUNCSIG__;
541 name.size_ =
sizeof(__FUNCSIG__) - 52;
544 auto name = str_view{};
547 for (std::size_t i = name.size_; i > 0; --i) {
548 if (name.str_[i] ==
':') {
563#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
564# define MAGIC_ENUM_VS_2017_WORKAROUND 1
567#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
568template <
typename E, E V>
569constexpr auto n() noexcept {
570 static_assert(is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
572# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
573 constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
574 auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
578 name.str_ = __FUNCSIG__;
579 name.size_ =
sizeof(__FUNCSIG__) - 17;
581 for (std::size_t i = name.size_; i > 0; --i) {
582 if (name.str_[i] ==
',' || name.str_[i] ==
':') {
591 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
599template <
typename E, E V>
601 [[maybe_unused]]
constexpr auto custom = customize::enum_name<E>(V);
602 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
604 constexpr auto name = custom.second;
605 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
610#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
611 constexpr auto name = n<E, V>();
613 constexpr auto name = n<V>();
617 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
621template <
typename E, E V>
624template <
typename E, auto V>
626#if defined(__clang__) && __clang_major__ >= 16
628 constexpr E v = __builtin_bit_cast(E, V);
630 constexpr E v =
static_cast<E
>(V);
632 [[maybe_unused]]
constexpr auto custom = customize::enum_name<E>(v);
633 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
635 constexpr auto name = custom.second;
636 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
637 return name.size() != 0;
639#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
640 return n<E, v>().size_ != 0;
642 return n<v>().size_ != 0;
654template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
655constexpr U
ualue(std::size_t i)
noexcept {
656 if constexpr (std::is_same_v<U, bool>) {
657 static_assert(O == 0,
"magic_enum::detail::ualue requires valid offset.");
659 return static_cast<U
>(i);
661 return static_cast<U
>(U{1} <<
static_cast<U
>(
static_cast<int>(i) + O));
663 return static_cast<U
>(
static_cast<int>(i) + O);
667template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
668constexpr E
value(std::size_t i)
noexcept {
669 return static_cast<E
>(ualue<E, O, S>(i));
672template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
678 constexpr auto rhs = (std::numeric_limits<U>::min)();
688template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
691 return std::numeric_limits<U>::digits - 1;
694 constexpr auto rhs = (std::numeric_limits<U>::max)();
704#define MAGIC_ENUM_FOR_EACH_256(T) \
705 T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \
706 T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \
707 T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \
708 T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \
709 T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \
710 T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \
711 T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \
712 T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255)
714template <
typename E, enum_subtype S, std::
size_t Size,
int Min, std::
size_t I>
715constexpr void valid_count(
bool* valid, std::size_t& count)
noexcept {
716#define MAGIC_ENUM_V(O) \
717 if constexpr ((I + O) < Size) { \
718 if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
719 valid[I + O] = true; \
726 if constexpr ((I + 256) < Size) {
727 valid_count<E, S, Size, Min, I + 256>(valid, count);
732template <std::
size_t N>
738template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
741 valid_count<E, S, Size, Min, 0>(vc.
valid, vc.
count);
745template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
747 constexpr auto vc = valid_count<E, S, Size, Min>();
749 if constexpr (vc.count > 0) {
750#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
751 std::array<E, vc.count>
values = {};
755 for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
757 values[v++] = value<E, Min, S>(i);
760#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
766 return std::array<E, 0>{};
770template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
772 constexpr auto min = reflected_min<E, S>();
773 constexpr auto max = reflected_max<E, S>();
774 constexpr auto range_size = max - min + 1;
775 static_assert(range_size > 0,
"magic_enum::enum_range requires valid size.");
777 return values<E, S, range_size, min>();
780template <
typename E,
typename U = std::underlying_type_t<E>>
782 if constexpr (std::is_same_v<U, bool>) {
787#if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
788 constexpr auto flags_values = values<E, enum_subtype::flags>();
789 constexpr auto default_values = values<E, enum_subtype::common>();
790 if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
793 for (std::size_t i = 0; i < default_values.size(); ++i) {
794 const auto v =
static_cast<U
>(default_values[i]);
795 if (v != 0 && (v & (v - 1)) != 0) {
812template <
typename E,
typename D = std::decay_t<E>>
813inline constexpr auto subtype_v = subtype<D>(std::is_enum<D>{});
815template <
typename E, enum_subtype S>
818template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
821template <
typename E, enum_subtype S>
822inline constexpr auto count_v = values_v<E, S>.size();
824template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
825inline constexpr auto min_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.front()) : U{0};
827template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
828inline constexpr auto max_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.back()) : U{0};
831constexpr auto names(std::index_sequence<I...>)
noexcept {
832 constexpr auto names = std::array<string_view,
sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
836template <
typename E, enum_subtype S>
837inline constexpr auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
839template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
843constexpr auto entries(std::index_sequence<I...>)
noexcept {
844 constexpr auto entries = std::array<std::pair<E, string_view>,
sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
848template <
typename E, enum_subtype S>
849inline constexpr auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
851template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
854template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
856 if constexpr (count_v<E, S> == 0) {
858 }
else if constexpr (std::is_same_v<U, bool>) {
863 constexpr auto range_size = max - min + 1;
865 return range_size != count_v<E, S>;
869template <
typename E, enum_subtype S = subtype_v<E>>
872template <
typename E, enum_subtype S>
874#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
877 : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
880template <
typename E, enum_subtype S>
883template <
bool,
typename R>
889 static_assert(
supported<R>::value,
"magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
892template <
typename T,
typename R,
typename BinaryPredicate = std::equal_to<>,
typename D = std::decay_t<T>>
895template <
typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>,
int> = 0>
898template <
typename T,
bool = std::is_enum_v<T>>
902struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
904template <
typename T,
bool = std::is_enum_v<T>>
908struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
910template <
typename T,
bool = std::is_enum_v<std::decay_t<T>>>
916#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
918template <
typename Value,
typename =
void>
919struct constexpr_hash_t;
921template <
typename Value>
922struct constexpr_hash_t<Value, std::
enable_if_t<is_enum_v<Value>>> {
923 constexpr auto operator()(Value value)
const noexcept {
925 if constexpr (std::is_same_v<U, bool>) {
926 return static_cast<std::size_t
>(
value);
928 return static_cast<U
>(value);
931 using secondary_hash = constexpr_hash_t;
934template <
typename Value>
935struct constexpr_hash_t<Value, std::
enable_if_t<std::is_same_v<Value, string_view>>> {
936 static constexpr std::uint32_t crc_table[256] {
937 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
938 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
939 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
940 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
941 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
942 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
943 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
944 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
945 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
946 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
947 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
948 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
949 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
950 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
951 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
952 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
953 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
954 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
955 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
956 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
957 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
958 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
959 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
960 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
961 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
962 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
963 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
964 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
965 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
966 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
967 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
968 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
970 constexpr std::uint32_t operator()(string_view value)
const noexcept {
971 auto crc =
static_cast<std::uint32_t
>(0xffffffffL);
972 for (
const auto c :
value) {
973 crc = (crc >> 8) ^ crc_table[(crc ^
static_cast<std::uint32_t
>(c)) & 0xff];
975 return crc ^ 0xffffffffL;
978 struct secondary_hash {
979 constexpr std::uint32_t operator()(string_view value)
const noexcept {
980 auto acc =
static_cast<std::uint64_t
>(2166136261ULL);
981 for (
const auto c :
value) {
982 acc = ((acc ^
static_cast<std::uint64_t
>(c)) *
static_cast<std::uint64_t
>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
984 return static_cast<std::uint32_t
>(acc);
989template <
typename Hash>
990inline constexpr Hash hash_v{};
992template <auto* GlobValues,
typename Hash>
993constexpr auto calculate_cases(std::size_t Page)
noexcept {
994 constexpr std::array
values = *GlobValues;
995 constexpr std::size_t size =
values.size();
997 using switch_t = std::invoke_result_t<Hash,
typename decltype(
values)::value_type>;
998 static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
999 const std::size_t values_to = (std::min)(
static_cast<std::size_t
>(256), size - Page);
1001 std::array<switch_t, 256> result{};
1002 auto fill = result.begin();
1004 auto first =
values.begin() +
static_cast<std::ptrdiff_t
>(Page);
1005 auto last =
values.begin() +
static_cast<std::ptrdiff_t
>(Page + values_to);
1006 while (first != last) {
1007 *fill++ = hash_v<Hash>(*first++);
1012 for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1016 auto it = result.begin();
1017 auto last_value = (std::numeric_limits<switch_t>::min)();
1018 for (; fill != result.end(); *fill++ = last_value++) {
1019 while (last_value == *it) {
1028template <
typename R,
typename F,
typename... Args>
1029constexpr R invoke_r(F&& f, Args&&... args)
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
1030 if constexpr (std::is_void_v<R>) {
1031 std::forward<F>(f)(std::forward<Args>(args)...);
1033 return static_cast<R
>(std::forward<F>(f)(std::forward<Args>(args)...));
1037enum class case_call_t {
1042template <
typename T =
void>
1043inline constexpr auto default_result_type_lambda = []()
noexcept(std::is_nothrow_default_constructible_v<T>) {
return T{}; };
1046inline constexpr auto default_result_type_lambda<void> = []()
noexcept {};
1048template <auto* Arr,
typename Hash>
1049constexpr bool has_duplicate() noexcept {
1050 using value_t = std::decay_t<
decltype((*Arr)[0])>;
1051 using hash_value_t = std::invoke_result_t<Hash, value_t>;
1052 std::array<hash_value_t, Arr->size()> hashes{};
1053 std::size_t size = 0;
1054 for (
auto elem : *Arr) {
1055 hashes[size] = hash_v<Hash>(elem);
1056 for (
auto i = size++; i > 0; --i) {
1057 if (hashes[i] < hashes[i - 1]) {
1058 auto tmp = hashes[i];
1059 hashes[i] = hashes[i - 1];
1060 hashes[i - 1] = tmp;
1061 }
else if (hashes[i] == hashes[i - 1]) {
1071#define MAGIC_ENUM_CASE(val) \
1073 if constexpr ((val) + Page < size) { \
1074 if (!pred(values[val + Page], searched)) { \
1077 if constexpr (CallValue == case_call_t::index) { \
1078 if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1079 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1080 } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1081 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1083 } else if constexpr (CallValue == case_call_t::value) { \
1084 if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1085 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1086 } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1087 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1091 } else [[fallthrough]];
1093template <
auto* GlobValues,
1094 case_call_t CallValue,
1095 std::size_t Page = 0,
1096 typename Hash = constexpr_hash_t<
typename std::decay_t<
decltype(*GlobValues)>::value_type>,
1097 typename BinaryPredicate = std::equal_to<>,
1099 typename ResultGetterType>
1100constexpr decltype(
auto) constexpr_switch(
1102 typename std::decay_t<
decltype(*GlobValues)>::value_type searched,
1103 ResultGetterType&& def,
1104 BinaryPredicate&& pred = {}) {
1105 using result_t = std::invoke_result_t<ResultGetterType>;
1106 using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash,
typename Hash::secondary_hash>;
1107 static_assert(has_duplicate<GlobValues, hash_t>(),
"magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues.");
1108 constexpr std::array
values = *GlobValues;
1109 constexpr std::size_t size =
values.size();
1110 constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1112 switch (hash_v<hash_t>(searched)) {
1115 if constexpr (size > 256 + Page) {
1116 return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1123#undef MAGIC_ENUM_CASE