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 7
39 #ifndef MAGIC_ENUM_USE_STD_MODULE
45 #include <type_traits>
49 #if defined(MAGIC_ENUM_CONFIG_FILE)
50 # include MAGIC_ENUM_CONFIG_FILE
53 #ifndef MAGIC_ENUM_USE_STD_MODULE
54 #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
57 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING)
60 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
61 # include <string_view>
65 #if defined(MAGIC_ENUM_NO_ASSERT)
66 # define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
67 #elif !defined(MAGIC_ENUM_ASSERT)
69 # define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
72 #if defined(__clang__)
73 # pragma clang diagnostic push
74 # pragma clang diagnostic ignored "-Wunknown-warning-option"
75 # pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
76 # pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
77 #elif defined(__GNUC__)
78 # pragma GCC diagnostic push
79 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
80 # pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
81 #elif defined(_MSC_VER)
82 # pragma warning(push)
83 # pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
84 # pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
85 # pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
86 # pragma warning(disable : 4514) // Unreferenced inline function has been removed.
90 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__)
91 # undef MAGIC_ENUM_SUPPORTED
92 # define MAGIC_ENUM_SUPPORTED 1
96 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
97 # undef MAGIC_ENUM_SUPPORTED_ALIASES
98 # define MAGIC_ENUM_SUPPORTED_ALIASES 1
103 #if !defined(MAGIC_ENUM_RANGE_MIN)
104 # define MAGIC_ENUM_RANGE_MIN -128
109 #if !defined(MAGIC_ENUM_RANGE_MAX)
110 # define MAGIC_ENUM_RANGE_MAX 127
114 #if defined(__RESHARPER__)
115 # undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
116 # undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
117 # if __RESHARPER__ >= 20230100
118 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V)
119 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name<T>()
121 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
122 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
129 #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
136 #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
139 using std::string_view;
143 #if defined(MAGIC_ENUM_USING_ALIAS_STRING)
150 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");
152 if constexpr (std::is_same_v<char_type, wchar_t>) {
153 constexpr
const char c[] =
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
154 constexpr
const wchar_t wc[] = L
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
155 static_assert(std::size(c) == std::size(wc),
"magic_enum::customize identifier characters are multichars in wchar_t.");
157 for (std::size_t i = 0; i < std::size(c); ++i) {
164 } (),
"magic_enum::customize wchar_t is not compatible with ASCII.");
166 namespace customize {
171 template <
typename E>
189 class customize_t :
public std::pair<detail::customize_tag, string_view> {
204 template <
typename E>
210 template <
typename E>
219 template <
typename T>
221 #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
224 : std::false_type {};
227 template <auto V,
typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>,
int> = 0>
230 template <
typename... T>
233 template <
typename T,
typename =
void>
236 template <
typename T>
237 struct 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)>>> {};
239 template <
typename T,
typename =
void>
240 struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
242 template <
typename T>
243 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> {};
245 template <
typename T,
typename =
void>
246 struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
248 template <
typename T>
249 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> {};
256 template <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 {}; }
299 template <
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;
334 template <
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<>>;
340 template <
typename BinaryPredicate>
342 return is_default_predicate<BinaryPredicate>() ||
343 std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
346 template <
typename BinaryPredicate>
347 constexpr
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])) {
374 template <
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;
394 template <
typename I>
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
411 template <
typename T, std::size_t N, std::size_t... I>
412 constexpr std::array<std::remove_cv_t<T>, N>
to_array(T (&a)[N], std::index_sequence<I...>) noexcept {
417 template <
typename T>
418 inline constexpr
bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
420 template <
typename E>
421 constexpr
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] ==
':') {
475 template <
typename E>
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.");
493 template <
typename E>
497 constexpr
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)
568 template <
typename E, E V>
569 constexpr
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')) {
599 template <
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.");
621 template <
typename E, E V>
626 #if defined(__clang__) && __clang_major__ >= 16
627 template <
typename E, auto V,
typename =
void>
629 template <
typename E, auto V>
630 inline constexpr
bool is_enum_constexpr_static_cast_valid<E, V, std::void_t<std::integral_constant<E, static_cast<E>(V)>>> =
true;
632 template <
typename, auto>
636 template <
typename E, auto V>
638 if constexpr (is_enum_constexpr_static_cast_valid<E, V>) {
639 constexpr E v =
static_cast<E
>(V);
640 [[maybe_unused]] constexpr
auto custom = customize::enum_name<E>(v);
641 static_assert(std::is_same_v<std::decay_t<decltype(custom)>,
customize::customize_t>,
"magic_enum::customize requires customize_t type.");
643 constexpr
auto name = custom.second;
644 static_assert(!name.empty(),
"magic_enum::customize requires not empty string.");
645 return name.size() != 0;
647 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
648 return n<E, v>().size_ != 0;
650 return n<v>().size_ != 0;
665 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
666 constexpr U
ualue(std::size_t i) noexcept {
667 if constexpr (std::is_same_v<U, bool>) {
668 static_assert(O == 0,
"magic_enum::detail::ualue requires valid offset.");
670 return static_cast<U
>(i);
672 return static_cast<U
>(U{1} <<
static_cast<U
>(
static_cast<int>(i) + O));
674 return static_cast<U
>(
static_cast<int>(i) + O);
678 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
679 constexpr E
value(std::size_t i) noexcept {
680 return static_cast<E
>(ualue<E, O, S>(i));
683 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
689 constexpr
auto rhs = (std::numeric_limits<U>::min)();
699 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
702 return std::numeric_limits<U>::digits - 1;
705 constexpr
auto rhs = (std::numeric_limits<U>::max)();
715 #define MAGIC_ENUM_FOR_EACH_256(T) \
716 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) \
717 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) \
718 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) \
719 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) \
720 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) \
721 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) \
722 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) \
723 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)
725 template <
typename E, enum_subtype S, std::
size_t Size,
int Min, std::
size_t I>
726 constexpr
void valid_count(
bool* valid, std::size_t& count) noexcept {
727 #define MAGIC_ENUM_V(O) \
728 if constexpr ((I + O) < Size) { \
729 if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
730 valid[I + O] = true; \
737 if constexpr ((I + 256) < Size) {
738 valid_count<E, S, Size, Min, I + 256>(valid, count);
743 template <std::
size_t N>
749 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
752 valid_count<E, S, Size, Min, 0>(vc.
valid, vc.
count);
756 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
758 constexpr
auto vc = valid_count<E, S, Size, Min>();
760 if constexpr (vc.count > 0) {
761 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
762 std::array<E, vc.count>
values = {};
766 for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
768 values[v++] = value<E, Min, S>(i);
771 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
777 return std::array<E, 0>{};
781 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
783 constexpr
auto min = reflected_min<E, S>();
784 constexpr
auto max = reflected_max<E, S>();
785 constexpr
auto range_size = max - min + 1;
786 static_assert(range_size > 0,
"magic_enum::enum_range requires valid size.");
788 return values<E, S, range_size, min>();
791 template <
typename E,
typename U = std::underlying_type_t<E>>
793 if constexpr (std::is_same_v<U, bool>) {
798 #if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
799 constexpr
auto flags_values = values<E, enum_subtype::flags>();
800 constexpr
auto default_values = values<E, enum_subtype::common>();
801 if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
804 for (std::size_t i = 0; i < default_values.size(); ++i) {
805 const auto v =
static_cast<U
>(default_values[i]);
806 if (v != 0 && (v & (v - 1)) != 0) {
817 template <
typename T>
823 template <
typename E,
typename D = std::decay_t<E>>
824 inline constexpr
auto subtype_v = subtype<D>(std::is_enum<D>{});
826 template <
typename E, enum_subtype S>
829 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
832 template <
typename E, enum_subtype S>
833 inline constexpr
auto count_v = values_v<E, S>.size();
835 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
836 inline constexpr
auto min_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.front()) : U{0};
838 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
839 inline constexpr
auto max_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.back()) : U{0};
842 constexpr
auto names(std::index_sequence<I...>) noexcept {
843 constexpr
auto names = std::array<string_view,
sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
847 template <
typename E, enum_subtype S>
848 inline constexpr
auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
850 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
854 constexpr
auto entries(std::index_sequence<I...>) noexcept {
855 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]>}...}};
859 template <
typename E, enum_subtype S>
860 inline constexpr
auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
862 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
865 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
867 if constexpr (count_v<E, S> == 0) {
869 }
else if constexpr (std::is_same_v<U, bool>) {
874 constexpr
auto range_size = max - min + 1;
876 return range_size != count_v<E, S>;
880 template <
typename E, enum_subtype S = subtype_v<E>>
883 template <
typename E, enum_subtype S>
888 : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
891 template <
typename E, enum_subtype S>
894 template <
bool,
typename R>
897 template <
typename R>
900 static_assert(
supported<R>::value,
"magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
903 template <
typename T,
typename R,
typename BinaryPredicate = std::equal_to<>,
typename D = std::decay_t<T>>
906 template <
typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>,
int> = 0>
909 template <
typename T,
bool = std::is_enum_v<T>>
912 template <
typename T>
913 struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
915 template <
typename T,
bool = std::is_enum_v<T>>
918 template <
typename T>
919 struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
921 template <
typename T,
bool = std::is_enum_v<std::decay_t<T>>>
924 template <
typename T>
927 #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
929 template <
typename Value,
typename =
void>
930 struct constexpr_hash_t;
932 template <
typename Value>
933 struct constexpr_hash_t<Value,
std::
enable_if_t<is_enum_v<Value>>> {
934 constexpr
auto operator()(Value
value)
const noexcept {
936 if constexpr (std::is_same_v<U, bool>) {
937 return static_cast<std::size_t
>(
value);
939 return static_cast<U
>(
value);
942 using secondary_hash = constexpr_hash_t;
945 template <
typename Value>
946 struct constexpr_hash_t<Value,
std::
enable_if_t<std::is_same_v<Value, string_view>>> {
947 static constexpr std::uint32_t crc_table[256] {
948 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
949 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
950 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
951 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
952 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
953 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
954 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
955 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
956 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
957 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
958 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
959 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
960 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
961 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
962 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
963 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
964 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
965 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
966 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
967 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
968 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
969 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
970 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
971 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
972 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
973 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
974 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
975 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
976 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
977 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
978 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
979 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
981 constexpr std::uint32_t operator()(string_view
value)
const noexcept {
982 auto crc =
static_cast<std::uint32_t
>(0xffffffffL);
983 for (
const auto c :
value) {
984 crc = (crc >> 8) ^ crc_table[(crc ^
static_cast<std::uint32_t
>(c)) & 0xff];
986 return crc ^ 0xffffffffL;
989 struct secondary_hash {
990 constexpr std::uint32_t operator()(string_view
value)
const noexcept {
991 auto acc =
static_cast<std::uint64_t
>(2166136261ULL);
992 for (
const auto c :
value) {
993 acc = ((acc ^
static_cast<std::uint64_t
>(c)) *
static_cast<std::uint64_t
>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
995 return static_cast<std::uint32_t
>(acc);
1000 template <
typename Hash>
1001 inline constexpr Hash hash_v{};
1003 template <auto* GlobValues,
typename Hash>
1004 constexpr
auto calculate_cases(std::size_t Page) noexcept {
1005 constexpr std::array
values = *GlobValues;
1006 constexpr std::size_t size =
values.size();
1009 static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
1010 const std::size_t values_to = (std::min)(
static_cast<std::size_t
>(256), size - Page);
1012 std::array<switch_t, 256> result{};
1013 auto fill = result.begin();
1015 auto first =
values.begin() +
static_cast<std::ptrdiff_t
>(Page);
1016 auto last =
values.begin() +
static_cast<std::ptrdiff_t
>(Page + values_to);
1017 while (first != last) {
1018 *fill++ = hash_v<Hash>(*first++);
1023 for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1027 auto it = result.begin();
1028 auto last_value = (std::numeric_limits<switch_t>::min)();
1029 for (; fill != result.end(); *fill++ = last_value++) {
1030 while (last_value == *it) {
1039 template <
typename R,
typename F,
typename... Args>
1040 constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
1041 if constexpr (std::is_void_v<R>) {
1042 std::forward<F>(f)(std::forward<Args>(args)...);
1044 return static_cast<R
>(std::forward<F>(f)(std::forward<Args>(args)...));
1048 enum class case_call_t {
1053 template <
typename T =
void>
1054 inline constexpr
auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) {
return T{}; };
1059 template <auto* Arr,
typename Hash>
1060 constexpr
bool has_duplicate() noexcept {
1061 using value_t = std::decay_t<decltype((*Arr)[0])>;
1062 using hash_value_t = std::invoke_result_t<Hash, value_t>;
1063 std::array<hash_value_t, Arr->size()> hashes{};
1064 std::size_t size = 0;
1065 for (
auto elem : *Arr) {
1066 hashes[size] = hash_v<Hash>(elem);
1067 for (
auto i = size++; i > 0; --i) {
1068 if (hashes[i] < hashes[i - 1]) {
1069 auto tmp = hashes[i];
1070 hashes[i] = hashes[i - 1];
1071 hashes[i - 1] = tmp;
1072 }
else if (hashes[i] == hashes[i - 1]) {
1082 #define MAGIC_ENUM_CASE(val) \
1084 if constexpr ((val) + Page < size) { \
1085 if (!pred(values[val + Page], searched)) { \
1088 if constexpr (CallValue == case_call_t::index) { \
1089 if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1090 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1091 } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1092 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1094 } else if constexpr (CallValue == case_call_t::value) { \
1095 if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1096 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1097 } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1098 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1102 } else [[fallthrough]];
1104 template <
auto* GlobValues,
1105 case_call_t CallValue,
1106 std::size_t Page = 0,
1107 typename Hash = constexpr_hash_t<
typename std::decay_t<decltype(*GlobValues)>::value_type>,
1108 typename BinaryPredicate = std::equal_to<>,
1110 typename ResultGetterType>
1113 typename
std::decay_t<decltype(*GlobValues)>::value_type searched,
1114 ResultGetterType&& def,
1115 BinaryPredicate&& pred = {}) {
1116 using result_t = std::invoke_result_t<ResultGetterType>;
1117 using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash,
typename Hash::secondary_hash>;
1118 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.");
1119 constexpr std::array
values = *GlobValues;
1120 constexpr std::size_t size =
values.size();
1121 constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1123 switch (hash_v<hash_t>(searched)) {
1126 if constexpr (size > 256 + Page) {
1127 return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1134 #undef MAGIC_ENUM_CASE
1143 template <
typename T>
1148 template <
typename T>
1151 template <
typename T>
1156 template <
typename T>
1159 template <
typename T>
1164 template <
typename T>
1167 template <
typename T>
1174 template <
typename E>
1176 constexpr string_view name = detail::type_name_v<std::decay_t<E>>;
1177 static_assert(!name.empty(),
"magic_enum::enum_type_name enum type does not have a name.");
1183 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1185 return detail::count_v<std::decay_t<E>, S>;
1190 template <
typename E, 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.");
1195 if constexpr (detail::is_sparse_v<D, S>) {
1196 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
1200 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
1205 template <
typename E, std::
size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1207 using D = std::decay_t<E>;
1208 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1209 static_assert(I < detail::count_v<D, S>,
"magic_enum::enum_value out of range.");
1211 return enum_value<D, S>(I);
1215 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1217 using D = std::decay_t<E>;
1218 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1220 return detail::values_v<D, S>;
1224 template <
typename E>
1230 template <
typename E>
1237 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1239 using D = std::decay_t<E>;
1241 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1244 #if defined(MAGIC_ENUM_ENABLE_HASH)
1245 return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
1246 [](std::size_t i) {
return optional<std::size_t>{i}; },
1248 detail::default_result_type_lambda<optional<std::size_t>>);
1250 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1251 if (enum_value<D, S>(i) ==
value) {
1258 const auto v =
static_cast<U
>(
value);
1259 if (v >= detail::min_v<D, S> && v <= detail::max_v<D, S>) {
1260 return static_cast<std::size_t
>(v - detail::min_v<D, S>);
1268 template <detail::enum_subtype S,
typename E>
1269 [[nodiscard]] constexpr
auto enum_index(E
value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1270 using D = std::decay_t<E>;
1271 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1273 return enum_index<D, S>(
value);
1277 template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1279 using D = std::decay_t<decltype(V)>;
1280 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1281 constexpr
auto index = enum_index<D, S>(V);
1282 static_assert(index,
"magic_enum::enum_index enum value does not have a index.");
1292 static_assert(!name.empty(),
"magic_enum::enum_name enum value does not have a name.");
1299 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1301 using D = std::decay_t<E>;
1302 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1304 if (
const auto i = enum_index<D, S>(
value)) {
1305 return detail::names_v<D, S>[*i];
1312 template <detail::enum_subtype S,
typename E>
1313 [[nodiscard]] constexpr
auto enum_name(E
value) -> detail::enable_if_t<E, string_view> {
1314 using D = std::decay_t<E>;
1315 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1317 return enum_name<D, S>(
value);
1321 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1323 using D = std::decay_t<E>;
1324 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1326 return detail::names_v<D, S>;
1330 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1332 using D = std::decay_t<E>;
1333 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1335 return detail::entries_v<D, S>;
1343 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1345 using D = std::decay_t<E>;
1346 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1349 #if defined(MAGIC_ENUM_ENABLE_HASH)
1351 [](D v) {
return optional<D>{v}; },
1352 static_cast<D
>(
value),
1355 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1357 return static_cast<D
>(
value);
1363 if (
value >= detail::min_v<D, S> &&
value <= detail::max_v<D, S>) {
1364 return static_cast<D
>(
value);
1372 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1373 [[nodiscard]] constexpr
auto enum_cast(string_view
value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
1374 using D = std::decay_t<E>;
1375 static_assert(detail::is_reflected_v<D, S>,
"magic_enum requires enum implementation and valid max and min.");
1377 #if defined(MAGIC_ENUM_ENABLE_HASH)
1378 if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
1379 return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
1380 [](std::size_t i) {
return optional<D>{detail::values_v<D, S>[i]}; },
1382 detail::default_result_type_lambda<optional<D>>,
1383 [&p](string_view lhs, string_view rhs) {
return detail::cmp_equal(lhs, rhs, p); });
1386 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1388 return enum_value<D, S>(i);
1395 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1397 using D = std::decay_t<E>;
1400 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(
value)));
1404 template <detail::enum_subtype S,
typename E>
1405 [[nodiscard]] constexpr
auto enum_contains(E
value) noexcept -> detail::enable_if_t<E, bool> {
1406 using D = std::decay_t<E>;
1407 using U = underlying_type_t<D>;
1409 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(
value)));
1413 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1415 using D = std::decay_t<E>;
1417 return static_cast<bool>(enum_cast<D, S>(
value));
1421 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1422 [[nodiscard]] constexpr
auto enum_contains(string_view
value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
1423 using D = std::decay_t<E>;
1425 return static_cast<bool>(enum_cast<D, S>(
value, std::move(p)));
1429 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1431 using D = std::decay_t<E>;
1433 if constexpr (detail::is_reflected_v<D, S>) {
1434 constexpr
auto min = detail::reflected_min<E, S>();
1435 constexpr
auto max = detail::reflected_max<E, S>();
1443 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1445 using D = std::decay_t<E>;
1451 template <detail::enum_subtype S,
typename E>
1452 [[nodiscard]] constexpr
auto enum_reflected(E
value) noexcept -> detail::enable_if_t<E, bool> {
1453 using D = std::decay_t<E>;
1455 return enum_reflected<D, S>(
value);
1458 template <
bool AsFlags = true>
1461 template <
bool AsFlags = true>
1464 namespace bitwise_operators {
1466 template <
typename E, detail::enable_if_t<E,
int> = 0>
1468 return static_cast<E
>(~static_cast<underlying_type_t<E>>(rhs));
1471 template <
typename E, detail::enable_if_t<E,
int> = 0>
1476 template <
typename E, detail::enable_if_t<E,
int> = 0>
1481 template <
typename E, detail::enable_if_t<E,
int> = 0>
1486 template <
typename E, detail::enable_if_t<E,
int> = 0>
1488 return lhs = (lhs | rhs);
1491 template <
typename E, detail::enable_if_t<E,
int> = 0>
1493 return lhs = (lhs & rhs);
1496 template <
typename E, detail::enable_if_t<E,
int> = 0>
1498 return lhs = (lhs ^ rhs);
1505 #if defined(__clang__)
1506 # pragma clang diagnostic pop
1507 #elif defined(__GNUC__)
1508 # pragma GCC diagnostic pop
1509 #elif defined(_MSC_VER)
1510 # pragma warning(pop)
1513 #undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
1514 #undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
1515 #undef MAGIC_ENUM_VS_2017_WORKAROUND
1516 #undef MAGIC_ENUM_ARRAY_CONSTEXPR
1517 #undef MAGIC_ENUM_FOR_EACH_256
1519 #endif // NEARGYE_MAGIC_ENUM_HPP