218#
if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
221 : std::false_type {};
224template <auto V,
typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>,
int> = 0>
227template <
typename...
T>
230template <
typename T,
typename =
void>
234struct 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)>>> {};
236template <
typename T,
typename =
void>
237struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
240struct 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> {};
242template <
typename T,
typename =
void>
243struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
246struct 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> {};
253template <std::u
int16_t N>
266 constexpr std::uint16_t
size() const noexcept {
return N; }
268 constexpr operator string_view() const noexcept {
return {
data(),
size()}; }
271 template <std::uint16_t... I>
272 constexpr static_str(
const char*
str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{
static_cast<char_type>(
str[I])...,
static_cast<char_type>(
'\0')} {}
274 template <std::uint16_t... I>
275 constexpr static_str(string_view
str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{
str[I]...,
static_cast<char_type>(
'\0')} {}
277 char_type chars_[
static_cast<std::size_t
>(N) + 1];
291 constexpr std::uint16_t
size() const noexcept {
return 0; }
293 constexpr operator string_view() const noexcept {
return {}; }
296template <
typename Op = std::equal_to<>>
303 template <
typename L,
typename R>
304 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> {
305 return Op{}(to_lower(lhs), to_lower(rhs));
310#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
313 constexpr bool workaround =
true;
315 constexpr bool workaround =
false;
318 if constexpr (workaround) {
319 for (std::size_t i = 0; i <
str.size(); ++i) {
325 return string_view::npos;
331template <
typename BinaryPredicate>
333 return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
334 std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
337template <
typename BinaryPredicate>
340 std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
343template <
typename BinaryPredicate>
345#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
348 constexpr bool workaround =
true;
350 constexpr bool workaround =
false;
354 if (lhs.size() != rhs.size()) {
358 const auto size = lhs.size();
359 for (std::size_t i = 0; i < size; ++i) {
360 if (!p(lhs[i], rhs[i])) {
371template <
typename L,
typename R>
373 static_assert(std::is_integral_v<L> && std::is_integral_v<R>,
"magic_enum::detail::cmp_less requires integral type.");
375 if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
378 }
else if constexpr (std::is_same_v<L, bool>) {
379 return static_cast<R
>(lhs) < rhs;
380 }
else if constexpr (std::is_same_v<R, bool>) {
381 return lhs < static_cast<L>(rhs);
382 }
else if constexpr (std::is_signed_v<R>) {
384 return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);
387 return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;
393 static_assert(std::is_integral_v<I>,
"magic_enum::detail::log2 requires integral type.");
395 if constexpr (std::is_same_v<I, bool>) {
399 for (;
value > I{1};
value >>= I{1}, ++ret) {}
405#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
406# define MAGIC_ENUM_ARRAY_CONSTEXPR 1
408template <
typename T, std::size_t N, std::size_t... I>
409constexpr std::array<std::remove_cv_t<T>, N>
to_array(
T (&a)[N], std::index_sequence<I...>)
noexcept {
415inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
418constexpr auto n() noexcept {
419 static_assert(
is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
422#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
423 constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
424 constexpr auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} :
str_view{};
425#elif defined(__clang__)
426 auto name =
str_view{__PRETTY_FUNCTION__ + 34,
sizeof(__PRETTY_FUNCTION__) - 36};
427#elif defined(__GNUC__)
428 auto name =
str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
429 if (name.str_[name.size_ - 1] ==
']') {
436#elif defined(_MSC_VER)
437 auto name =
str_view{__FUNCSIG__ + 40,
sizeof(__FUNCSIG__) - 57};
442 for (std::size_t i = name.size_; i > 0; --i) {
443 if (name.str_[i] ==
':') {
461 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
463 constexpr auto name = custom.second;
464 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
469 constexpr auto name =
n<E>();
480constexpr auto n() noexcept {
481 static_assert(
is_enum_v<
decltype(V)>,
"magic_enum::detail::n requires enum type.");
484#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
485 constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
486 auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
487#elif defined(__clang__)
488 auto name = str_view{__PRETTY_FUNCTION__ + 34,
sizeof(__PRETTY_FUNCTION__) - 36};
489 if (name.size_ > 22 && name.str_[0] ==
'(' && name.str_[1] ==
'a' && name.str_[10] ==
' ' && name.str_[22] ==
':') {
493 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
496#elif defined(__GNUC__)
497 auto name =
str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
498 if (name.str_[name.size_ - 1] ==
']') {
505 if (name.str_[0] ==
'(') {
508#elif defined(_MSC_VER)
510 if ((__FUNCSIG__[5] ==
'_' && __FUNCSIG__[35] !=
'(') || (__FUNCSIG__[5] ==
'c' && __FUNCSIG__[41] !=
'(')) {
511 name =
str_view{__FUNCSIG__ + 35,
sizeof(__FUNCSIG__) - 52};
517 for (std::size_t i = name.size_; i > 0; --i) {
518 if (name.str_[i] ==
':') {
533#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
534# define MAGIC_ENUM_VS_2017_WORKAROUND 1
537#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
538template <
typename E, E V>
539constexpr auto n() noexcept {
540 static_assert(
is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
542# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
543 constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
544 auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} :
str_view{};
548 for (std::size_t i = name.size_; i > 0; --i) {
549 if (name.str_[i] ==
',' || name.str_[i] ==
':') {
558 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
566template <
typename E, E V>
569 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
571 constexpr auto name = custom.second;
572 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
577#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
578 constexpr auto name =
n<E, V>();
580 constexpr auto name =
n<V>();
588template <
typename E, E V>
591template <
typename E, auto V>
593#if defined(__clang__) && __clang_major__ >= 16
595 constexpr E v = __builtin_bit_cast(E, V);
597 constexpr E v =
static_cast<E
>(V);
600 static_assert(std::is_same_v<std::decay_t<
decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
602 constexpr auto name = custom.second;
603 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
604 return name.size() != 0;
606#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
609 return n<v>().size_ != 0;
621template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
622constexpr U
ualue(std::size_t i)
noexcept {
623 if constexpr (std::is_same_v<U, bool>) {
624 static_assert(O == 0,
"magic_enum::detail::ualue requires valid offset.");
626 return static_cast<U
>(i);
628 return static_cast<U
>(U{1} <<
static_cast<U
>(
static_cast<int>(i) + O));
630 return static_cast<U
>(
static_cast<int>(i) + O);
634template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
635constexpr E
value(std::size_t i)
noexcept {
639template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
645 constexpr auto rhs = (std::numeric_limits<U>::min)();
655template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
658 return std::numeric_limits<U>::digits - 1;
661 constexpr auto rhs = (std::numeric_limits<U>::max)();
671#define MAGIC_ENUM_FOR_EACH_256(T) \
672 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) \
673 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) \
674 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) \
675 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) \
676 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) \
677 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) \
678 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) \
679 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)
681template <
typename E, enum_subtype S, std::
size_t Size,
int Min, std::
size_t I>
682constexpr void valid_count(
bool* valid, std::size_t& count)
noexcept {
683#define MAGIC_ENUM_V(O) \
684 if constexpr ((I + O) < Size) { \
685 if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
686 valid[I + O] = true; \
693 if constexpr ((I + 256) < Size) {
699template <std::
size_t N>
705template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
712template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
716 if constexpr (vc.count > 0) {
717#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
718 std::array<E, vc.count>
values = {};
722 for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
727#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
733 return std::array<E, 0>{};
737template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
741 constexpr auto range_size =
max -
min + 1;
742 static_assert(range_size > 0,
"magic_enum::enum_range requires valid size.");
743 static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(),
"magic_enum::enum_range requires valid size.");
748template <
typename E,
typename U = std::underlying_type_t<E>>
750 if constexpr (std::is_same_v<U, bool>) {
755#if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
758 if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
761 for (std::size_t i = 0; i < default_values.size(); ++i) {
762 const auto v =
static_cast<U
>(default_values[i]);
763 if (v != 0 && (v & (v - 1)) != 0) {
780template <
typename E,
typename D = std::decay_t<E>>
783template <
typename E, enum_subtype S>
786template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
789template <
typename E, enum_subtype S>
792template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
795template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
799constexpr auto names(std::index_sequence<I...>)
noexcept {
803template <
typename E, enum_subtype S>
806template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
810constexpr auto entries(std::index_sequence<I...>)
noexcept {
814template <
typename E, enum_subtype S>
817template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
820template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
824 }
else if constexpr (std::is_same_v<U, bool>) {
829 constexpr auto range_size =
max -
min + 1;
835template <
typename E, enum_subtype S = subtype_v<E>>
838template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
840 static_assert(S ==
enum_subtype::flags,
"magic_enum::detail::values_ors requires valid subtype.");
843 for (std::size_t i = 0; i < count_v<E, S>; ++i) {
850template <
bool,
typename R>
856 static_assert(
supported<R>::value,
"magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
859template <
typename T,
typename R,
typename BinaryPredicate = std::equal_to<>,
typename D = std::decay_t<T>>
862template <
typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>,
int> = 0>
865template <
typename T,
bool = std::is_enum_v<T>>
869struct is_scoped_enum<
T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
871template <
typename T,
bool = std::is_enum_v<T>>
875struct is_unscoped_enum<
T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
877template <
typename T,
bool = std::is_enum_v<std::decay_t<T>>>
883#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
885template <
typename Value,
typename =
void>
886struct constexpr_hash_t;
888template <
typename Value>
889struct constexpr_hash_t<Value,
std::
enable_if_t<is_enum_v<Value>>> {
890 constexpr auto operator()(Value
value)
const noexcept {
892 if constexpr (std::is_same_v<U, bool>) {
893 return static_cast<std::size_t
>(
value);
895 return static_cast<U
>(value);
898 using secondary_hash = constexpr_hash_t;
901template <
typename Value>
902struct constexpr_hash_t<
Value, std::
enable_if_t<std::is_same_v<Value, string_view>>> {
903 static constexpr std::uint32_t crc_table[256] {
904 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
905 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
906 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
907 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
908 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
909 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
910 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
911 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
912 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
913 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
914 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
915 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
916 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
917 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
918 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
919 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
920 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
921 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
922 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
923 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
924 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
925 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
926 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
927 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
928 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
929 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
930 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
931 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
932 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
933 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
934 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
935 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
937 constexpr std::uint32_t operator()(string_view value)
const noexcept {
938 auto crc =
static_cast<std::uint32_t
>(0xffffffffL);
939 for (
const auto c : value) {
940 crc = (crc >> 8) ^ crc_table[(crc ^
static_cast<std::uint32_t
>(
c)) & 0xff];
942 return crc ^ 0xffffffffL;
945 struct secondary_hash {
946 constexpr std::uint32_t operator()(string_view value)
const noexcept {
947 auto acc =
static_cast<std::uint64_t
>(2166136261ULL);
948 for (
const auto c : value) {
949 acc = ((acc ^
static_cast<std::uint64_t
>(
c)) *
static_cast<std::uint64_t
>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
951 return static_cast<std::uint32_t
>(acc);
956template <
typename Hash>
957inline constexpr Hash hash_v{};
959template <auto* GlobValues,
typename Hash>
960constexpr auto calculate_cases(std::size_t Page)
noexcept {
961 constexpr std::array
values = *GlobValues;
962 constexpr std::size_t size =
values.size();
964 using switch_t = std::invoke_result_t<Hash,
typename decltype(
values)::value_type>;
965 static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
966 const std::size_t values_to = (std::min)(
static_cast<std::size_t
>(256), size - Page);
968 std::array<switch_t, 256> result{};
969 auto fill = result.begin();
971 auto first =
values.begin() +
static_cast<std::ptrdiff_t
>(Page);
972 auto last =
values.begin() +
static_cast<std::ptrdiff_t
>(Page + values_to);
973 while (first != last) {
974 *fill++ = hash_v<Hash>(*first++);
979 for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
983 auto it = result.begin();
984 auto last_value = (std::numeric_limits<switch_t>::min)();
985 for (; fill != result.end(); *fill++ = last_value++) {
986 while (last_value == *it) {
995template <
typename R,
typename F,
typename... Args>
996constexpr R invoke_r(F&& f, Args&&... args)
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
997 if constexpr (std::is_void_v<R>) {
998 std::forward<F>(f)(std::forward<Args>(args)...);
1000 return static_cast<R
>(std::forward<F>(f)(std::forward<Args>(args)...));
1004enum class case_call_t {
1009template <
typename T =
void>
1010inline constexpr auto default_result_type_lambda = []()
noexcept(std::is_nothrow_default_constructible_v<T>) {
return T{}; };
1013inline constexpr auto default_result_type_lambda<void> = []()
noexcept {};
1015template <auto* Arr,
typename Hash>
1016constexpr bool has_duplicate() noexcept {
1017 using value_t = std::decay_t<
decltype((*Arr)[0])>;
1018 using hash_value_t = std::invoke_result_t<Hash, value_t>;
1019 std::array<hash_value_t, Arr->size()> hashes{};
1020 std::size_t size = 0;
1021 for (
auto elem : *Arr) {
1022 hashes[size] = hash_v<Hash>(elem);
1023 for (
auto i = size++; i > 0; --i) {
1024 if (hashes[i] < hashes[i - 1]) {
1025 auto tmp = hashes[i];
1026 hashes[i] = hashes[i - 1];
1027 hashes[i - 1] = tmp;
1028 }
else if (hashes[i] == hashes[i - 1]) {
1038#define MAGIC_ENUM_CASE(val) \
1040 if constexpr ((val) + Page < size) { \
1041 if (!pred(values[val + Page], searched)) { \
1044 if constexpr (CallValue == case_call_t::index) { \
1045 if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1046 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1047 } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1048 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1050 } else if constexpr (CallValue == case_call_t::value) { \
1051 if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1052 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1053 } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1054 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1058 } else [[fallthrough]];
1060template <
auto* GlobValues,
1061 case_call_t CallValue,
1062 std::size_t Page = 0,
1063 typename Hash = constexpr_hash_t<
typename std::decay_t<
decltype(*GlobValues)>::value_type>,
1064 typename BinaryPredicate = std::equal_to<>,
1066 typename ResultGetterType>
1067constexpr decltype(
auto) constexpr_switch(
1069 typename std::decay_t<
decltype(*GlobValues)>::value_type searched,
1070 ResultGetterType&& def,
1071 BinaryPredicate&& pred = {}) {
1072 using result_t = std::invoke_result_t<ResultGetterType>;
1073 using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash,
typename Hash::secondary_hash>;
1074 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.");
1075 constexpr std::array
values = *GlobValues;
1076 constexpr std::size_t size =
values.size();
1077 constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1079 switch (hash_v<hash_t>(searched)) {
1082 if constexpr (size > 256 + Page) {
1083 return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1090#undef MAGIC_ENUM_CASE