32 #ifndef NEARGYE_MAGIC_ENUM_HPP
33 #define NEARGYE_MAGIC_ENUM_HPP
35 #define MAGIC_ENUM_VERSION_MAJOR 0
36 #define MAGIC_ENUM_VERSION_MINOR 9
37 #define MAGIC_ENUM_VERSION_PATCH 5
44 #include <type_traits>
47 #if defined(MAGIC_ENUM_CONFIG_FILE)
48 # include MAGIC_ENUM_CONFIG_FILE
51 #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
54 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING)
57 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
58 # include <string_view>
61 #if defined(MAGIC_ENUM_NO_ASSERT)
62 # define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
63 #elif !defined(MAGIC_ENUM_ASSERT)
65 # define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
68 #if defined(__clang__)
69 # pragma clang diagnostic push
70 # pragma clang diagnostic ignored "-Wunknown-warning-option"
71 # pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
72 # pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
73 #elif defined(__GNUC__)
74 # pragma GCC diagnostic push
75 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
76 # pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
77 #elif defined(_MSC_VER)
78 # pragma warning(push)
79 # pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
80 # pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
81 # pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
82 # pragma warning(disable : 4514) // Unreferenced inline function has been removed.
86 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__)
87 # undef MAGIC_ENUM_SUPPORTED
88 # define MAGIC_ENUM_SUPPORTED 1
92 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
93 # undef MAGIC_ENUM_SUPPORTED_ALIASES
94 # define MAGIC_ENUM_SUPPORTED_ALIASES 1
99 #if !defined(MAGIC_ENUM_RANGE_MIN)
100 # define MAGIC_ENUM_RANGE_MIN -128
105 #if !defined(MAGIC_ENUM_RANGE_MAX)
106 # define MAGIC_ENUM_RANGE_MAX 127
110 #if defined(__RESHARPER__)
111 # undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
112 # undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
113 # if __RESHARPER__ >= 20230100
114 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V)
115 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name<T>()
117 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
118 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
125 #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
126 MAGIC_ENUM_USING_ALIAS_OPTIONAL
132 #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
133 MAGIC_ENUM_USING_ALIAS_STRING_VIEW
139 #if defined(MAGIC_ENUM_USING_ALIAS_STRING)
140 MAGIC_ENUM_USING_ALIAS_STRING
146 static_assert(std::is_same_v<string_view::value_type, string::value_type>,
"magic_enum::customize requires same string_view::value_type and string::value_type");
148 if constexpr (std::is_same_v<char_type, wchar_t>) {
149 constexpr
const char c[] =
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
150 constexpr
const wchar_t wc[] = L
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
151 static_assert(
std::size(c) ==
std::size(wc),
"magic_enum::customize identifier characters are multichars in wchar_t.");
153 for (std::size_t i = 0; i <
std::size(c); ++i) {
160 } (),
"magic_enum::customize wchar_t is not compatible with ASCII.");
162 namespace customize {
167 template <
typename E>
185 class customize_t :
public std::pair<detail::customize_tag, string_view> {
200 template <
typename E>
206 template <
typename E>
215 template <
typename T>
217 #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
220 : std::false_type {};
223 template <auto V,
typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>,
int> = 0>
226 template <
typename... T>
229 template <
typename T,
typename =
void>
232 template <
typename T>
235 template <
typename T,
typename =
void>
236 struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
238 template <
typename T>
239 struct 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> {};
241 template <
typename T,
typename =
void>
242 struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
244 template <
typename T>
245 struct 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> {};
252 template <std::u
int16_t N>
265 constexpr std::uint16_t
size() const noexcept {
return N; }
270 template <std::uint16_t... I>
273 template <std::uint16_t... I>
290 constexpr std::uint16_t
size() const noexcept {
return 0; }
295 template <
typename Op = std::equal_to<>>
302 template <
typename L,
typename R>
303 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> {
309 #if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
312 constexpr
bool workaround =
true;
314 constexpr
bool workaround =
false;
317 if constexpr (workaround) {
318 for (std::size_t i = 0; i < str.size(); ++i) {
324 return string_view::npos;
330 template <
typename BinaryPredicate>
332 return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
333 std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
336 template <
typename BinaryPredicate>
338 return is_default_predicate<BinaryPredicate>() ||
339 std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
342 template <
typename BinaryPredicate>
344 #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
347 constexpr
bool workaround =
true;
349 constexpr
bool workaround =
false;
352 if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {
353 if (lhs.size() != rhs.size()) {
357 const auto size = lhs.size();
358 for (std::size_t i = 0; i <
size; ++i) {
359 if (!
p(lhs[i], rhs[i])) {
370 template <
typename L,
typename R>
372 static_assert(std::is_integral_v<L> && std::is_integral_v<R>,
"magic_enum::detail::cmp_less requires integral type.");
374 if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
377 }
else if constexpr (std::is_same_v<L, bool>) {
378 return static_cast<R
>(lhs) < rhs;
379 }
else if constexpr (std::is_same_v<R, bool>) {
380 return lhs < static_cast<L>(rhs);
381 }
else if constexpr (std::is_signed_v<R>) {
383 return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);
386 return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;
390 template <
typename I>
392 static_assert(std::is_integral_v<I>,
"magic_enum::detail::log2 requires integral type.");
394 if constexpr (std::is_same_v<I, bool>) {
398 for (;
value > I{1};
value >>= I{1}, ++ret) {}
404 #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
405 # define MAGIC_ENUM_ARRAY_CONSTEXPR 1
407 template <
typename T, std::size_t N, std::size_t... I>
408 constexpr std::array<std::remove_cv_t<T>, N>
to_array(T (&a)[N], std::index_sequence<I...>) noexcept {
413 template <
typename T>
414 inline constexpr
bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
416 template <
typename E>
417 constexpr
auto n() noexcept {
418 static_assert(is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
421 #if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
422 constexpr
auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
423 constexpr
auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} :
str_view{};
424 #elif defined(__clang__)
426 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
427 static_assert(always_false_v<E>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
430 name.
size_ =
sizeof(__PRETTY_FUNCTION__) - 36;
431 name.
str_ = __PRETTY_FUNCTION__ + 34;
433 #elif defined(__GNUC__)
434 auto name =
str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
435 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
436 static_assert(always_false_v<E>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
438 }
else if (name.
str_[name.
size_ - 1] ==
']') {
445 #elif defined(_MSC_VER)
448 name.
str_ = __FUNCSIG__;
450 name.
size_ +=
sizeof(__FUNCSIG__) - 57;
455 for (std::size_t i = name.
size_; i > 0; --i) {
456 if (name.
str_[i] ==
':') {
471 template <
typename E>
473 [[maybe_unused]] constexpr
auto custom = customize::enum_type_name<E>();
474 static_assert(std::is_same_v<std::decay_t<decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
476 constexpr
auto name = custom.second;
477 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
482 constexpr
auto name = n<E>();
485 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
489 template <
typename E>
493 constexpr
auto n() noexcept {
494 static_assert(
is_enum_v<decltype(V)>,
"magic_enum::detail::n requires enum type.");
497 #if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
498 constexpr
auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
499 auto name = name_ptr ?
str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
500 #elif defined(__clang__)
502 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
503 static_assert(
always_false_v<decltype(V)>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
506 name.size_ =
sizeof(__PRETTY_FUNCTION__) - 36;
507 name.str_ = __PRETTY_FUNCTION__ + 34;
509 if (name.size_ > 22 && name.str_[0] ==
'(' && name.str_[1] ==
'a' && name.str_[10] ==
' ' && name.str_[22] ==
':') {
513 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
516 #elif defined(__GNUC__)
517 auto name = str_view{__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 1};
518 if constexpr (
sizeof(__PRETTY_FUNCTION__) ==
sizeof(__FUNCTION__)) {
519 static_assert(
always_false_v<decltype(V)>,
"magic_enum::detail::n requires __PRETTY_FUNCTION__.");
521 }
else if (name.str_[name.size_ - 1] ==
']') {
528 if (name.str_[0] ==
'(') {
531 #elif defined(_MSC_VER)
533 if ((__FUNCSIG__[5] ==
'_' && __FUNCSIG__[35] !=
'(') || (__FUNCSIG__[5] ==
'c' && __FUNCSIG__[41] !=
'(')) {
535 name.str_ = __FUNCSIG__;
537 name.size_ =
sizeof(__FUNCSIG__) - 52;
540 auto name = str_view{};
543 for (std::size_t i = name.size_; i > 0; --i) {
544 if (name.str_[i] ==
':') {
559 #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
560 # define MAGIC_ENUM_VS_2017_WORKAROUND 1
563 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
564 template <
typename E, E V>
565 constexpr
auto n() noexcept {
566 static_assert(is_enum_v<E>,
"magic_enum::detail::n requires enum type.");
568 # if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
569 constexpr
auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
570 auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
574 name.str_ = __FUNCSIG__;
575 name.size_ =
sizeof(__FUNCSIG__) - 17;
577 for (std::size_t i = name.size_; i > 0; --i) {
578 if (name.str_[i] ==
',' || name.str_[i] ==
':') {
587 if (name.str_[0] ==
'(' || name.str_[0] ==
'-' || (name.str_[0] >=
'0' && name.str_[0] <=
'9')) {
595 template <
typename E, E V>
597 [[maybe_unused]] constexpr
auto custom = customize::enum_name<E>(V);
598 static_assert(std::is_same_v<std::decay_t<decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
600 constexpr
auto name = custom.second;
601 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
606 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
607 constexpr
auto name = n<E, V>();
609 constexpr
auto name = n<V>();
613 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
617 template <
typename E, E V>
620 template <
typename E, auto V>
622 #if defined(__clang__) && __clang_major__ >= 16
624 constexpr E v = __builtin_bit_cast(E, V);
626 constexpr E v =
static_cast<E
>(V);
628 [[maybe_unused]] constexpr
auto custom = customize::enum_name<E>(v);
629 static_assert(std::is_same_v<std::decay_t<decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
631 constexpr
auto name = custom.second;
632 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
633 return name.size() != 0;
635 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
636 return n<E, v>().size_ != 0;
638 return n<v>().size_ != 0;
650 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
651 constexpr U
ualue(std::size_t i) noexcept {
652 if constexpr (std::is_same_v<U, bool>) {
653 static_assert(O == 0,
"magic_enum::detail::ualue requires valid offset.");
655 return static_cast<U
>(i);
657 return static_cast<U
>(U{1} <<
static_cast<U
>(
static_cast<int>(i) + O));
659 return static_cast<U
>(
static_cast<int>(i) + O);
663 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
664 constexpr E
value(std::size_t i) noexcept {
665 return static_cast<E
>(ualue<E, O, S>(i));
668 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
674 constexpr
auto rhs = (std::numeric_limits<U>::min)();
684 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
690 constexpr
auto rhs = (std::numeric_limits<U>::max)();
700 #define MAGIC_ENUM_FOR_EACH_256(T) \
701 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) \
702 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) \
703 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) \
704 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) \
705 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) \
706 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) \
707 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) \
708 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)
710 template <
typename E, enum_subtype S, std::
size_t Size,
int Min, std::
size_t I>
712 #define MAGIC_ENUM_V(O) \
713 if constexpr ((I + O) < Size) { \
714 if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
715 valid[I + O] = true; \
722 if constexpr ((I + 256) < Size) {
723 valid_count<E, S, Size, Min, I + 256>(valid,
count);
728 template <std::
size_t N>
734 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
737 valid_count<E, S, Size, Min, 0>(vc.
valid, vc.
count);
741 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
743 constexpr
auto vc = valid_count<E, S, Size, Min>();
745 if constexpr (vc.count > 0) {
746 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
747 std::array<E, vc.count>
values = {};
751 for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
753 values[v++] = value<E, Min, S>(i);
756 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
762 return std::array<E, 0>{};
766 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
768 constexpr
auto min = reflected_min<E, S>();
769 constexpr
auto max = reflected_max<E, S>();
771 static_assert(
range_size > 0,
"magic_enum::enum_range requires valid size.");
773 return values<E, S, range_size, min>();
776 template <
typename E,
typename U = std::underlying_type_t<E>>
778 if constexpr (std::is_same_v<U, bool>) {
783 #if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
784 constexpr
auto flags_values = values<E, enum_subtype::flags>();
785 constexpr
auto default_values = values<E, enum_subtype::common>();
786 if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
789 for (std::size_t i = 0; i < default_values.size(); ++i) {
790 const auto v =
static_cast<U
>(default_values[i]);
791 if (v != 0 && (v & (v - 1)) != 0) {
802 template <
typename T>
808 template <
typename E,
typename D = std::decay_t<E>>
809 inline constexpr
auto subtype_v = subtype<D>(std::is_enum<D>{});
811 template <
typename E, enum_subtype S>
814 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
817 template <
typename E, enum_subtype S>
818 inline constexpr
auto count_v = values_v<E, S>.size();
820 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
821 inline constexpr
auto min_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.front()) : U{0};
823 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
824 inline constexpr
auto max_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.back()) : U{0};
827 constexpr
auto names(std::index_sequence<I...>) noexcept {
828 constexpr
auto names = std::array<
string_view,
sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
832 template <
typename E, enum_subtype S>
835 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
839 constexpr
auto entries(std::index_sequence<I...>) noexcept {
840 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]>}...}};
844 template <
typename E, enum_subtype S>
847 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
850 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
852 if constexpr (count_v<E, S> == 0) {
854 }
else if constexpr (std::is_same_v<U, bool>) {
865 template <
typename E, enum_subtype S = subtype_v<E>>
868 template <
typename E, enum_subtype S>
870 #if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
873 : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
876 template <
typename E, enum_subtype S>
879 template <
bool,
typename R>
882 template <
typename R>
885 static_assert(
supported<R>::value,
"magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
888 template <
typename T,
typename R,
typename BinaryPredicate = std::equal_to<>,
typename D = std::decay_t<T>>
891 template <
typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>,
int> = 0>
894 template <
typename T,
bool = std::is_enum_v<T>>
897 template <
typename T>
900 template <
typename T,
bool = std::is_enum_v<T>>
903 template <
typename T>
906 template <
typename T,
bool = std::is_enum_v<std::decay_t<T>>>
909 template <
typename T>
912 #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
914 template <
typename Value,
typename =
void>
915 struct constexpr_hash_t;
917 template <
typename Value>
918 struct constexpr_hash_t<Value,
std::
enable_if_t<is_enum_v<Value>>> {
919 constexpr
auto operator()(Value
value)
const noexcept {
921 if constexpr (std::is_same_v<U, bool>) {
922 return static_cast<std::size_t
>(
value);
924 return static_cast<U
>(
value);
927 using secondary_hash = constexpr_hash_t;
930 template <
typename Value>
931 struct constexpr_hash_t<Value,
std::
enable_if_t<std::is_same_v<Value, string_view>>> {
932 static constexpr std::uint32_t crc_table[256] {
933 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
934 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
935 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
936 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
937 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
938 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
939 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
940 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
941 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
942 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
943 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
944 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
945 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
946 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
947 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
948 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
949 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
950 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
951 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
952 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
953 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
954 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
955 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
956 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
957 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
958 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
959 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
960 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
961 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
962 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
963 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
964 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
967 auto crc =
static_cast<std::uint32_t
>(0xffffffffL);
968 for (
const auto c :
value) {
969 crc = (crc >> 8) ^ crc_table[(crc ^
static_cast<std::uint32_t
>(c)) & 0xff];
971 return crc ^ 0xffffffffL;
974 struct secondary_hash {
976 auto acc =
static_cast<std::uint64_t
>(2166136261ULL);
977 for (
const auto c :
value) {
978 acc = ((acc ^
static_cast<std::uint64_t
>(c)) *
static_cast<std::uint64_t
>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
980 return static_cast<std::uint32_t
>(acc);
985 template <
typename Hash>
986 inline constexpr Hash hash_v{};
988 template <auto* GlobValues,
typename Hash>
989 constexpr
auto calculate_cases(std::size_t Page) noexcept {
990 constexpr std::array
values = *GlobValues;
993 using switch_t = std::invoke_result_t<Hash,
typename decltype(
values)::value_type>;
994 static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
995 const std::size_t values_to = (std::min)(
static_cast<std::size_t
>(256),
size - Page);
997 std::array<switch_t, 256> result{};
998 auto fill = result.begin();
1000 auto first =
values.begin() +
static_cast<std::ptrdiff_t
>(Page);
1001 auto last =
values.begin() +
static_cast<std::ptrdiff_t
>(Page + values_to);
1002 while (first != last) {
1003 *fill++ = hash_v<Hash>(*first++);
1008 for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1012 auto it = result.begin();
1013 auto last_value = (std::numeric_limits<switch_t>::min)();
1014 for (; fill != result.end(); *fill++ = last_value++) {
1015 while (last_value == *it) {
1024 template <
typename R,
typename F,
typename... Args>
1025 constexpr R invoke_r(F&&
f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
1026 if constexpr (std::is_void_v<R>) {
1027 std::forward<F>(
f)(std::forward<Args>(args)...);
1029 return static_cast<R
>(std::forward<F>(
f)(std::forward<Args>(args)...));
1033 enum class case_call_t {
1038 template <
typename T =
void>
1039 inline constexpr
auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) {
return T{}; };
1042 inline constexpr
auto default_result_type_lambda<void> = []() noexcept {};
1044 template <auto* Arr,
typename Hash>
1045 constexpr
bool has_duplicate() noexcept {
1046 using value_t = std::decay_t<decltype((*Arr)[0])>;
1047 using hash_value_t = std::invoke_result_t<Hash, value_t>;
1048 std::array<hash_value_t, Arr->size()> hashes{};
1049 std::size_t
size = 0;
1050 for (
auto elem : *Arr) {
1051 hashes[
size] = hash_v<Hash>(elem);
1052 for (
auto i =
size++; i > 0; --i) {
1053 if (hashes[i] < hashes[i - 1]) {
1054 auto tmp = hashes[i];
1055 hashes[i] = hashes[i - 1];
1056 hashes[i - 1] = tmp;
1057 }
else if (hashes[i] == hashes[i - 1]) {
1067 #define MAGIC_ENUM_CASE(val) \
1069 if constexpr ((val) + Page < size) { \
1070 if (!pred(values[val + Page], searched)) { \
1073 if constexpr (CallValue == case_call_t::index) { \
1074 if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1075 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1076 } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1077 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1079 } else if constexpr (CallValue == case_call_t::value) { \
1080 if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1081 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1082 } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1083 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1087 } else [[fallthrough]];
1089 template <
auto* GlobValues,
1090 case_call_t CallValue,
1091 std::size_t Page = 0,
1092 typename Hash = constexpr_hash_t<
typename std::decay_t<decltype(*GlobValues)>::value_type>,
1093 typename BinaryPredicate = std::equal_to<>,
1095 typename ResultGetterType>
1096 constexpr decltype(
auto) constexpr_switch(
1098 typename
std::decay_t<decltype(*GlobValues)>::value_type searched,
1099 ResultGetterType&& def,
1100 BinaryPredicate&& pred = {}) {
1101 using result_t = std::invoke_result_t<ResultGetterType>;
1102 using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash,
typename Hash::secondary_hash>;
1103 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.");
1104 constexpr std::array
values = *GlobValues;
1106 constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1108 switch (hash_v<hash_t>(searched)) {
1111 if constexpr (
size > 256 + Page) {
1112 return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1119 #undef MAGIC_ENUM_CASE
1128 template <
typename T>
1133 template <
typename T>
1136 template <
typename T>
1141 template <
typename T>
1144 template <
typename T>
1149 template <
typename T>
1152 template <
typename T>
1159 template <
typename E>
1161 constexpr
string_view name = detail::type_name_v<std::decay_t<E>>;
1162 static_assert(!name.empty(),
"magic_enum::enum_type_name enum type does not have a name.");
1168 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1170 return detail::count_v<std::decay_t<E>, S>;
1175 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1177 using D = std::decay_t<E>;
1178 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1180 if constexpr (detail::is_sparse_v<D, S>) {
1181 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
1185 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
1190 template <
typename E, std::
size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1192 using D = std::decay_t<E>;
1193 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1194 static_assert(I < detail::count_v<D, S>,
"magic_enum::enum_value out of range.");
1196 return enum_value<D, S>(I);
1200 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1202 using D = std::decay_t<E>;
1203 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1205 return detail::values_v<D, S>;
1209 template <
typename E>
1215 template <
typename E>
1222 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1224 using D = std::decay_t<E>;
1226 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1229 #if defined(MAGIC_ENUM_ENABLE_HASH)
1230 return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
1231 [](std::size_t i) {
return optional<std::size_t>{i}; },
1233 detail::default_result_type_lambda<optional<std::size_t>>);
1235 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1236 if (enum_value<D, S>(i) == value) {
1243 const auto v =
static_cast<U
>(value);
1244 if (v >= detail::min_v<D, S> && v <= detail::max_v<D, S>) {
1245 return static_cast<std::size_t
>(v - detail::min_v<D, S>);
1253 template <detail::enum_subtype S,
typename E>
1255 using D = std::decay_t<E>;
1256 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1258 return enum_index<D, S>(value);
1262 template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1264 using D = std::decay_t<decltype(V)>;
1265 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1266 constexpr
auto index = enum_index<D, S>(V);
1267 static_assert(index,
"magic_enum::enum_index enum value does not have a index.");
1277 static_assert(!name.empty(),
"magic_enum::enum_name enum value does not have a name.");
1284 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1286 using D = std::decay_t<E>;
1287 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1289 if (
const auto i = enum_index<D, S>(value)) {
1290 return detail::names_v<D, S>[*i];
1297 template <detail::enum_subtype S,
typename E>
1299 using D = std::decay_t<E>;
1300 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1302 return enum_name<D, S>(value);
1306 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1308 using D = std::decay_t<E>;
1309 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1311 return detail::names_v<D, S>;
1315 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1317 using D = std::decay_t<E>;
1318 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1320 return detail::entries_v<D, S>;
1328 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1330 using D = std::decay_t<E>;
1331 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1334 #if defined(MAGIC_ENUM_ENABLE_HASH)
1336 [](D v) {
return optional<D>{v}; },
1337 static_cast<D
>(value),
1338 detail::default_result_type_lambda<optional<D>>);
1340 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1342 return static_cast<D
>(value);
1348 if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
1349 return static_cast<D
>(value);
1357 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1359 using D = std::decay_t<E>;
1360 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1362 #if defined(MAGIC_ENUM_ENABLE_HASH)
1363 if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
1364 return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
1365 [](std::size_t i) {
return optional<D>{detail::values_v<D, S>[i]}; },
1367 detail::default_result_type_lambda<optional<D>>,
1371 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1373 return enum_value<D, S>(i);
1380 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1382 using D = std::decay_t<E>;
1385 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(value)));
1389 template <detail::enum_subtype S,
typename E>
1391 using D = std::decay_t<E>;
1392 using U = underlying_type_t<D>;
1394 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(value)));
1398 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1400 using D = std::decay_t<E>;
1402 return static_cast<bool>(enum_cast<D, S>(value));
1406 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1408 using D = std::decay_t<E>;
1410 return static_cast<bool>(enum_cast<D, S>(value, std::move(
p)));
1413 template <
bool AsFlags = true>
1416 template <
bool AsFlags = true>
1419 namespace bitwise_operators {
1421 template <
typename E, detail::enable_if_t<E,
int> = 0>
1423 return static_cast<E
>(~static_cast<underlying_type_t<E>>(rhs));
1426 template <
typename E, detail::enable_if_t<E,
int> = 0>
1431 template <
typename E, detail::enable_if_t<E,
int> = 0>
1436 template <
typename E, detail::enable_if_t<E,
int> = 0>
1441 template <
typename E, detail::enable_if_t<E,
int> = 0>
1443 return lhs = (lhs | rhs);
1446 template <
typename E, detail::enable_if_t<E,
int> = 0>
1448 return lhs = (lhs & rhs);
1451 template <
typename E, detail::enable_if_t<E,
int> = 0>
1453 return lhs = (lhs ^ rhs);
1460 #if defined(__clang__)
1461 # pragma clang diagnostic pop
1462 #elif defined(__GNUC__)
1463 # pragma GCC diagnostic pop
1464 #elif defined(_MSC_VER)
1465 # pragma warning(pop)
1468 #undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
1469 #undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
1470 #undef MAGIC_ENUM_VS_2017_WORKAROUND
1471 #undef MAGIC_ENUM_ARRAY_CONSTEXPR
1472 #undef MAGIC_ENUM_FOR_EACH_256
1474 #endif // NEARGYE_MAGIC_ENUM_HPP