magic_enum.hpp
Go to the documentation of this file.
1 // __ __ _ ______ _____
2 // | \/ | (_) | ____| / ____|_ _
3 // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
4 // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
5 // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
6 // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
7 // __/ | https://github.com/Neargye/magic_enum
8 // |___/ version 0.9.7
9 //
10 // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
11 // SPDX-License-Identifier: MIT
12 // Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to deal
16 // in the Software without restriction, including without limitation the rights
17 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 // copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included in all
22 // copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 
32 #ifndef NEARGYE_MAGIC_ENUM_HPP
33 #define NEARGYE_MAGIC_ENUM_HPP
34 
35 #define MAGIC_ENUM_VERSION_MAJOR 0
36 #define MAGIC_ENUM_VERSION_MINOR 9
37 #define MAGIC_ENUM_VERSION_PATCH 7
38 
39 #ifndef MAGIC_ENUM_USE_STD_MODULE
40 #include <array>
41 #include <cstddef>
42 #include <cstdint>
43 #include <functional>
44 #include <limits>
45 #include <type_traits>
46 #include <utility>
47 #endif
48 
49 #if defined(MAGIC_ENUM_CONFIG_FILE)
50 # include MAGIC_ENUM_CONFIG_FILE
51 #endif
52 
53 #ifndef MAGIC_ENUM_USE_STD_MODULE
54 #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
55 # include <optional>
56 #endif
57 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING)
58 # include <string>
59 #endif
60 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
61 # include <string_view>
62 #endif
63 #endif
64 
65 #if defined(MAGIC_ENUM_NO_ASSERT)
66 # define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
67 #elif !defined(MAGIC_ENUM_ASSERT)
68 # include <cassert>
69 # define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
70 #endif
71 
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.
87 #endif
88 
89 // Checks magic_enum compiler compatibility.
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
93 #endif
94 
95 // Checks magic_enum compiler aliases compatibility.
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
99 #endif
100 
101 // Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128.
102 // If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN.
103 #if !defined(MAGIC_ENUM_RANGE_MIN)
104 # define MAGIC_ENUM_RANGE_MIN -128
105 #endif
106 
107 // Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 127.
108 // If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.
109 #if !defined(MAGIC_ENUM_RANGE_MAX)
110 # define MAGIC_ENUM_RANGE_MAX 127
111 #endif
112 
113 // Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations.
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>()
120 # else
121 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
122 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
123 # endif
124 #endif
125 
126 namespace magic_enum {
127 
128 // If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.
129 #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
131 #else
132 using std::optional;
133 #endif
134 
135 // If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW.
136 #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
138 #else
139 using std::string_view;
140 #endif
141 
142 // If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING.
143 #if defined(MAGIC_ENUM_USING_ALIAS_STRING)
145 #else
146 using std::string;
147 #endif
148 
149 using char_type = string_view::value_type;
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");
151 static_assert([] {
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.");
156 
157  for (std::size_t i = 0; i < std::size(c); ++i) {
158  if (c[i] != wc[i]) {
159  return false;
160  }
161  }
162  }
163  return true;
164 } (), "magic_enum::customize wchar_t is not compatible with ASCII.");
165 
166 namespace customize {
167 
168 // Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 127.
169 // If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.
170 // If need another range for specific enum type, add specialization enum_range for necessary enum type.
171 template <typename E>
172 struct enum_range {
173  static constexpr int min = MAGIC_ENUM_RANGE_MIN;
174  static constexpr int max = MAGIC_ENUM_RANGE_MAX;
175 };
176 
177 static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
178 
179 namespace detail {
180 
181 enum class customize_tag {
182  default_tag,
183  invalid_tag,
184  custom_tag
185 };
186 
187 } // namespace magic_enum::customize::detail
188 
189 class customize_t : public std::pair<detail::customize_tag, string_view> {
190  public:
191  constexpr customize_t(string_view srt) : std::pair<detail::customize_tag, string_view>{detail::customize_tag::custom_tag, srt} {}
192  constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {}
193  constexpr customize_t(detail::customize_tag tag) : std::pair<detail::customize_tag, string_view>{tag, string_view{}} {
195  }
196 };
197 
198 // Default customize.
200 // Invalid customize.
202 
203 // If need custom names for enum, add specialization enum_name for necessary enum type.
204 template <typename E>
205 constexpr customize_t enum_name(E) noexcept {
206  return default_tag;
207 }
208 
209 // If need custom type name for enum, add specialization enum_type_name for necessary enum type.
210 template <typename E>
211 constexpr customize_t enum_type_name() noexcept {
212  return default_tag;
213 }
214 
215 } // namespace magic_enum::customize
216 
217 namespace detail {
218 
219 template <typename T>
220 struct supported
221 #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
222  : std::true_type {};
223 #else
224  : std::false_type {};
225 #endif
226 
227 template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
228 using enum_constant = std::integral_constant<E, V>;
229 
230 template <typename... T>
231 inline constexpr bool always_false_v = false;
232 
233 template <typename T, typename = void>
234 struct has_is_flags : std::false_type {};
235 
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)>>> {};
238 
239 template <typename T, typename = void>
240 struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
241 
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> {};
244 
245 template <typename T, typename = void>
246 struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
247 
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> {};
250 
251 struct str_view {
252  const char* str_ = nullptr;
253  std::size_t size_ = 0;
254 };
255 
256 template <std::uint16_t N>
257 class static_str {
258  public:
259  constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence<std::uint16_t, N>{}} {
260  MAGIC_ENUM_ASSERT(str.size_ == N);
261  }
262 
263  constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence<std::uint16_t, N>{}} {
264  MAGIC_ENUM_ASSERT(str.size() == N);
265  }
266 
267  constexpr const char_type* data() const noexcept { return chars_; }
268 
269  constexpr std::uint16_t size() const noexcept { return N; }
270 
271  constexpr operator string_view() const noexcept { return {data(), size()}; }
272 
273  private:
274  template <std::uint16_t... I>
275  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')} {}
276 
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')} {}
279 
280  char_type chars_[static_cast<std::size_t>(N) + 1];
281 };
282 
283 template <>
284 class static_str<0> {
285  public:
286  constexpr explicit static_str() = default;
287 
288  constexpr explicit static_str(str_view) noexcept {}
289 
290  constexpr explicit static_str(string_view) noexcept {}
291 
292  constexpr const char_type* data() const noexcept { return nullptr; }
293 
294  constexpr std::uint16_t size() const noexcept { return 0; }
295 
296  constexpr operator string_view() const noexcept { return {}; }
297 };
298 
299 template <typename Op = std::equal_to<>>
301  static constexpr char_type to_lower(char_type c) noexcept {
302  return (c >= static_cast<char_type>('A') && c <= static_cast<char_type>('Z')) ? static_cast<char_type>(c + (static_cast<char_type>('a') - static_cast<char_type>('A'))) : c;
303  }
304 
305  public:
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> {
308  return Op{}(to_lower(lhs), to_lower(rhs));
309  }
310 };
311 
312 constexpr std::size_t find(string_view str, char_type c) noexcept {
313 #if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
314 // https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc
315 // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
316  constexpr bool workaround = true;
317 #else
318  constexpr bool workaround = false;
319 #endif
320 
321  if constexpr (workaround) {
322  for (std::size_t i = 0; i < str.size(); ++i) {
323  if (str[i] == c) {
324  return i;
325  }
326  }
327 
328  return string_view::npos;
329  } else {
330  return str.find(c);
331  }
332 }
333 
334 template <typename BinaryPredicate>
335 constexpr bool is_default_predicate() noexcept {
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<>>;
338 }
339 
340 template <typename BinaryPredicate>
341 constexpr bool is_nothrow_invocable() {
342  return is_default_predicate<BinaryPredicate>() ||
343  std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
344 }
345 
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__)
349  // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
350  // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
351  constexpr bool workaround = true;
352 #else
353  constexpr bool workaround = false;
354 #endif
355 
356  if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {
357  if (lhs.size() != rhs.size()) {
358  return false;
359  }
360 
361  const auto size = lhs.size();
362  for (std::size_t i = 0; i < size; ++i) {
363  if (!p(lhs[i], rhs[i])) {
364  return false;
365  }
366  }
367 
368  return true;
369  } else {
370  return lhs == rhs;
371  }
372 }
373 
374 template <typename L, typename R>
375 constexpr bool cmp_less(L lhs, R rhs) noexcept {
376  static_assert(std::is_integral_v<L> && std::is_integral_v<R>, "magic_enum::detail::cmp_less requires integral type.");
377 
378  if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
379  // If same signedness (both signed or both unsigned).
380  return lhs < rhs;
381  } else if constexpr (std::is_same_v<L, bool>) { // bool special case
382  return static_cast<R>(lhs) < rhs;
383  } else if constexpr (std::is_same_v<R, bool>) { // bool special case
384  return lhs < static_cast<L>(rhs);
385  } else if constexpr (std::is_signed_v<R>) {
386  // If 'right' is negative, then result is 'false', otherwise cast & compare.
387  return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);
388  } else {
389  // If 'left' is negative, then result is 'true', otherwise cast & compare.
390  return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;
391  }
392 }
393 
394 template <typename I>
395 constexpr I log2(I value) noexcept {
396  static_assert(std::is_integral_v<I>, "magic_enum::detail::log2 requires integral type.");
397 
398  if constexpr (std::is_same_v<I, bool>) { // bool special case
399  return MAGIC_ENUM_ASSERT(false), value;
400  } else {
401  auto ret = I{0};
402  for (; value > I{1}; value >>= I{1}, ++ret) {}
403 
404  return ret;
405  }
406 }
407 
408 #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
409 # define MAGIC_ENUM_ARRAY_CONSTEXPR 1
410 #else
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 {
413  return {{a[I]...}};
414 }
415 #endif
416 
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>>;
419 
420 template <typename E>
421 constexpr auto n() noexcept {
422  static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
423 
424  if constexpr (supported<E>::value) {
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__)
429  str_view name;
430  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
431  static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
432  return str_view{};
433  } else {
434  name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
435  name.str_ = __PRETTY_FUNCTION__ + 34;
436  }
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__.");
441  return str_view{};
442  } else if (name.str_[name.size_ - 1] == ']') {
443  name.size_ -= 50;
444  name.str_ += 49;
445  } else {
446  name.size_ -= 40;
447  name.str_ += 37;
448  }
449 #elif defined(_MSC_VER)
450  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
451  str_view name;
452  name.str_ = __FUNCSIG__;
453  name.str_ += 40;
454  name.size_ += sizeof(__FUNCSIG__) - 57;
455 #else
456  auto name = str_view{};
457 #endif
458  std::size_t p = 0;
459  for (std::size_t i = name.size_; i > 0; --i) {
460  if (name.str_[i] == ':') {
461  p = i + 1;
462  break;
463  }
464  }
465  if (p > 0) {
466  name.size_ -= p;
467  name.str_ += p;
468  }
469  return name;
470  } else {
471  return str_view{}; // Unsupported compiler or Invalid customize.
472  }
473 }
474 
475 template <typename E>
476 constexpr auto type_name() noexcept {
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.");
479  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
480  constexpr auto name = custom.second;
481  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
482  return static_str<name.size()>{name};
483  } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
484  return static_str<0>{};
485  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
486  constexpr auto name = n<E>();
487  return static_str<name.size_>{name};
488  } else {
489  static_assert(always_false_v<E>, "magic_enum::customize invalid.");
490  }
491 }
492 
493 template <typename E>
494 inline constexpr auto type_name_v = type_name<E>();
495 
496 template <auto V>
497 constexpr auto n() noexcept {
498  static_assert(is_enum_v<decltype(V)>, "magic_enum::detail::n requires enum type.");
499 
500  if constexpr (supported<decltype(V)>::value) {
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__)
505  str_view name;
506  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
507  static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
508  return str_view{};
509  } else {
510  name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
511  name.str_ = __PRETTY_FUNCTION__ + 34;
512  }
513  if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') {
514  name.size_ -= 23;
515  name.str_ += 23;
516  }
517  if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
518  name = str_view{};
519  }
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__.");
524  return str_view{};
525  } else if (name.str_[name.size_ - 1] == ']') {
526  name.size_ -= 55;
527  name.str_ += 54;
528  } else {
529  name.size_ -= 40;
530  name.str_ += 37;
531  }
532  if (name.str_[0] == '(') {
533  name = str_view{};
534  }
535 #elif defined(_MSC_VER)
536  str_view name;
537  if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) {
538  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
539  name.str_ = __FUNCSIG__;
540  name.str_ += 35;
541  name.size_ = sizeof(__FUNCSIG__) - 52;
542  }
543 #else
544  auto name = str_view{};
545 #endif
546  std::size_t p = 0;
547  for (std::size_t i = name.size_; i > 0; --i) {
548  if (name.str_[i] == ':') {
549  p = i + 1;
550  break;
551  }
552  }
553  if (p > 0) {
554  name.size_ -= p;
555  name.str_ += p;
556  }
557  return name;
558  } else {
559  return str_view{}; // Unsupported compiler or Invalid customize.
560  }
561 }
562 
563 #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
564 # define MAGIC_ENUM_VS_2017_WORKAROUND 1
565 #endif
566 
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.");
571 
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{};
575 # else
576  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
577  str_view name;
578  name.str_ = __FUNCSIG__;
579  name.size_ = sizeof(__FUNCSIG__) - 17;
580  std::size_t p = 0;
581  for (std::size_t i = name.size_; i > 0; --i) {
582  if (name.str_[i] == ',' || name.str_[i] == ':') {
583  p = i + 1;
584  break;
585  }
586  }
587  if (p > 0) {
588  name.size_ -= p;
589  name.str_ += p;
590  }
591  if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
592  name = str_view{};
593  }
594  return name;
595 # endif
596 }
597 #endif
598 
599 template <typename E, E V>
600 constexpr auto enum_name() noexcept {
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.");
603  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
604  constexpr auto name = custom.second;
605  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
606  return static_str<name.size()>{name};
607  } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
608  return static_str<0>{};
609  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
610 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
611  constexpr auto name = n<E, V>();
612 #else
613  constexpr auto name = n<V>();
614 #endif
615  return static_str<name.size_>{name};
616  } else {
617  static_assert(always_false_v<E>, "magic_enum::customize invalid.");
618  }
619 }
620 
621 template <typename E, E V>
622 inline constexpr auto enum_name_v = enum_name<E, V>();
623 
624 // CWG1766: Values outside the range of the values of an enumeration
625 // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
626 #if defined(__clang__) && __clang_major__ >= 16
627 template <typename E, auto V, typename = void>
628 inline constexpr bool is_enum_constexpr_static_cast_valid = false;
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;
631 #else
632 template <typename, auto>
633 inline constexpr bool is_enum_constexpr_static_cast_valid = true;
634 #endif
635 
636 template <typename E, auto V>
637 constexpr bool is_valid() noexcept {
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.");
642  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
643  constexpr auto name = custom.second;
644  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
645  return name.size() != 0;
646  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
647 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
648  return n<E, v>().size_ != 0;
649 #else
650  return n<v>().size_ != 0;
651 #endif
652  } else {
653  return false;
654  }
655  } else {
656  return false;
657  }
658 }
659 
660 enum class enum_subtype {
661  common,
662  flags
663 };
664 
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>) { // bool special case
668  static_assert(O == 0, "magic_enum::detail::ualue requires valid offset.");
669 
670  return static_cast<U>(i);
671  } else if constexpr (S == enum_subtype::flags) {
672  return static_cast<U>(U{1} << static_cast<U>(static_cast<int>(i) + O));
673  } else {
674  return static_cast<U>(static_cast<int>(i) + O);
675  }
676 }
677 
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));
681 }
682 
683 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
684 constexpr int reflected_min() noexcept {
685  if constexpr (S == enum_subtype::flags) {
686  return 0;
687  } else {
688  constexpr auto lhs = range_min<E>::value;
689  constexpr auto rhs = (std::numeric_limits<U>::min)();
690 
691  if constexpr (cmp_less(rhs, lhs)) {
692  return lhs;
693  } else {
694  return rhs;
695  }
696  }
697 }
698 
699 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
700 constexpr int reflected_max() noexcept {
701  if constexpr (S == enum_subtype::flags) {
702  return std::numeric_limits<U>::digits - 1;
703  } else {
704  constexpr auto lhs = range_max<E>::value;
705  constexpr auto rhs = (std::numeric_limits<U>::max)();
706 
707  if constexpr (cmp_less(lhs, rhs)) {
708  return lhs;
709  } else {
710  return rhs;
711  }
712  }
713 }
714 
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)
724 
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; \
731  ++count; \
732  } \
733  }
734 
736 
737  if constexpr ((I + 256) < Size) {
738  valid_count<E, S, Size, Min, I + 256>(valid, count);
739  }
740 #undef MAGIC_ENUM_V
741 }
742 
743 template <std::size_t N>
745  std::size_t count = 0;
746  bool valid[N] = {};
747 };
748 
749 template <typename E, enum_subtype S, std::size_t Size, int Min>
750 constexpr auto valid_count() noexcept {
752  valid_count<E, S, Size, Min, 0>(vc.valid, vc.count);
753  return vc;
754 }
755 
756 template <typename E, enum_subtype S, std::size_t Size, int Min>
757 constexpr auto values() noexcept {
758  constexpr auto vc = valid_count<E, S, Size, Min>();
759 
760  if constexpr (vc.count > 0) {
761 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
762  std::array<E, vc.count> values = {};
763 #else
764  E values[vc.count] = {};
765 #endif
766  for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
767  if (vc.valid[i]) {
768  values[v++] = value<E, Min, S>(i);
769  }
770  }
771 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
772  return values;
773 #else
774  return to_array(values, std::make_index_sequence<vc.count>{});
775 #endif
776  } else {
777  return std::array<E, 0>{};
778  }
779 }
780 
781 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
782 constexpr auto values() noexcept {
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.");
787 
788  return values<E, S, range_size, min>();
789 }
790 
791 template <typename E, typename U = std::underlying_type_t<E>>
792 constexpr enum_subtype subtype(std::true_type) noexcept {
793  if constexpr (std::is_same_v<U, bool>) { // bool special case
794  return enum_subtype::common;
795  } else if constexpr (has_is_flags<E>::value) {
797  } else {
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()) {
802  return enum_subtype::common;
803  }
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) {
807  return enum_subtype::common;
808  }
809  }
810  return enum_subtype::flags;
811 #else
812  return enum_subtype::common;
813 #endif
814  }
815 }
816 
817 template <typename T>
818 constexpr enum_subtype subtype(std::false_type) noexcept {
819  // For non-enum type return default common subtype.
820  return enum_subtype::common;
821 }
822 
823 template <typename E, typename D = std::decay_t<E>>
824 inline constexpr auto subtype_v = subtype<D>(std::is_enum<D>{});
825 
826 template <typename E, enum_subtype S>
827 inline constexpr auto values_v = values<E, S>();
828 
829 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
830 using values_t = decltype((values_v<D, S>));
831 
832 template <typename E, enum_subtype S>
833 inline constexpr auto count_v = values_v<E, S>.size();
834 
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};
837 
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};
840 
841 template <typename E, enum_subtype S, std::size_t... I>
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]>...}};
844  return names;
845 }
846 
847 template <typename E, enum_subtype S>
848 inline constexpr auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
849 
850 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
851 using names_t = decltype((names_v<D, S>));
852 
853 template <typename E, enum_subtype S, std::size_t... I>
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]>}...}};
856  return entries;
857 }
858 
859 template <typename E, enum_subtype S>
860 inline constexpr auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
861 
862 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
863 using entries_t = decltype((entries_v<D, S>));
864 
865 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
866 constexpr bool is_sparse() noexcept {
867  if constexpr (count_v<E, S> == 0) {
868  return false;
869  } else if constexpr (std::is_same_v<U, bool>) { // bool special case
870  return false;
871  } else {
872  constexpr auto max = (S == enum_subtype::flags) ? log2(max_v<E, S>) : max_v<E, S>;
873  constexpr auto min = (S == enum_subtype::flags) ? log2(min_v<E, S>) : min_v<E, S>;
874  constexpr auto range_size = max - min + 1;
875 
876  return range_size != count_v<E, S>;
877  }
878 }
879 
880 template <typename E, enum_subtype S = subtype_v<E>>
881 inline constexpr bool is_sparse_v = is_sparse<E, S>();
882 
883 template <typename E, enum_subtype S>
886  : std::true_type {};
887 #else
888  : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
889 #endif
890 
891 template <typename E, enum_subtype S>
892 inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};
893 
894 template <bool, typename R>
895 struct enable_if_enum {};
896 
897 template <typename R>
898 struct enable_if_enum<true, R> {
899  using type = R;
900  static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
901 };
902 
903 template <typename T, typename R, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
904 using enable_if_t = typename enable_if_enum<std::is_enum_v<D> && std::is_invocable_r_v<bool, BinaryPredicate, char_type, char_type>, R>::type;
905 
906 template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
907 using enum_concept = T;
908 
909 template <typename T, bool = std::is_enum_v<T>>
910 struct is_scoped_enum : std::false_type {};
911 
912 template <typename T>
913 struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
914 
915 template <typename T, bool = std::is_enum_v<T>>
916 struct is_unscoped_enum : std::false_type {};
917 
918 template <typename T>
919 struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
920 
921 template <typename T, bool = std::is_enum_v<std::decay_t<T>>>
922 struct underlying_type {};
923 
924 template <typename T>
925 struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
926 
927 #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
928 
929 template <typename Value, typename = void>
930 struct constexpr_hash_t;
931 
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 {
935  using U = typename underlying_type<Value>::type;
936  if constexpr (std::is_same_v<U, bool>) { // bool special case
937  return static_cast<std::size_t>(value);
938  } else {
939  return static_cast<U>(value);
940  }
941  }
942  using secondary_hash = constexpr_hash_t;
943 };
944 
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
980  };
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];
985  }
986  return crc ^ 0xffffffffL;
987  }
988 
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)();
994  }
995  return static_cast<std::uint32_t>(acc);
996  }
997  };
998 };
999 
1000 template <typename Hash>
1001 inline constexpr Hash hash_v{};
1002 
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();
1007 
1008  using switch_t = std::invoke_result_t<Hash, typename decltype(values)::value_type>;
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);
1011 
1012  std::array<switch_t, 256> result{};
1013  auto fill = result.begin();
1014  {
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++);
1019  }
1020  }
1021 
1022  // dead cases, try to avoid case collisions
1023  for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1024  }
1025 
1026  {
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) {
1031  ++last_value, ++it;
1032  }
1033  }
1034  }
1035 
1036  return result;
1037 }
1038 
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)...);
1043  } else {
1044  return static_cast<R>(std::forward<F>(f)(std::forward<Args>(args)...));
1045  }
1046 }
1047 
1048 enum class case_call_t {
1049  index,
1050  value
1051 };
1052 
1053 template <typename T = void>
1054 inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
1055 
1056 template <>
1057 inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
1058 
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]) {
1073  return false;
1074  } else {
1075  break;
1076  }
1077  }
1078  }
1079  return true;
1080 }
1081 
1082 #define MAGIC_ENUM_CASE(val) \
1083  case cases[val]: \
1084  if constexpr ((val) + Page < size) { \
1085  if (!pred(values[val + Page], searched)) { \
1086  break; \
1087  } \
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."); \
1093  } \
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."); \
1099  } \
1100  } \
1101  break; \
1102  } else [[fallthrough]];
1103 
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<>,
1109  typename Lambda,
1110  typename ResultGetterType>
1111 constexpr decltype(auto) constexpr_switch(
1112  Lambda&& lambda,
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);
1122 
1123  switch (hash_v<hash_t>(searched)) {
1124  MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE)
1125  default:
1126  if constexpr (size > 256 + Page) {
1127  return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1128  }
1129  break;
1130  }
1131  return def();
1132 }
1133 
1134 #undef MAGIC_ENUM_CASE
1135 
1136 #endif
1137 
1138 } // namespace magic_enum::detail
1139 
1140 // Checks is magic_enum supported compiler.
1142 
1143 template <typename T>
1145 
1146 // Checks whether T is an Unscoped enumeration type.
1147 // Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false.
1148 template <typename T>
1150 
1151 template <typename T>
1153 
1154 // Checks whether T is an Scoped enumeration type.
1155 // Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false.
1156 template <typename T>
1158 
1159 template <typename T>
1161 
1162 // If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.
1163 // Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed.
1164 template <typename T>
1166 
1167 template <typename T>
1169 
1170 template <auto V>
1172 
1173 // Returns type name of enum.
1174 template <typename E>
1175 [[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t<E, string_view> {
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.");
1178 
1179  return name;
1180 }
1181 
1182 // Returns number of enum values.
1183 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1184 [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t<E, std::size_t> {
1185  return detail::count_v<std::decay_t<E>, S>;
1186 }
1187 
1188 // Returns enum value at specified index.
1189 // No bounds checking is performed: the behavior is undefined if index >= number of enum values.
1190 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1191 [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<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 
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];
1197  } else {
1198  constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v<D, S>) : detail::min_v<D, S>;
1199 
1200  return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
1201  }
1202 }
1203 
1204 // Returns enum value at specified index.
1205 template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1206 [[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<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.");
1210 
1211  return enum_value<D, S>(I);
1212 }
1213 
1214 // Returns std::array with enum values, sorted by enum value.
1215 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1216 [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
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.");
1219 
1220  return detail::values_v<D, S>;
1221 }
1222 
1223 // Returns integer value from enum value.
1224 template <typename E>
1225 [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1226  return static_cast<underlying_type_t<E>>(value);
1227 }
1228 
1229 // Returns underlying value from enum value.
1230 template <typename E>
1231 [[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1232  return static_cast<underlying_type_t<E>>(value);
1233 }
1234 
1235 // Obtains index in enum values from enum value.
1236 // Returns optional with index.
1237 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1238 [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1239  using D = std::decay_t<E>;
1240  using U = underlying_type_t<D>;
1241  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1242 
1243  if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
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}; },
1247  value,
1248  detail::default_result_type_lambda<optional<std::size_t>>);
1249 #else
1250  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1251  if (enum_value<D, S>(i) == value) {
1252  return i;
1253  }
1254  }
1255  return {}; // Invalid value or out of range.
1256 #endif
1257  } else {
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>);
1261  }
1262  return {}; // Invalid value or out of range.
1263  }
1264 }
1265 
1266 // Obtains index in enum values from enum value.
1267 // Returns optional with index.
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.");
1272 
1273  return enum_index<D, S>(value);
1274 }
1275 
1276 // Obtains index in enum values from static storage enum variable.
1277 template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1278 [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
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.");
1283 
1284  return *index;
1285 }
1286 
1287 // Returns name from static storage enum variable.
1288 // This version is much lighter on the compile times and is not restricted to the enum_range limitation.
1289 template <auto V>
1290 [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t<decltype(V), string_view> {
1291  constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;
1292  static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");
1293 
1294  return name;
1295 }
1296 
1297 // Returns name from enum value.
1298 // If enum value does not have name or value out of range, returns empty string.
1299 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1300 [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
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.");
1303 
1304  if (const auto i = enum_index<D, S>(value)) {
1305  return detail::names_v<D, S>[*i];
1306  }
1307  return {};
1308 }
1309 
1310 // Returns name from enum value.
1311 // If enum value does not have name or value out of range, returns empty string.
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.");
1316 
1317  return enum_name<D, S>(value);
1318 }
1319 
1320 // Returns std::array with names, sorted by enum value.
1321 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1322 [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
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.");
1325 
1326  return detail::names_v<D, S>;
1327 }
1328 
1329 // Returns std::array with pairs (value, name), sorted by enum value.
1330 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1331 [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
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.");
1334 
1335  return detail::entries_v<D, S>;
1336 }
1337 
1338 // Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
1340 
1341 // Obtains enum value from integer value.
1342 // Returns optional with enum value.
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.");
1347 
1348  if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
1349 #if defined(MAGIC_ENUM_ENABLE_HASH)
1350  return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
1351  [](D v) { return optional<D>{v}; },
1352  static_cast<D>(value),
1353  detail::default_result_type_lambda<optional<D>>);
1354 #else
1355  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1356  if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
1357  return static_cast<D>(value);
1358  }
1359  }
1360  return {}; // Invalid value or out of range.
1361 #endif
1362  } else {
1363  if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
1364  return static_cast<D>(value);
1365  }
1366  return {}; // Invalid value or out of range.
1367  }
1368 }
1369 
1370 // Obtains enum value from name.
1371 // Returns optional with enum 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.");
1376 
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]}; },
1381  value,
1382  detail::default_result_type_lambda<optional<D>>,
1383  [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
1384  }
1385 #endif
1386  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1387  if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
1388  return enum_value<D, S>(i);
1389  }
1390  }
1391  return {}; // Invalid value or out of range.
1392 }
1393 
1394 // Checks whether enum contains value with such value.
1395 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1396 [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
1397  using D = std::decay_t<E>;
1398  using U = underlying_type_t<D>;
1399 
1400  return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1401 }
1402 
1403 // Checks whether enum contains value with such 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>;
1408 
1409  return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1410 }
1411 
1412 // Checks whether enum contains value with such integer value.
1413 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1414 [[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
1415  using D = std::decay_t<E>;
1416 
1417  return static_cast<bool>(enum_cast<D, S>(value));
1418 }
1419 
1420 // Checks whether enum contains enumerator with such name.
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>;
1424 
1425  return static_cast<bool>(enum_cast<D, S>(value, std::move(p)));
1426 }
1427 
1428 // Returns true if the enum integer value is in the range of values that can be reflected.
1429 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1430 [[nodiscard]] constexpr auto enum_reflected(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
1431  using D = std::decay_t<E>;
1432 
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>();
1436  return value >= min && value <= max;
1437  } else {
1438  return false;
1439  }
1440 }
1441 
1442 // Returns true if the enum value is in the range of values that can be reflected.
1443 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1444 [[nodiscard]] constexpr auto enum_reflected(E value) noexcept -> detail::enable_if_t<E, bool> {
1445  using D = std::decay_t<E>;
1446 
1447  return enum_reflected<D, S>(static_cast<underlying_type_t<D>>(value));
1448 }
1449 
1450 // Returns true if the enum value is in the range of values that can be reflected.
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>;
1454 
1455  return enum_reflected<D, S>(value);
1456 }
1457 
1458 template <bool AsFlags = true>
1460 
1461 template <bool AsFlags = true>
1463 
1464 namespace bitwise_operators {
1465 
1466 template <typename E, detail::enable_if_t<E, int> = 0>
1467 constexpr E operator~(E rhs) noexcept {
1468  return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));
1469 }
1470 
1471 template <typename E, detail::enable_if_t<E, int> = 0>
1472 constexpr E operator|(E lhs, E rhs) noexcept {
1473  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));
1474 }
1475 
1476 template <typename E, detail::enable_if_t<E, int> = 0>
1477 constexpr E operator&(E lhs, E rhs) noexcept {
1478  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));
1479 }
1480 
1481 template <typename E, detail::enable_if_t<E, int> = 0>
1482 constexpr E operator^(E lhs, E rhs) noexcept {
1483  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));
1484 }
1485 
1486 template <typename E, detail::enable_if_t<E, int> = 0>
1487 constexpr E& operator|=(E& lhs, E rhs) noexcept {
1488  return lhs = (lhs | rhs);
1489 }
1490 
1491 template <typename E, detail::enable_if_t<E, int> = 0>
1492 constexpr E& operator&=(E& lhs, E rhs) noexcept {
1493  return lhs = (lhs & rhs);
1494 }
1495 
1496 template <typename E, detail::enable_if_t<E, int> = 0>
1497 constexpr E& operator^=(E& lhs, E rhs) noexcept {
1498  return lhs = (lhs ^ rhs);
1499 }
1500 
1501 } // namespace magic_enum::bitwise_operators
1502 
1503 } // namespace magic_enum
1504 
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)
1511 #endif
1512 
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
1518 
1519 #endif // NEARGYE_MAGIC_ENUM_HPP
magic_enum::as_common
constexpr auto as_common
Definition: magic_enum.hpp:1462
magic_enum::Enum
detail::enum_concept< T > Enum
Definition: magic_enum.hpp:1144
magic_enum::detail::static_str< 0 >::data
constexpr const char_type * data() const noexcept
Definition: magic_enum.hpp:292
magic_enum::is_unscoped_enum
Definition: magic_enum.hpp:1149
magic_enum::customize::enum_range::max
static constexpr int max
Definition: magic_enum.hpp:174
magic_enum::customize::customize_t::customize_t
constexpr customize_t(string_view srt)
Definition: magic_enum.hpp:191
magic_enum::case_insensitive
constexpr auto case_insensitive
Definition: magic_enum.hpp:1339
MAGIC_ENUM_USING_ALIAS_STRING_VIEW
#define MAGIC_ENUM_USING_ALIAS_STRING_VIEW
Definition: test_aliases.cpp:97
magic_enum::detail::enum_subtype::flags
@ flags
MAGIC_ENUM_RANGE_MAX
#define MAGIC_ENUM_RANGE_MAX
Definition: magic_enum.hpp:110
magic_enum::detail::case_insensitive::to_lower
static constexpr char_type to_lower(char_type c) noexcept
Definition: magic_enum.hpp:301
magic_enum::detail::enum_name
constexpr auto enum_name() noexcept
Definition: magic_enum.hpp:600
magic_enum::detail::underlying_type
Definition: magic_enum.hpp:922
MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM
#define MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM
Definition: test.cpp:26
magic_enum::char_type
string_view::value_type char_type
Definition: magic_enum.hpp:149
magic_enum::detail::cmp_equal
constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate &&p) noexcept(is_nothrow_invocable< BinaryPredicate >())
Definition: magic_enum.hpp:347
magic_enum::detail::is_default_predicate
constexpr bool is_default_predicate() noexcept
Definition: magic_enum.hpp:335
magic_enum::customize::enum_name
constexpr customize_t enum_name(E) noexcept
Definition: magic_enum.hpp:205
magic_enum::detail::static_str::static_str
constexpr static_str(string_view str, std::integer_sequence< std::uint16_t, I... >) noexcept
Definition: magic_enum.hpp:278
magic_enum::detail::is_sparse
constexpr bool is_sparse() noexcept
Definition: magic_enum.hpp:866
MAGIC_ENUM_V
#define MAGIC_ENUM_V(O)
magic_enum::customize::invalid_tag
constexpr auto invalid_tag
Definition: magic_enum.hpp:201
magic_enum::detail::is_enum_v
constexpr bool is_enum_v
Definition: magic_enum.hpp:418
magic_enum::detail::valid_count_t::valid
bool valid[N]
Definition: magic_enum.hpp:746
magic_enum::detail::default_result_type_lambda
constexpr auto default_result_type_lambda
Definition: magic_enum_switch.hpp:99
magic_enum::detail::is_nothrow_invocable
constexpr bool is_nothrow_invocable()
Definition: magic_enum.hpp:341
magic_enum::detail::valid_count
constexpr void valid_count(bool *valid, std::size_t &count) noexcept
Definition: magic_enum.hpp:726
magic_enum::bitwise_operators::operator|=
constexpr E & operator|=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1487
magic_enum::detail::enable_if_t
typename enable_if_enum< std::is_enum_v< D > &&std::is_invocable_r_v< bool, BinaryPredicate, char_type, char_type >, R >::type enable_if_t
Definition: magic_enum.hpp:904
magic_enum::detail::subtype
constexpr enum_subtype subtype(std::true_type) noexcept
Definition: magic_enum.hpp:792
magic_enum::detail::result_t
std::enable_if_t< std::is_enum_v< D > &&!std::is_same_v< R, nonesuch >, R > result_t
Definition: magic_enum_switch.hpp:94
magic_enum::customize::detail::customize_tag::default_tag
@ default_tag
MAGIC_ENUM_RANGE_MIN
#define MAGIC_ENUM_RANGE_MIN
Definition: magic_enum.hpp:104
magic_enum::detail::names
constexpr auto names(std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:842
magic_enum::bitwise_operators::operator|
constexpr E operator|(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1472
magic_enum::detail::is_unscoped_enum
Definition: magic_enum.hpp:916
magic_enum::detail::case_insensitive
Definition: magic_enum.hpp:300
magic_enum::detail::static_str::static_str
constexpr static_str(str_view str) noexcept
Definition: magic_enum.hpp:259
magic_enum::detail::static_str< 0 >::static_str
constexpr static_str(string_view) noexcept
Definition: magic_enum.hpp:290
magic_enum::detail::static_str< 0 >
Definition: magic_enum.hpp:284
MAGIC_ENUM_FOR_EACH_256
#define MAGIC_ENUM_FOR_EACH_256(T)
Definition: magic_enum.hpp:715
magic_enum::detail::has_is_flags
Definition: magic_enum.hpp:234
magic_enum::bitwise_operators::operator^
constexpr E operator^(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1482
magic_enum::detail::str_view::size_
std::size_t size_
Definition: magic_enum.hpp:253
magic_enum::detail::names_t
decltype((names_v< D, S >)) names_t
Definition: magic_enum.hpp:851
magic_enum::detail::static_str::size
constexpr std::uint16_t size() const noexcept
Definition: magic_enum.hpp:269
magic_enum::bitwise_operators::operator^=
constexpr E & operator^=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1497
magic_enum::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:679
magic_enum::detail::is_sparse_v
constexpr bool is_sparse_v
Definition: magic_enum.hpp:881
magic_enum::detail::static_str< 0 >::size
constexpr std::uint16_t size() const noexcept
Definition: magic_enum.hpp:294
magic_enum::detail::is_enum_constexpr_static_cast_valid
constexpr bool is_enum_constexpr_static_cast_valid
Definition: magic_enum.hpp:633
magic_enum::bitwise_operators::operator&=
constexpr E & operator&=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1492
magic_enum::customize::detail::customize_tag::custom_tag
@ custom_tag
magic_enum::enum_count
constexpr auto enum_count() noexcept -> detail::enable_if_t< E, std::size_t >
Definition: magic_enum.hpp:1184
magic_enum::customize::detail::customize_tag
customize_tag
Definition: magic_enum.hpp:181
magic_enum::customize::enum_type_name
constexpr customize_t enum_type_name() noexcept
Definition: magic_enum.hpp:211
magic_enum::detail::is_reflected_v
constexpr bool is_reflected_v
Definition: magic_enum.hpp:892
magic_enum::detail::log2
constexpr I log2(I value) noexcept
Definition: magic_enum.hpp:395
magic_enum::detail::to_array
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N], std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:412
magic_enum::detail::static_str::data
constexpr const char_type * data() const noexcept
Definition: magic_enum.hpp:267
magic_enum::detail::enum_subtype::common
@ common
magic_enum::detail::default_result_type_lambda< void >
constexpr auto default_result_type_lambda< void >
Definition: magic_enum_switch.hpp:102
magic_enum::detail::static_str
Definition: magic_enum.hpp:257
magic_enum::detail::enum_name_v
constexpr auto enum_name_v
Definition: magic_enum.hpp:622
magic_enum::enum_contains
constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum.hpp:1396
magic_enum::detail::str_view::str_
const char * str_
Definition: magic_enum.hpp:252
magic_enum::detail::values
constexpr auto values() noexcept
Definition: magic_enum.hpp:757
magic_enum::as_flags
constexpr auto as_flags
Definition: magic_enum.hpp:1459
magic_enum::enum_value
constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t< E, std::decay_t< E >>
Definition: magic_enum.hpp:1191
magic_enum::customize::customize_t::customize_t
constexpr customize_t(const char_type *srt)
Definition: magic_enum.hpp:192
MAGIC_ENUM_USING_ALIAS_STRING
#define MAGIC_ENUM_USING_ALIAS_STRING
Definition: test_aliases.cpp:96
magic_enum::is_unscoped_enum_v
constexpr bool is_unscoped_enum_v
Definition: magic_enum.hpp:1152
magic_enum::customize::detail::customize_tag::invalid_tag
@ invalid_tag
magic_enum::detail::entries_v
constexpr auto entries_v
Definition: magic_enum.hpp:860
magic_enum::enum_underlying
constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E >>
Definition: magic_enum.hpp:1231
magic_enum::detail::entries
constexpr auto entries(std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:854
magic_enum::detail::values_v
constexpr auto values_v
Definition: magic_enum.hpp:827
magic_enum::underlying_type_t
typename underlying_type< T >::type underlying_type_t
Definition: magic_enum.hpp:1168
MAGIC_ENUM_USING_ALIAS_OPTIONAL
#define MAGIC_ENUM_USING_ALIAS_OPTIONAL
Definition: test_aliases.cpp:95
magic_enum::is_magic_enum_supported
constexpr bool is_magic_enum_supported
Definition: magic_enum.hpp:1141
magic_enum::enum_index
constexpr auto enum_index(E value) noexcept -> detail::enable_if_t< E, optional< std::size_t >>
Definition: magic_enum.hpp:1238
magic_enum::detail::valid_count_t
Definition: magic_enum.hpp:744
magic_enum::detail::cmp_less
constexpr bool cmp_less(L lhs, R rhs) noexcept
Definition: magic_enum.hpp:375
magic_enum::detail::str_view
Definition: magic_enum.hpp:251
magic_enum::enum_entries
constexpr auto enum_entries() noexcept -> detail::enable_if_t< E, detail::entries_t< E, S >>
Definition: magic_enum.hpp:1331
MAGIC_ENUM_ASSERT
#define MAGIC_ENUM_ASSERT(...)
Definition: magic_enum.hpp:69
magic_enum::is_scoped_enum_v
constexpr bool is_scoped_enum_v
Definition: magic_enum.hpp:1160
magic_enum::customize::customize_t::customize_t
constexpr customize_t(detail::customize_tag tag)
Definition: magic_enum.hpp:193
magic_enum::enum_values
constexpr auto enum_values() noexcept -> detail::enable_if_t< E, detail::values_t< E, S >>
Definition: magic_enum.hpp:1216
magic_enum::detail::invoke_result_t
typename invoke_result< F, V >::type invoke_result_t
Definition: magic_enum_switch.hpp:57
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:421
magic_enum::detail::type_name
constexpr auto type_name() noexcept
Definition: magic_enum.hpp:476
magic_enum::detail::subtype_v
constexpr auto subtype_v
Definition: magic_enum.hpp:824
magic_enum::detail::max_v
constexpr auto max_v
Definition: magic_enum.hpp:839
magic_enum::detail::min_v
constexpr auto min_v
Definition: magic_enum.hpp:836
magic_enum::detail::enum_concept
T enum_concept
Definition: magic_enum.hpp:907
magic_enum::bitwise_operators::operator~
constexpr E operator~(E rhs) noexcept
Definition: magic_enum.hpp:1467
magic_enum::detail::range_min
Definition: magic_enum.hpp:240
magic_enum::customize::enum_range
Definition: magic_enum.hpp:172
magic_enum::is_scoped_enum
Definition: magic_enum.hpp:1157
magic_enum::detail::ualue
constexpr U ualue(std::size_t i) noexcept
Definition: magic_enum.hpp:666
magic_enum::detail::static_str< 0 >::static_str
constexpr static_str(str_view) noexcept
Definition: magic_enum.hpp:288
magic_enum::detail::is_reflected
Definition: magic_enum.hpp:884
magic_enum::detail::count_v
constexpr auto count_v
Definition: magic_enum.hpp:833
magic_enum::customize::enum_range::min
static constexpr int min
Definition: magic_enum.hpp:173
magic_enum::detail::type_name_v
constexpr auto type_name_v
Definition: magic_enum.hpp:494
magic_enum::detail::is_scoped_enum
Definition: magic_enum.hpp:910
magic_enum::customize::customize_t
Definition: magic_enum.hpp:189
magic_enum::enum_name
constexpr auto enum_name() noexcept -> detail::enable_if_t< decltype(V), string_view >
Definition: magic_enum.hpp:1290
magic_enum::detail::enum_constant
std::integral_constant< E, V > enum_constant
Definition: magic_enum.hpp:228
std
magic_enum::detail::find
constexpr std::size_t find(string_view str, char_type c) noexcept
Definition: magic_enum.hpp:312
magic_enum::detail::names_v
constexpr auto names_v
Definition: magic_enum.hpp:848
magic_enum::detail::reflected_max
constexpr int reflected_max() noexcept
Definition: magic_enum.hpp:700
magic_enum::enum_cast
constexpr auto enum_cast(underlying_type_t< E > value) noexcept -> detail::enable_if_t< E, optional< std::decay_t< E >>>
Definition: magic_enum.hpp:1344
magic_enum::detail::enable_if_enum
Definition: magic_enum.hpp:895
magic_enum::customize::default_tag
constexpr auto default_tag
Definition: magic_enum.hpp:199
magic_enum::detail::always_false_v
constexpr bool always_false_v
Definition: magic_enum.hpp:231
magic_enum::detail::range_max
Definition: magic_enum.hpp:246
magic_enum::underlying_type
Definition: magic_enum.hpp:1165
magic_enum::detail::valid_count_t::count
std::size_t count
Definition: magic_enum.hpp:745
magic_enum
Definition: magic_enum.hpp:126
magic_enum::enum_names
constexpr auto enum_names() noexcept -> detail::enable_if_t< E, detail::names_t< E, S >>
Definition: magic_enum.hpp:1322
magic_enum::detail::is_valid
constexpr bool is_valid() noexcept
Definition: magic_enum.hpp:637
magic_enum::enum_reflected
constexpr auto enum_reflected(underlying_type_t< E > value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum.hpp:1430
magic_enum::bitwise_operators::operator&
constexpr E operator&(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1477
magic_enum::detail::static_str::static_str
constexpr static_str(string_view str) noexcept
Definition: magic_enum.hpp:263
magic_enum::detail::reflected_min
constexpr int reflected_min() noexcept
Definition: magic_enum.hpp:684
magic_enum::detail::enum_subtype
enum_subtype
Definition: magic_enum.hpp:660
magic_enum::detail::static_str::static_str
constexpr static_str(const char *str, std::integer_sequence< std::uint16_t, I... >) noexcept
Definition: magic_enum.hpp:275
magic_enum::enum_constant
detail::enum_constant< V > enum_constant
Definition: magic_enum.hpp:1171
magic_enum::enum_type_name
constexpr auto enum_type_name() noexcept -> detail::enable_if_t< E, string_view >
Definition: magic_enum.hpp:1175
magic_enum::detail::case_insensitive::operator()
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 >
Definition: magic_enum.hpp:307
magic_enum::detail::supported
Definition: magic_enum.hpp:220
magic_enum::detail::entries_t
decltype((entries_v< D, S >)) entries_t
Definition: magic_enum.hpp:863
magic_enum::detail::values_t
decltype((values_v< D, S >)) values_t
Definition: magic_enum.hpp:830
magic_enum::enum_integer
constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E >>
Definition: magic_enum.hpp:1225
magic_enum::detail::constexpr_switch
constexpr decltype(auto) constexpr_switch(F &&f, E value, Def &&def)
Definition: magic_enum_switch.hpp:123
magic_enum::detail::enable_if_enum< true, R >::type
R type
Definition: magic_enum.hpp:899
magic_enum::detail::static_str::chars_
char_type chars_[static_cast< std::size_t >(N)+1]
Definition: magic_enum.hpp:280


magic_enum
Author(s):
autogenerated on Fri Feb 21 2025 03:20:19