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 3
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)
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 #elif defined(__GNUC__)
73 # pragma GCC diagnostic push
74 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
75 #elif defined(_MSC_VER)
76 # pragma warning(push)
77 # pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
78 # pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
79 # pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
80 # pragma warning(disable : 4514) // Unreferenced inline function has been removed.
84 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__)
85 # undef MAGIC_ENUM_SUPPORTED
86 # define MAGIC_ENUM_SUPPORTED 1
90 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
91 # undef MAGIC_ENUM_SUPPORTED_ALIASES
92 # define MAGIC_ENUM_SUPPORTED_ALIASES 1
97 #if !defined(MAGIC_ENUM_RANGE_MIN)
98 # define MAGIC_ENUM_RANGE_MIN -128
103 #if !defined(MAGIC_ENUM_RANGE_MAX)
104 # define MAGIC_ENUM_RANGE_MAX 127
108 #if defined(__RESHARPER__)
109 # undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
110 # undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
111 # if __RESHARPER__ >= 20230100
112 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V)
113 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name<T>()
115 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
116 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
123 #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
124 MAGIC_ENUM_USING_ALIAS_OPTIONAL
130 #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
131 MAGIC_ENUM_USING_ALIAS_STRING_VIEW
133 using std::string_view;
137 #if defined(MAGIC_ENUM_USING_ALIAS_STRING)
138 MAGIC_ENUM_USING_ALIAS_STRING
144 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");
146 if constexpr (std::is_same_v<char_type, wchar_t>) {
147 constexpr
const char c[] =
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
148 constexpr
const wchar_t wc[] = L
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
149 static_assert(std::size(
c) == std::size(wc),
"magic_enum::customize identifier characters are multichars in wchar_t.");
151 for (std::size_t i = 0; i < std::size(
c); ++i) {
158 } (),
"magic_enum::customize wchar_t is not compatible with ASCII.");
160 namespace customize {
165 template <
typename E>
167 static_assert(std::is_enum_v<E>,
"magic_enum::customize::enum_range requires enum type.");
170 static_assert(
max >
min,
"magic_enum::customize::enum_range requires max > min.");
186 class customize_t :
public std::pair<detail::customize_tag, string_view> {
201 template <
typename E>
207 template <
typename E>
216 template <
typename T>
218 #
if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
221 : std::false_type {};
224 template <auto V,
typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>,
int> = 0>
227 template <
typename...
T>
230 template <
typename T,
typename =
void>
233 template <
typename T>
234 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)>>> {};
236 template <
typename T,
typename =
void>
237 struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
239 template <
typename T>
240 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> {};
242 template <
typename T,
typename =
void>
243 struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
245 template <
typename T>
246 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> {};
253 template <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 {}; }
296 template <
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;
331 template <
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<>>;
337 template <
typename BinaryPredicate>
339 return is_default_predicate<BinaryPredicate>() ||
340 std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
343 template <
typename BinaryPredicate>
344 constexpr
bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable<BinaryPredicate>()) {
345 #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
348 constexpr
bool workaround =
true;
350 constexpr
bool workaround =
false;
353 if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {
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])) {
371 template <
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;
391 template <
typename I>
393 static_assert(std::is_integral_v<I>,
"magic_enum::detail::log2 requires integral type.");
395 if constexpr (std::is_same_v<I, bool>) {
405 #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
406 # define MAGIC_ENUM_ARRAY_CONSTEXPR 1
408 template <
typename T, std::size_t N, std::size_t... I>
409 constexpr std::array<std::remove_cv_t<T>, N>
to_array(
T (&
a)[N], std::index_sequence<I...>) noexcept {
414 template <
typename T>
415 inline constexpr
bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
417 template <
typename E>
418 constexpr
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] ==
':') {
458 template <
typename E>
460 [[maybe_unused]] constexpr
auto custom = customize::enum_type_name<E>();
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>();
472 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
476 template <
typename E>
480 constexpr
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};
514 auto name = str_view{};
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)
538 template <
typename E, E V>
539 constexpr
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{};
546 str_view name = str_view{__FUNCSIG__,
sizeof(__FUNCSIG__) - 17};
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')) {
566 template <
typename E, E V>
568 [[maybe_unused]] constexpr
auto custom = customize::enum_name<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>();
584 static_assert(always_false_v<E>,
"magic_enum::customize invalid.");
588 template <
typename E, E V>
591 template <
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);
599 [[maybe_unused]] constexpr
auto custom = customize::enum_name<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)
607 return n<E, v>().size_ != 0;
609 return n<v>().size_ != 0;
621 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
622 constexpr 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);
634 template <
typename E,
int O, enum_subtype S,
typename U = std::underlying_type_t<E>>
635 constexpr E
value(std::size_t i) noexcept {
636 return static_cast<E
>(ualue<E, O, S>(i));
639 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
655 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
658 return std::numeric_limits<U>::digits - 1;
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)
681 template <
typename E, enum_subtype S, std::
size_t Size,
int Min, std::
size_t I>
682 constexpr
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) {
694 valid_count<E, S, Size, Min, I + 256>(valid, count);
699 template <std::
size_t N>
705 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
708 valid_count<E, S, Size, Min, 0>(vc.
valid, vc.
count);
712 template <
typename E, enum_subtype S, std::
size_t Size,
int Min>
714 constexpr
auto vc = valid_count<E, S, Size, 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) {
724 values[
v++] = value<E, Min, S>(i);
727 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
733 return std::array<E, 0>{};
737 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
739 constexpr
auto min = reflected_min<E, S>();
740 constexpr
auto max = reflected_max<E, S>();
741 constexpr
auto range_size =
max -
min + 1;
742 static_assert(range_size > 0,
"magic_enum::enum_range requires valid size.");
745 return values<E, S, range_size, min>();
748 template <
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)
756 constexpr
auto flags_values = values<E, enum_subtype::flags>();
757 constexpr
auto default_values = values<E, enum_subtype::common>();
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) {
774 template <
typename T>
780 template <
typename E,
typename D = std::decay_t<E>>
781 inline constexpr
auto subtype_v = subtype<D>(std::is_enum<D>{});
783 template <
typename E, enum_subtype S>
786 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
789 template <
typename E, enum_subtype S>
790 inline constexpr
auto count_v = values_v<E, S>.size();
792 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
793 inline constexpr
auto min_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.front()) : U{0};
795 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
796 inline constexpr
auto max_v = (count_v<E, S> > 0) ?
static_cast<U
>(values_v<E, S>.back()) : U{0};
799 constexpr
auto names(std::index_sequence<I...>) noexcept {
800 return std::array<string_view,
sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
803 template <
typename E, enum_subtype S>
804 inline constexpr
auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
806 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
810 constexpr
auto entries(std::index_sequence<I...>) noexcept {
811 return std::array<std::pair<E, string_view>,
sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
814 template <
typename E, enum_subtype S>
815 inline constexpr
auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
817 template <
typename E, enum_subtype S,
typename D = std::decay_t<E>>
820 template <
typename E, enum_subtype S,
typename U = std::underlying_type_t<E>>
822 if constexpr (count_v<E, S> == 0) {
824 }
else if constexpr (std::is_same_v<U, bool>) {
829 constexpr
auto range_size =
max -
min + 1;
831 return range_size != count_v<E, S>;
835 template <
typename E, enum_subtype S = subtype_v<E>>
838 template <
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) {
844 ors |=
static_cast<U
>(values_v<E, S>[i]);
850 template <
bool,
typename R>
853 template <
typename R>
856 static_assert(
supported<R>::value,
"magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
859 template <
typename T,
typename R,
typename BinaryPredicate = std::equal_to<>,
typename D = std::decay_t<T>>
862 template <
typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>,
int> = 0>
865 template <
typename T,
bool = std::is_enum_v<T>>
868 template <
typename T>
869 struct is_scoped_enum<
T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
871 template <
typename T,
bool = std::is_enum_v<T>>
874 template <
typename T>
875 struct is_unscoped_enum<
T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
877 template <
typename T,
bool = std::is_enum_v<std::decay_t<T>>>
880 template <
typename T>
883 #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
885 template <
typename Value,
typename =
void>
886 struct constexpr_hash_t;
888 template <
typename 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;
901 template <
typename Value>
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) {
951 return static_cast<std::uint32_t
>(acc);
956 template <
typename Hash>
957 inline constexpr Hash hash_v{};
959 template <auto* GlobValues,
typename Hash>
960 constexpr
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++);
983 auto it = result.begin();
985 for (; fill != result.end(); *fill++ = last_value++) {
986 while (last_value == *it) {
995 template <
typename R,
typename F,
typename... Args>
996 constexpr 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)...));
1004 enum class case_call_t {
1009 template <
typename T =
void>
1010 inline constexpr
auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) {
return T{}; };
1013 inline constexpr
auto default_result_type_lambda<void> = []() noexcept {};
1015 template <auto* Arr,
typename Hash>
1016 constexpr
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]];
1060 template <
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>
1067 constexpr 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
1099 template <
typename T>
1104 template <
typename T>
1107 template <
typename T>
1112 template <
typename T>
1115 template <
typename T>
1120 template <
typename T>
1123 template <
typename T>
1130 template <
typename E>
1132 constexpr string_view name = detail::type_name_v<std::decay_t<E>>;
1133 static_assert(!name.empty(),
"magic_enum::enum_type_name enum type does not have a name.");
1139 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1141 return detail::count_v<std::decay_t<E>, S>;
1146 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1148 using D = std::decay_t<E>;
1150 if constexpr (detail::is_sparse_v<D, S>) {
1160 template <
typename E, std::
size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1162 using D = std::decay_t<E>;
1163 static_assert(I < detail::count_v<D, S>,
"magic_enum::enum_value out of range.");
1165 return enum_value<D, S>(I);
1169 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1171 return detail::values_v<std::decay_t<E>, S>;
1175 template <
typename E>
1181 template <
typename E>
1188 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1190 using D = std::decay_t<E>;
1193 if constexpr (detail::count_v<D, S> == 0) {
1194 static_cast<void>(
value);
1197 #if defined(MAGIC_ENUM_ENABLE_HASH)
1199 [](std::size_t i) {
return optional<std::size_t>{i}; },
1201 detail::default_result_type_lambda<optional<std::size_t>>);
1203 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1204 if (enum_value<D, S>(i) ==
value) {
1211 const auto v =
static_cast<U
>(
value);
1212 if (
v >= detail::min_v<D, S> &&
v <= detail::max_v<D, S>) {
1213 return static_cast<std::size_t
>(
v - detail::min_v<D, S>);
1221 template <detail::enum_subtype S,
typename E>
1222 [[nodiscard]] constexpr
auto enum_index(E
value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1223 using D = std::decay_t<E>;
1225 return enum_index<D, S>(
value);
1229 template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1232 static_assert(
index,
"magic_enum::enum_index enum value does not have a index.");
1242 static_assert(!name.empty(),
"magic_enum::enum_name enum value does not have a name.");
1249 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1251 using D = std::decay_t<E>;
1253 if (
const auto i = enum_index<D, S>(
value)) {
1254 return detail::names_v<D, S>[*i];
1261 template <detail::enum_subtype S,
typename E>
1262 [[nodiscard]] constexpr
auto enum_name(E
value) -> detail::enable_if_t<E, string_view> {
1263 using D = std::decay_t<E>;
1265 return enum_name<D, S>(
value);
1269 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1271 return detail::names_v<std::decay_t<E>, S>;
1275 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1277 return detail::entries_v<std::decay_t<E>, S>;
1285 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1287 using D = std::decay_t<E>;
1289 if constexpr (detail::count_v<D, S> == 0) {
1290 static_cast<void>(
value);
1294 #if defined(MAGIC_ENUM_ENABLE_HASH)
1296 [](D
v) {
return optional<D>{
v}; },
1297 static_cast<D
>(
value),
1298 detail::default_result_type_lambda<optional<D>>);
1300 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1302 return static_cast<D
>(
value);
1308 if (
value >= detail::min_v<D, S> &&
value <= detail::max_v<D, S>) {
1309 return static_cast<D
>(
value);
1318 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1319 [[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> {
1320 using D = std::decay_t<E>;
1322 if constexpr (detail::count_v<D, S> == 0) {
1323 static_cast<void>(
value);
1325 #if defined(MAGIC_ENUM_ENABLE_HASH)
1326 }
else if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
1328 [](std::size_t i) {
return optional<D>{detail::values_v<D, S>[i]}; },
1330 detail::default_result_type_lambda<optional<D>>,
1331 [&p](string_view lhs, string_view rhs) {
return detail::cmp_equal(lhs, rhs, p); });
1334 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1336 return enum_value<D, S>(i);
1344 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1346 using D = std::decay_t<E>;
1349 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(
value)));
1353 template <detail::enum_subtype S,
typename E>
1354 [[nodiscard]] constexpr
auto enum_contains(E
value) noexcept -> detail::enable_if_t<E, bool> {
1355 using D = std::decay_t<E>;
1356 using U = underlying_type_t<D>;
1358 return static_cast<bool>(enum_cast<D, S>(
static_cast<U
>(
value)));
1362 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>>
1364 using D = std::decay_t<E>;
1366 return static_cast<bool>(enum_cast<D, S>(
value));
1370 template <
typename E, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>>
1371 [[nodiscard]] constexpr
auto enum_contains(string_view
value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
1372 using D = std::decay_t<E>;
1374 return static_cast<bool>(enum_cast<D, S>(
value, std::move(p)));
1377 template <
bool AsFlags = true>
1380 template <
bool AsFlags = true>
1383 namespace bitwise_operators {
1385 template <
typename E, detail::enable_if_t<E,
int> = 0>
1387 return static_cast<E
>(~static_cast<underlying_type_t<E>>(rhs));
1390 template <
typename E, detail::enable_if_t<E,
int> = 0>
1395 template <
typename E, detail::enable_if_t<E,
int> = 0>
1400 template <
typename E, detail::enable_if_t<E,
int> = 0>
1405 template <
typename E, detail::enable_if_t<E,
int> = 0>
1407 return lhs = (lhs | rhs);
1410 template <
typename E, detail::enable_if_t<E,
int> = 0>
1412 return lhs = (lhs & rhs);
1415 template <
typename E, detail::enable_if_t<E,
int> = 0>
1417 return lhs = (lhs ^ rhs);
1424 #if defined(__clang__)
1425 # pragma clang diagnostic pop
1426 #elif defined(__GNUC__)
1427 # pragma GCC diagnostic pop
1428 #elif defined(_MSC_VER)
1429 # pragma warning(pop)
1432 #undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
1433 #undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
1434 #undef MAGIC_ENUM_VS_2017_WORKAROUND
1435 #undef MAGIC_ENUM_ARRAY_CONSTEXPR
1436 #undef MAGIC_ENUM_FOR_EACH_256
1438 #endif // NEARGYE_MAGIC_ENUM_HPP