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.5
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 5
38 
39 #include <array>
40 #include <cstddef>
41 #include <cstdint>
42 #include <functional>
43 #include <limits>
44 #include <type_traits>
45 #include <utility>
46 
47 #if defined(MAGIC_ENUM_CONFIG_FILE)
48 # include MAGIC_ENUM_CONFIG_FILE
49 #endif
50 
51 #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
52 # include <optional>
53 #endif
54 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING)
55 # include <string>
56 #endif
57 #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
58 # include <string_view>
59 #endif
60 
61 #if defined(MAGIC_ENUM_NO_ASSERT)
62 # define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
63 #elif !defined(MAGIC_ENUM_ASSERT)
64 # include <cassert>
65 # define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
66 #endif
67 
68 #if defined(__clang__)
69 # pragma clang diagnostic push
70 # pragma clang diagnostic ignored "-Wunknown-warning-option"
71 # pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
72 # pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
73 #elif defined(__GNUC__)
74 # pragma GCC diagnostic push
75 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
76 # pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
77 #elif defined(_MSC_VER)
78 # pragma warning(push)
79 # pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
80 # pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
81 # pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
82 # pragma warning(disable : 4514) // Unreferenced inline function has been removed.
83 #endif
84 
85 // Checks magic_enum compiler compatibility.
86 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__)
87 # undef MAGIC_ENUM_SUPPORTED
88 # define MAGIC_ENUM_SUPPORTED 1
89 #endif
90 
91 // Checks magic_enum compiler aliases compatibility.
92 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
93 # undef MAGIC_ENUM_SUPPORTED_ALIASES
94 # define MAGIC_ENUM_SUPPORTED_ALIASES 1
95 #endif
96 
97 // Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128.
98 // If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN.
99 #if !defined(MAGIC_ENUM_RANGE_MIN)
100 # define MAGIC_ENUM_RANGE_MIN -128
101 #endif
102 
103 // Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128.
104 // If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.
105 #if !defined(MAGIC_ENUM_RANGE_MAX)
106 # define MAGIC_ENUM_RANGE_MAX 127
107 #endif
108 
109 // Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations.
110 #if defined(__RESHARPER__)
111 # undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
112 # undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
113 # if __RESHARPER__ >= 20230100
114 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V)
115 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name<T>()
116 # else
117 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr
118 # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr
119 # endif
120 #endif
121 
122 namespace magic_enum {
123 
124 // If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.
125 #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)
126 MAGIC_ENUM_USING_ALIAS_OPTIONAL
127 #else
128 using std::optional;
129 #endif
130 
131 // If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW.
132 #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)
133 MAGIC_ENUM_USING_ALIAS_STRING_VIEW
134 #else
135 using std::string_view;
136 #endif
137 
138 // If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING.
139 #if defined(MAGIC_ENUM_USING_ALIAS_STRING)
140 MAGIC_ENUM_USING_ALIAS_STRING
141 #else
142 using std::string;
143 #endif
144 
145 using char_type = string_view::value_type;
146 static_assert(std::is_same_v<string_view::value_type, string::value_type>, "magic_enum::customize requires same string_view::value_type and string::value_type");
147 static_assert([] {
148  if constexpr (std::is_same_v<char_type, wchar_t>) {
149  constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
150  constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
151  static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t.");
152 
153  for (std::size_t i = 0; i < std::size(c); ++i) {
154  if (c[i] != wc[i]) {
155  return false;
156  }
157  }
158  }
159  return true;
160 } (), "magic_enum::customize wchar_t is not compatible with ASCII.");
161 
162 namespace customize {
163 
164 // 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 = 128.
165 // If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.
166 // If need another range for specific enum type, add specialization enum_range for necessary enum type.
167 template <typename E>
168 struct enum_range {
169  static constexpr int min = MAGIC_ENUM_RANGE_MIN;
170  static constexpr int max = MAGIC_ENUM_RANGE_MAX;
171 };
172 
173 static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
174 
175 namespace detail {
176 
177 enum class customize_tag {
178  default_tag,
179  invalid_tag,
180  custom_tag
181 };
182 
183 } // namespace magic_enum::customize::detail
184 
185 class customize_t : public std::pair<detail::customize_tag, string_view> {
186  public:
188  constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {}
191  }
192 };
193 
194 // Default customize.
196 // Invalid customize.
198 
199 // If need custom names for enum, add specialization enum_name for necessary enum type.
200 template <typename E>
201 constexpr customize_t enum_name(E) noexcept {
202  return default_tag;
203 }
204 
205 // If need custom type name for enum, add specialization enum_type_name for necessary enum type.
206 template <typename E>
207 constexpr customize_t enum_type_name() noexcept {
208  return default_tag;
209 }
210 
211 } // namespace magic_enum::customize
212 
213 namespace detail {
214 
215 template <typename T>
216 struct supported
217 #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
218  : std::true_type {};
219 #else
220  : std::false_type {};
221 #endif
222 
223 template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
224 using enum_constant = std::integral_constant<E, V>;
225 
226 template <typename... T>
227 inline constexpr bool always_false_v = false;
228 
229 template <typename T, typename = void>
230 struct has_is_flags : std::false_type {};
231 
232 template <typename T>
233 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)>>> {};
234 
235 template <typename T, typename = void>
236 struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
237 
238 template <typename T>
239 struct range_min<T, std::void_t<decltype(customize::enum_range<T>::min)>> : std::integral_constant<decltype(customize::enum_range<T>::min), customize::enum_range<T>::min> {};
240 
241 template <typename T, typename = void>
242 struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
243 
244 template <typename T>
245 struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};
246 
247 struct str_view {
248  const char* str_ = nullptr;
249  std::size_t size_ = 0;
250 };
251 
252 template <std::uint16_t N>
253 class static_str {
254  public:
255  constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence<std::uint16_t, N>{}} {
256  MAGIC_ENUM_ASSERT(str.size_ == N);
257  }
258 
259  constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence<std::uint16_t, N>{}} {
260  MAGIC_ENUM_ASSERT(str.size() == N);
261  }
262 
263  constexpr const char_type* data() const noexcept { return chars_; }
264 
265  constexpr std::uint16_t size() const noexcept { return N; }
266 
267  constexpr operator string_view() const noexcept { return {data(), size()}; }
268 
269  private:
270  template <std::uint16_t... I>
271  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')} {}
272 
273  template <std::uint16_t... I>
274  constexpr static_str(string_view str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{str[I]..., static_cast<char_type>('\0')} {}
275 
276  char_type chars_[static_cast<std::size_t>(N) + 1];
277 };
278 
279 template <>
280 class static_str<0> {
281  public:
282  constexpr explicit static_str() = default;
283 
284  constexpr explicit static_str(str_view) noexcept {}
285 
286  constexpr explicit static_str(string_view) noexcept {}
287 
288  constexpr const char_type* data() const noexcept { return nullptr; }
289 
290  constexpr std::uint16_t size() const noexcept { return 0; }
291 
292  constexpr operator string_view() const noexcept { return {}; }
293 };
294 
295 template <typename Op = std::equal_to<>>
297  static constexpr char_type to_lower(char_type c) noexcept {
298  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;
299  }
300 
301  public:
302  template <typename L, typename R>
303  constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<L>, char_type> && std::is_same_v<std::decay_t<R>, char_type>, bool> {
304  return Op{}(to_lower(lhs), to_lower(rhs));
305  }
306 };
307 
308 constexpr std::size_t find(string_view str, char_type c) noexcept {
309 #if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
310 // https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc
311 // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
312  constexpr bool workaround = true;
313 #else
314  constexpr bool workaround = false;
315 #endif
316 
317  if constexpr (workaround) {
318  for (std::size_t i = 0; i < str.size(); ++i) {
319  if (str[i] == c) {
320  return i;
321  }
322  }
323 
324  return string_view::npos;
325  } else {
326  return str.find(c);
327  }
328 }
329 
330 template <typename BinaryPredicate>
331 constexpr bool is_default_predicate() noexcept {
332  return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
333  std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
334 }
335 
336 template <typename BinaryPredicate>
337 constexpr bool is_nothrow_invocable() {
338  return is_default_predicate<BinaryPredicate>() ||
339  std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
340 }
341 
342 template <typename BinaryPredicate>
343 constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable<BinaryPredicate>()) {
344 #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
345  // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
346  // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
347  constexpr bool workaround = true;
348 #else
349  constexpr bool workaround = false;
350 #endif
351 
352  if constexpr (!is_default_predicate<BinaryPredicate>() || workaround) {
353  if (lhs.size() != rhs.size()) {
354  return false;
355  }
356 
357  const auto size = lhs.size();
358  for (std::size_t i = 0; i < size; ++i) {
359  if (!p(lhs[i], rhs[i])) {
360  return false;
361  }
362  }
363 
364  return true;
365  } else {
366  return lhs == rhs;
367  }
368 }
369 
370 template <typename L, typename R>
371 constexpr bool cmp_less(L lhs, R rhs) noexcept {
372  static_assert(std::is_integral_v<L> && std::is_integral_v<R>, "magic_enum::detail::cmp_less requires integral type.");
373 
374  if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
375  // If same signedness (both signed or both unsigned).
376  return lhs < rhs;
377  } else if constexpr (std::is_same_v<L, bool>) { // bool special case
378  return static_cast<R>(lhs) < rhs;
379  } else if constexpr (std::is_same_v<R, bool>) { // bool special case
380  return lhs < static_cast<L>(rhs);
381  } else if constexpr (std::is_signed_v<R>) {
382  // If 'right' is negative, then result is 'false', otherwise cast & compare.
383  return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);
384  } else {
385  // If 'left' is negative, then result is 'true', otherwise cast & compare.
386  return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;
387  }
388 }
389 
390 template <typename I>
391 constexpr I log2(I value) noexcept {
392  static_assert(std::is_integral_v<I>, "magic_enum::detail::log2 requires integral type.");
393 
394  if constexpr (std::is_same_v<I, bool>) { // bool special case
395  return MAGIC_ENUM_ASSERT(false), value;
396  } else {
397  auto ret = I{0};
398  for (; value > I{1}; value >>= I{1}, ++ret) {}
399 
400  return ret;
401  }
402 }
403 
404 #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
405 # define MAGIC_ENUM_ARRAY_CONSTEXPR 1
406 #else
407 template <typename T, std::size_t N, std::size_t... I>
408 constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N], std::index_sequence<I...>) noexcept {
409  return {{a[I]...}};
410 }
411 #endif
412 
413 template <typename T>
414 inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
415 
416 template <typename E>
417 constexpr auto n() noexcept {
418  static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
419 
420  if constexpr (supported<E>::value) {
421 #if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
422  constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
423  constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
424 #elif defined(__clang__)
425  str_view name;
426  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
427  static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
428  return str_view{};
429  } else {
430  name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
431  name.str_ = __PRETTY_FUNCTION__ + 34;
432  }
433 #elif defined(__GNUC__)
434  auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
435  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
436  static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
437  return str_view{};
438  } else if (name.str_[name.size_ - 1] == ']') {
439  name.size_ -= 50;
440  name.str_ += 49;
441  } else {
442  name.size_ -= 40;
443  name.str_ += 37;
444  }
445 #elif defined(_MSC_VER)
446  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
447  str_view name;
448  name.str_ = __FUNCSIG__;
449  name.str_ += 40;
450  name.size_ += sizeof(__FUNCSIG__) - 57;
451 #else
452  auto name = str_view{};
453 #endif
454  std::size_t p = 0;
455  for (std::size_t i = name.size_; i > 0; --i) {
456  if (name.str_[i] == ':') {
457  p = i + 1;
458  break;
459  }
460  }
461  if (p > 0) {
462  name.size_ -= p;
463  name.str_ += p;
464  }
465  return name;
466  } else {
467  return str_view{}; // Unsupported compiler or Invalid customize.
468  }
469 }
470 
471 template <typename E>
472 constexpr auto type_name() noexcept {
473  [[maybe_unused]] constexpr auto custom = customize::enum_type_name<E>();
474  static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
475  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
476  constexpr auto name = custom.second;
477  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
478  return static_str<name.size()>{name};
479  } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
480  return static_str<0>{};
481  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
482  constexpr auto name = n<E>();
483  return static_str<name.size_>{name};
484  } else {
485  static_assert(always_false_v<E>, "magic_enum::customize invalid.");
486  }
487 }
488 
489 template <typename E>
490 inline constexpr auto type_name_v = type_name<E>();
491 
492 template <auto V>
493 constexpr auto n() noexcept {
494  static_assert(is_enum_v<decltype(V)>, "magic_enum::detail::n requires enum type.");
495 
496  if constexpr (supported<decltype(V)>::value) {
497 #if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
498  constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
499  auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
500 #elif defined(__clang__)
501  str_view name;
502  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
503  static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
504  return str_view{};
505  } else {
506  name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
507  name.str_ = __PRETTY_FUNCTION__ + 34;
508  }
509  if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') {
510  name.size_ -= 23;
511  name.str_ += 23;
512  }
513  if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
514  name = str_view{};
515  }
516 #elif defined(__GNUC__)
517  auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
518  if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
519  static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
520  return str_view{};
521  } else if (name.str_[name.size_ - 1] == ']') {
522  name.size_ -= 55;
523  name.str_ += 54;
524  } else {
525  name.size_ -= 40;
526  name.str_ += 37;
527  }
528  if (name.str_[0] == '(') {
529  name = str_view{};
530  }
531 #elif defined(_MSC_VER)
532  str_view name;
533  if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) {
534  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
535  name.str_ = __FUNCSIG__;
536  name.str_ += 35;
537  name.size_ = sizeof(__FUNCSIG__) - 52;
538  }
539 #else
540  auto name = str_view{};
541 #endif
542  std::size_t p = 0;
543  for (std::size_t i = name.size_; i > 0; --i) {
544  if (name.str_[i] == ':') {
545  p = i + 1;
546  break;
547  }
548  }
549  if (p > 0) {
550  name.size_ -= p;
551  name.str_ += p;
552  }
553  return name;
554  } else {
555  return str_view{}; // Unsupported compiler or Invalid customize.
556  }
557 }
558 
559 #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920
560 # define MAGIC_ENUM_VS_2017_WORKAROUND 1
561 #endif
562 
563 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
564 template <typename E, E V>
565 constexpr auto n() noexcept {
566  static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");
567 
568 # if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
569  constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
570  auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
571 # else
572  // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
573  str_view name;
574  name.str_ = __FUNCSIG__;
575  name.size_ = sizeof(__FUNCSIG__) - 17;
576  std::size_t p = 0;
577  for (std::size_t i = name.size_; i > 0; --i) {
578  if (name.str_[i] == ',' || name.str_[i] == ':') {
579  p = i + 1;
580  break;
581  }
582  }
583  if (p > 0) {
584  name.size_ -= p;
585  name.str_ += p;
586  }
587  if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
588  name = str_view{};
589  }
590  return name;
591 # endif
592 }
593 #endif
594 
595 template <typename E, E V>
596 constexpr auto enum_name() noexcept {
597  [[maybe_unused]] constexpr auto custom = customize::enum_name<E>(V);
598  static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
599  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
600  constexpr auto name = custom.second;
601  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
602  return static_str<name.size()>{name};
603  } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
604  return static_str<0>{};
605  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
606 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
607  constexpr auto name = n<E, V>();
608 #else
609  constexpr auto name = n<V>();
610 #endif
611  return static_str<name.size_>{name};
612  } else {
613  static_assert(always_false_v<E>, "magic_enum::customize invalid.");
614  }
615 }
616 
617 template <typename E, E V>
618 inline constexpr auto enum_name_v = enum_name<E, V>();
619 
620 template <typename E, auto V>
621 constexpr bool is_valid() noexcept {
622 #if defined(__clang__) && __clang_major__ >= 16
623  // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
624  constexpr E v = __builtin_bit_cast(E, V);
625 #else
626  constexpr E v = static_cast<E>(V);
627 #endif
628  [[maybe_unused]] constexpr auto custom = customize::enum_name<E>(v);
629  static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
630  if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
631  constexpr auto name = custom.second;
632  static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
633  return name.size() != 0;
634  } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
635 #if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
636  return n<E, v>().size_ != 0;
637 #else
638  return n<v>().size_ != 0;
639 #endif
640  } else {
641  return false;
642  }
643 }
644 
645 enum class enum_subtype {
646  common,
647  flags
648 };
649 
650 template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
651 constexpr U ualue(std::size_t i) noexcept {
652  if constexpr (std::is_same_v<U, bool>) { // bool special case
653  static_assert(O == 0, "magic_enum::detail::ualue requires valid offset.");
654 
655  return static_cast<U>(i);
656  } else if constexpr (S == enum_subtype::flags) {
657  return static_cast<U>(U{1} << static_cast<U>(static_cast<int>(i) + O));
658  } else {
659  return static_cast<U>(static_cast<int>(i) + O);
660  }
661 }
662 
663 template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
664 constexpr E value(std::size_t i) noexcept {
665  return static_cast<E>(ualue<E, O, S>(i));
666 }
667 
668 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
669 constexpr int reflected_min() noexcept {
670  if constexpr (S == enum_subtype::flags) {
671  return 0;
672  } else {
673  constexpr auto lhs = range_min<E>::value;
674  constexpr auto rhs = (std::numeric_limits<U>::min)();
675 
676  if constexpr (cmp_less(rhs, lhs)) {
677  return lhs;
678  } else {
679  return rhs;
680  }
681  }
682 }
683 
684 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
685 constexpr int reflected_max() noexcept {
686  if constexpr (S == enum_subtype::flags) {
688  } else {
689  constexpr auto lhs = range_max<E>::value;
690  constexpr auto rhs = (std::numeric_limits<U>::max)();
691 
692  if constexpr (cmp_less(lhs, rhs)) {
693  return lhs;
694  } else {
695  return rhs;
696  }
697  }
698 }
699 
700 #define MAGIC_ENUM_FOR_EACH_256(T) \
701  T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \
702  T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \
703  T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \
704  T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \
705  T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \
706  T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \
707  T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \
708  T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255)
709 
710 template <typename E, enum_subtype S, std::size_t Size, int Min, std::size_t I>
711 constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
712 #define MAGIC_ENUM_V(O) \
713  if constexpr ((I + O) < Size) { \
714  if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
715  valid[I + O] = true; \
716  ++count; \
717  } \
718  }
719 
721 
722  if constexpr ((I + 256) < Size) {
723  valid_count<E, S, Size, Min, I + 256>(valid, count);
724  }
725 #undef MAGIC_ENUM_V
726 }
727 
728 template <std::size_t N>
730  std::size_t count = 0;
731  bool valid[N] = {};
732 };
733 
734 template <typename E, enum_subtype S, std::size_t Size, int Min>
735 constexpr auto valid_count() noexcept {
737  valid_count<E, S, Size, Min, 0>(vc.valid, vc.count);
738  return vc;
739 }
740 
741 template <typename E, enum_subtype S, std::size_t Size, int Min>
742 constexpr auto values() noexcept {
743  constexpr auto vc = valid_count<E, S, Size, Min>();
744 
745  if constexpr (vc.count > 0) {
746 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
747  std::array<E, vc.count> values = {};
748 #else
749  E values[vc.count] = {};
750 #endif
751  for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
752  if (vc.valid[i]) {
753  values[v++] = value<E, Min, S>(i);
754  }
755  }
756 #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
757  return values;
758 #else
759  return to_array(values, std::make_index_sequence<vc.count>{});
760 #endif
761  } else {
762  return std::array<E, 0>{};
763  }
764 }
765 
766 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
767 constexpr auto values() noexcept {
768  constexpr auto min = reflected_min<E, S>();
769  constexpr auto max = reflected_max<E, S>();
770  constexpr auto range_size = max - min + 1;
771  static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
772 
773  return values<E, S, range_size, min>();
774 }
775 
776 template <typename E, typename U = std::underlying_type_t<E>>
777 constexpr enum_subtype subtype(std::true_type) noexcept {
778  if constexpr (std::is_same_v<U, bool>) { // bool special case
779  return enum_subtype::common;
780  } else if constexpr (has_is_flags<E>::value) {
782  } else {
783 #if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
784  constexpr auto flags_values = values<E, enum_subtype::flags>();
785  constexpr auto default_values = values<E, enum_subtype::common>();
786  if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
787  return enum_subtype::common;
788  }
789  for (std::size_t i = 0; i < default_values.size(); ++i) {
790  const auto v = static_cast<U>(default_values[i]);
791  if (v != 0 && (v & (v - 1)) != 0) {
792  return enum_subtype::common;
793  }
794  }
795  return enum_subtype::flags;
796 #else
797  return enum_subtype::common;
798 #endif
799  }
800 }
801 
802 template <typename T>
803 constexpr enum_subtype subtype(std::false_type) noexcept {
804  // For non-enum type return default common subtype.
805  return enum_subtype::common;
806 }
807 
808 template <typename E, typename D = std::decay_t<E>>
809 inline constexpr auto subtype_v = subtype<D>(std::is_enum<D>{});
810 
811 template <typename E, enum_subtype S>
812 inline constexpr auto values_v = values<E, S>();
813 
814 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
815 using values_t = decltype((values_v<D, S>));
816 
817 template <typename E, enum_subtype S>
818 inline constexpr auto count_v = values_v<E, S>.size();
819 
820 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
821 inline constexpr auto min_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.front()) : U{0};
822 
823 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
824 inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.back()) : U{0};
825 
826 template <typename E, enum_subtype S, std::size_t... I>
827 constexpr auto names(std::index_sequence<I...>) noexcept {
828  constexpr auto names = std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
829  return names;
830 }
831 
832 template <typename E, enum_subtype S>
833 inline constexpr auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
834 
835 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
836 using names_t = decltype((names_v<D, S>));
837 
838 template <typename E, enum_subtype S, std::size_t... I>
839 constexpr auto entries(std::index_sequence<I...>) noexcept {
840  constexpr auto entries = std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
841  return entries;
842 }
843 
844 template <typename E, enum_subtype S>
845 inline constexpr auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
846 
847 template <typename E, enum_subtype S, typename D = std::decay_t<E>>
848 using entries_t = decltype((entries_v<D, S>));
849 
850 template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
851 constexpr bool is_sparse() noexcept {
852  if constexpr (count_v<E, S> == 0) {
853  return false;
854  } else if constexpr (std::is_same_v<U, bool>) { // bool special case
855  return false;
856  } else {
857  constexpr auto max = (S == enum_subtype::flags) ? log2(max_v<E, S>) : max_v<E, S>;
858  constexpr auto min = (S == enum_subtype::flags) ? log2(min_v<E, S>) : min_v<E, S>;
859  constexpr auto range_size = max - min + 1;
860 
861  return range_size != count_v<E, S>;
862  }
863 }
864 
865 template <typename E, enum_subtype S = subtype_v<E>>
866 inline constexpr bool is_sparse_v = is_sparse<E, S>();
867 
868 template <typename E, enum_subtype S>
870 #if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
871  : std::true_type {};
872 #else
873  : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
874 #endif
875 
876 template <typename E, enum_subtype S>
877 inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};
878 
879 template <bool, typename R>
880 struct enable_if_enum {};
881 
882 template <typename R>
883 struct enable_if_enum<true, R> {
884  using type = R;
885  static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
886 };
887 
888 template <typename T, typename R, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
889 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;
890 
891 template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
892 using enum_concept = T;
893 
894 template <typename T, bool = std::is_enum_v<T>>
895 struct is_scoped_enum : std::false_type {};
896 
897 template <typename T>
898 struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
899 
900 template <typename T, bool = std::is_enum_v<T>>
901 struct is_unscoped_enum : std::false_type {};
902 
903 template <typename T>
904 struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
905 
906 template <typename T, bool = std::is_enum_v<std::decay_t<T>>>
907 struct underlying_type {};
908 
909 template <typename T>
910 struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
911 
912 #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
913 
914 template <typename Value, typename = void>
915 struct constexpr_hash_t;
916 
917 template <typename Value>
918 struct constexpr_hash_t<Value, std::enable_if_t<is_enum_v<Value>>> {
919  constexpr auto operator()(Value value) const noexcept {
920  using U = typename underlying_type<Value>::type;
921  if constexpr (std::is_same_v<U, bool>) { // bool special case
922  return static_cast<std::size_t>(value);
923  } else {
924  return static_cast<U>(value);
925  }
926  }
927  using secondary_hash = constexpr_hash_t;
928 };
929 
930 template <typename Value>
931 struct constexpr_hash_t<Value, std::enable_if_t<std::is_same_v<Value, string_view>>> {
932  static constexpr std::uint32_t crc_table[256] {
933  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
934  0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
935  0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
936  0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
937  0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
938  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
939  0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
940  0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
941  0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
942  0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
943  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
944  0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
945  0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
946  0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
947  0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
948  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
949  0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
950  0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
951  0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
952  0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
953  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
954  0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
955  0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
956  0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
957  0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
958  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
959  0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
960  0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
961  0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
962  0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
963  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
964  0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
965  };
966  constexpr std::uint32_t operator()(string_view value) const noexcept {
967  auto crc = static_cast<std::uint32_t>(0xffffffffL);
968  for (const auto c : value) {
969  crc = (crc >> 8) ^ crc_table[(crc ^ static_cast<std::uint32_t>(c)) & 0xff];
970  }
971  return crc ^ 0xffffffffL;
972  }
973 
974  struct secondary_hash {
975  constexpr std::uint32_t operator()(string_view value) const noexcept {
976  auto acc = static_cast<std::uint64_t>(2166136261ULL);
977  for (const auto c : value) {
978  acc = ((acc ^ static_cast<std::uint64_t>(c)) * static_cast<std::uint64_t>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
979  }
980  return static_cast<std::uint32_t>(acc);
981  }
982  };
983 };
984 
985 template <typename Hash>
986 inline constexpr Hash hash_v{};
987 
988 template <auto* GlobValues, typename Hash>
989 constexpr auto calculate_cases(std::size_t Page) noexcept {
990  constexpr std::array values = *GlobValues;
991  constexpr std::size_t size = values.size();
992 
993  using switch_t = std::invoke_result_t<Hash, typename decltype(values)::value_type>;
994  static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
995  const std::size_t values_to = (std::min)(static_cast<std::size_t>(256), size - Page);
996 
997  std::array<switch_t, 256> result{};
998  auto fill = result.begin();
999  {
1000  auto first = values.begin() + static_cast<std::ptrdiff_t>(Page);
1001  auto last = values.begin() + static_cast<std::ptrdiff_t>(Page + values_to);
1002  while (first != last) {
1003  *fill++ = hash_v<Hash>(*first++);
1004  }
1005  }
1006 
1007  // dead cases, try to avoid case collisions
1008  for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1009  }
1010 
1011  {
1012  auto it = result.begin();
1013  auto last_value = (std::numeric_limits<switch_t>::min)();
1014  for (; fill != result.end(); *fill++ = last_value++) {
1015  while (last_value == *it) {
1016  ++last_value, ++it;
1017  }
1018  }
1019  }
1020 
1021  return result;
1022 }
1023 
1024 template <typename R, typename F, typename... Args>
1025 constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
1026  if constexpr (std::is_void_v<R>) {
1027  std::forward<F>(f)(std::forward<Args>(args)...);
1028  } else {
1029  return static_cast<R>(std::forward<F>(f)(std::forward<Args>(args)...));
1030  }
1031 }
1032 
1033 enum class case_call_t {
1034  index,
1035  value
1036 };
1037 
1038 template <typename T = void>
1039 inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
1040 
1041 template <>
1042 inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
1043 
1044 template <auto* Arr, typename Hash>
1045 constexpr bool has_duplicate() noexcept {
1046  using value_t = std::decay_t<decltype((*Arr)[0])>;
1047  using hash_value_t = std::invoke_result_t<Hash, value_t>;
1048  std::array<hash_value_t, Arr->size()> hashes{};
1049  std::size_t size = 0;
1050  for (auto elem : *Arr) {
1051  hashes[size] = hash_v<Hash>(elem);
1052  for (auto i = size++; i > 0; --i) {
1053  if (hashes[i] < hashes[i - 1]) {
1054  auto tmp = hashes[i];
1055  hashes[i] = hashes[i - 1];
1056  hashes[i - 1] = tmp;
1057  } else if (hashes[i] == hashes[i - 1]) {
1058  return false;
1059  } else {
1060  break;
1061  }
1062  }
1063  }
1064  return true;
1065 }
1066 
1067 #define MAGIC_ENUM_CASE(val) \
1068  case cases[val]: \
1069  if constexpr ((val) + Page < size) { \
1070  if (!pred(values[val + Page], searched)) { \
1071  break; \
1072  } \
1073  if constexpr (CallValue == case_call_t::index) { \
1074  if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1075  return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1076  } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1077  MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1078  } \
1079  } else if constexpr (CallValue == case_call_t::value) { \
1080  if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1081  return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1082  } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1083  MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1084  } \
1085  } \
1086  break; \
1087  } else [[fallthrough]];
1088 
1089 template <auto* GlobValues,
1090  case_call_t CallValue,
1091  std::size_t Page = 0,
1092  typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,
1093  typename BinaryPredicate = std::equal_to<>,
1094  typename Lambda,
1095  typename ResultGetterType>
1096 constexpr decltype(auto) constexpr_switch(
1097  Lambda&& lambda,
1098  typename std::decay_t<decltype(*GlobValues)>::value_type searched,
1099  ResultGetterType&& def,
1100  BinaryPredicate&& pred = {}) {
1101  using result_t = std::invoke_result_t<ResultGetterType>;
1102  using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash, typename Hash::secondary_hash>;
1103  static_assert(has_duplicate<GlobValues, hash_t>(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues.");
1104  constexpr std::array values = *GlobValues;
1105  constexpr std::size_t size = values.size();
1106  constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1107 
1108  switch (hash_v<hash_t>(searched)) {
1109  MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE)
1110  default:
1111  if constexpr (size > 256 + Page) {
1112  return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1113  }
1114  break;
1115  }
1116  return def();
1117 }
1118 
1119 #undef MAGIC_ENUM_CASE
1120 
1121 #endif
1122 
1123 } // namespace magic_enum::detail
1124 
1125 // Checks is magic_enum supported compiler.
1127 
1128 template <typename T>
1130 
1131 // Checks whether T is an Unscoped enumeration type.
1132 // 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.
1133 template <typename T>
1135 
1136 template <typename T>
1138 
1139 // Checks whether T is an Scoped enumeration type.
1140 // 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.
1141 template <typename T>
1143 
1144 template <typename T>
1146 
1147 // If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.
1148 // 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.
1149 template <typename T>
1151 
1152 template <typename T>
1154 
1155 template <auto V>
1157 
1158 // Returns type name of enum.
1159 template <typename E>
1160 [[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t<E, string_view> {
1161  constexpr string_view name = detail::type_name_v<std::decay_t<E>>;
1162  static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name.");
1163 
1164  return name;
1165 }
1166 
1167 // Returns number of enum values.
1168 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1169 [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t<E, std::size_t> {
1170  return detail::count_v<std::decay_t<E>, S>;
1171 }
1172 
1173 // Returns enum value at specified index.
1174 // No bounds checking is performed: the behavior is undefined if index >= number of enum values.
1175 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1176 [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
1177  using D = std::decay_t<E>;
1178  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1179 
1180  if constexpr (detail::is_sparse_v<D, S>) {
1181  return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
1182  } else {
1183  constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v<D, S>) : detail::min_v<D, S>;
1184 
1185  return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
1186  }
1187 }
1188 
1189 // Returns enum value at specified index.
1190 template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1191 [[nodiscard]] constexpr auto enum_value() 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  static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");
1195 
1196  return enum_value<D, S>(I);
1197 }
1198 
1199 // Returns std::array with enum values, sorted by enum value.
1200 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1201 [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
1202  using D = std::decay_t<E>;
1203  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1204 
1205  return detail::values_v<D, S>;
1206 }
1207 
1208 // Returns integer value from enum value.
1209 template <typename E>
1210 [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1211  return static_cast<underlying_type_t<E>>(value);
1212 }
1213 
1214 // Returns underlying value from enum value.
1215 template <typename E>
1216 [[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1217  return static_cast<underlying_type_t<E>>(value);
1218 }
1219 
1220 // Obtains index in enum values from enum value.
1221 // Returns optional with index.
1222 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1223 [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1224  using D = std::decay_t<E>;
1225  using U = underlying_type_t<D>;
1226  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1227 
1228  if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
1229 #if defined(MAGIC_ENUM_ENABLE_HASH)
1230  return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
1231  [](std::size_t i) { return optional<std::size_t>{i}; },
1232  value,
1233  detail::default_result_type_lambda<optional<std::size_t>>);
1234 #else
1235  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1236  if (enum_value<D, S>(i) == value) {
1237  return i;
1238  }
1239  }
1240  return {}; // Invalid value or out of range.
1241 #endif
1242  } else {
1243  const auto v = static_cast<U>(value);
1244  if (v >= detail::min_v<D, S> && v <= detail::max_v<D, S>) {
1245  return static_cast<std::size_t>(v - detail::min_v<D, S>);
1246  }
1247  return {}; // Invalid value or out of range.
1248  }
1249 }
1250 
1251 // Obtains index in enum values from enum value.
1252 // Returns optional with index.
1253 template <detail::enum_subtype S, typename E>
1254 [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1255  using D = std::decay_t<E>;
1256  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1257 
1258  return enum_index<D, S>(value);
1259 }
1260 
1261 // Obtains index in enum values from static storage enum variable.
1262 template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1263 [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
1264  using D = std::decay_t<decltype(V)>;
1265  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1266  constexpr auto index = enum_index<D, S>(V);
1267  static_assert(index, "magic_enum::enum_index enum value does not have a index.");
1268 
1269  return *index;
1270 }
1271 
1272 // Returns name from static storage enum variable.
1273 // This version is much lighter on the compile times and is not restricted to the enum_range limitation.
1274 template <auto V>
1275 [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t<decltype(V), string_view> {
1276  constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;
1277  static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");
1278 
1279  return name;
1280 }
1281 
1282 // Returns name from enum value.
1283 // If enum value does not have name or value out of range, returns empty string.
1284 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1285 [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
1286  using D = std::decay_t<E>;
1287  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1288 
1289  if (const auto i = enum_index<D, S>(value)) {
1290  return detail::names_v<D, S>[*i];
1291  }
1292  return {};
1293 }
1294 
1295 // Returns name from enum value.
1296 // If enum value does not have name or value out of range, returns empty string.
1297 template <detail::enum_subtype S, typename E>
1298 [[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t<E, string_view> {
1299  using D = std::decay_t<E>;
1300  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1301 
1302  return enum_name<D, S>(value);
1303 }
1304 
1305 // Returns std::array with names, sorted by enum value.
1306 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1307 [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
1308  using D = std::decay_t<E>;
1309  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1310 
1311  return detail::names_v<D, S>;
1312 }
1313 
1314 // Returns std::array with pairs (value, name), sorted by enum value.
1315 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1316 [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
1317  using D = std::decay_t<E>;
1318  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1319 
1320  return detail::entries_v<D, S>;
1321 }
1322 
1323 // Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
1325 
1326 // Obtains enum value from integer value.
1327 // Returns optional with enum value.
1328 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1329 [[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
1330  using D = std::decay_t<E>;
1331  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1332 
1333  if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
1334 #if defined(MAGIC_ENUM_ENABLE_HASH)
1335  return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
1336  [](D v) { return optional<D>{v}; },
1337  static_cast<D>(value),
1338  detail::default_result_type_lambda<optional<D>>);
1339 #else
1340  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1341  if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
1342  return static_cast<D>(value);
1343  }
1344  }
1345  return {}; // Invalid value or out of range.
1346 #endif
1347  } else {
1348  if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
1349  return static_cast<D>(value);
1350  }
1351  return {}; // Invalid value or out of range.
1352  }
1353 }
1354 
1355 // Obtains enum value from name.
1356 // Returns optional with enum value.
1357 template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
1358 [[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> {
1359  using D = std::decay_t<E>;
1360  static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1361 
1362 #if defined(MAGIC_ENUM_ENABLE_HASH)
1363  if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
1364  return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
1365  [](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
1366  value,
1367  detail::default_result_type_lambda<optional<D>>,
1368  [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
1369  }
1370 #endif
1371  for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1372  if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
1373  return enum_value<D, S>(i);
1374  }
1375  }
1376  return {}; // Invalid value or out of range.
1377 }
1378 
1379 // Checks whether enum contains value with such value.
1380 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1381 [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
1382  using D = std::decay_t<E>;
1383  using U = underlying_type_t<D>;
1384 
1385  return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1386 }
1387 
1388 // Checks whether enum contains value with such value.
1389 template <detail::enum_subtype S, typename E>
1390 [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
1391  using D = std::decay_t<E>;
1392  using U = underlying_type_t<D>;
1393 
1394  return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1395 }
1396 
1397 // Checks whether enum contains value with such integer value.
1398 template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1399 [[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
1400  using D = std::decay_t<E>;
1401 
1402  return static_cast<bool>(enum_cast<D, S>(value));
1403 }
1404 
1405 // Checks whether enum contains enumerator with such name.
1406 template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
1407 [[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
1408  using D = std::decay_t<E>;
1409 
1410  return static_cast<bool>(enum_cast<D, S>(value, std::move(p)));
1411 }
1412 
1413 template <bool AsFlags = true>
1415 
1416 template <bool AsFlags = true>
1418 
1419 namespace bitwise_operators {
1420 
1421 template <typename E, detail::enable_if_t<E, int> = 0>
1422 constexpr E operator~(E rhs) noexcept {
1423  return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));
1424 }
1425 
1426 template <typename E, detail::enable_if_t<E, int> = 0>
1427 constexpr E operator|(E lhs, E rhs) noexcept {
1428  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));
1429 }
1430 
1431 template <typename E, detail::enable_if_t<E, int> = 0>
1432 constexpr E operator&(E lhs, E rhs) noexcept {
1433  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));
1434 }
1435 
1436 template <typename E, detail::enable_if_t<E, int> = 0>
1437 constexpr E operator^(E lhs, E rhs) noexcept {
1438  return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));
1439 }
1440 
1441 template <typename E, detail::enable_if_t<E, int> = 0>
1442 constexpr E& operator|=(E& lhs, E rhs) noexcept {
1443  return lhs = (lhs | rhs);
1444 }
1445 
1446 template <typename E, detail::enable_if_t<E, int> = 0>
1447 constexpr E& operator&=(E& lhs, E rhs) noexcept {
1448  return lhs = (lhs & rhs);
1449 }
1450 
1451 template <typename E, detail::enable_if_t<E, int> = 0>
1452 constexpr E& operator^=(E& lhs, E rhs) noexcept {
1453  return lhs = (lhs ^ rhs);
1454 }
1455 
1456 } // namespace magic_enum::bitwise_operators
1457 
1458 } // namespace magic_enum
1459 
1460 #if defined(__clang__)
1461 # pragma clang diagnostic pop
1462 #elif defined(__GNUC__)
1463 # pragma GCC diagnostic pop
1464 #elif defined(_MSC_VER)
1465 # pragma warning(pop)
1466 #endif
1467 
1468 #undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
1469 #undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
1470 #undef MAGIC_ENUM_VS_2017_WORKAROUND
1471 #undef MAGIC_ENUM_ARRAY_CONSTEXPR
1472 #undef MAGIC_ENUM_FOR_EACH_256
1473 
1474 #endif // NEARGYE_MAGIC_ENUM_HPP
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
magic_enum::as_common
constexpr auto as_common
Definition: magic_enum.hpp:1417
magic_enum::Enum
detail::enum_concept< T > Enum
Definition: magic_enum.hpp:1129
magic_enum::detail::static_str< 0 >::data
constexpr const char_type * data() const noexcept
Definition: magic_enum.hpp:288
magic_enum::is_unscoped_enum
Definition: magic_enum.hpp:1134
magic_enum::customize::enum_range::max
static constexpr int max
Definition: magic_enum.hpp:170
magic_enum::customize::customize_t::customize_t
constexpr customize_t(string_view srt)
Definition: magic_enum.hpp:187
magic_enum::case_insensitive
constexpr auto case_insensitive
Definition: magic_enum.hpp:1324
magic_enum::detail::enum_subtype::flags
@ flags
MAGIC_ENUM_RANGE_MAX
#define MAGIC_ENUM_RANGE_MAX
Definition: magic_enum.hpp:106
magic_enum::detail::case_insensitive::to_lower
static constexpr char_type to_lower(char_type c) noexcept
Definition: magic_enum.hpp:297
magic_enum::detail::enum_name
constexpr auto enum_name() noexcept
Definition: magic_enum.hpp:596
magic_enum::detail::underlying_type
Definition: magic_enum.hpp:907
magic_enum::char_type
string_view::value_type char_type
Definition: magic_enum.hpp:145
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:343
magic_enum::detail::is_default_predicate
constexpr bool is_default_predicate() noexcept
Definition: magic_enum.hpp:331
magic_enum::customize::enum_name
constexpr customize_t enum_name(E) noexcept
Definition: magic_enum.hpp:201
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:274
magic_enum::detail::is_sparse
constexpr bool is_sparse() noexcept
Definition: magic_enum.hpp:851
MAGIC_ENUM_V
#define MAGIC_ENUM_V(O)
magic_enum::customize::invalid_tag
constexpr auto invalid_tag
Definition: magic_enum.hpp:197
magic_enum::detail::is_enum_v
constexpr bool is_enum_v
Definition: magic_enum.hpp:414
magic_enum::detail::valid_count_t::valid
bool valid[N]
Definition: magic_enum.hpp:731
magic_enum::detail::is_nothrow_invocable
constexpr bool is_nothrow_invocable()
Definition: magic_enum.hpp:337
magic_enum::detail::valid_count
constexpr void valid_count(bool *valid, std::size_t &count) noexcept
Definition: magic_enum.hpp:711
magic_enum::bitwise_operators::operator|=
constexpr E & operator|=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1442
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:889
magic_enum::detail::subtype
constexpr enum_subtype subtype(std::true_type) noexcept
Definition: magic_enum.hpp:777
magic_enum::customize::detail::customize_tag::default_tag
@ default_tag
MAGIC_ENUM_RANGE_MIN
#define MAGIC_ENUM_RANGE_MIN
Definition: magic_enum.hpp:100
magic_enum::detail::names
constexpr auto names(std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:827
magic_enum::bitwise_operators::operator|
constexpr E operator|(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1427
magic_enum::detail::is_unscoped_enum
Definition: magic_enum.hpp:901
detail
detail namespace with internal helper functions
Definition: json.hpp:248
magic_enum::detail::case_insensitive
Definition: magic_enum.hpp:296
magic_enum::detail::static_str::static_str
constexpr static_str(str_view str) noexcept
Definition: magic_enum.hpp:255
magic_enum::detail::static_str< 0 >::static_str
constexpr static_str(string_view) noexcept
Definition: magic_enum.hpp:286
magic_enum::detail::static_str< 0 >
Definition: magic_enum.hpp:280
MAGIC_ENUM_FOR_EACH_256
#define MAGIC_ENUM_FOR_EACH_256(T)
Definition: magic_enum.hpp:700
magic_enum::detail::has_is_flags
Definition: magic_enum.hpp:230
magic_enum::bitwise_operators::operator^
constexpr E operator^(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1437
magic_enum::detail::str_view::size_
std::size_t size_
Definition: magic_enum.hpp:249
magic_enum::detail::names_t
decltype((names_v< D, S >)) names_t
Definition: magic_enum.hpp:836
magic_enum::detail::static_str::size
constexpr std::uint16_t size() const noexcept
Definition: magic_enum.hpp:265
magic_enum::bitwise_operators::operator^=
constexpr E & operator^=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1452
magic_enum::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:664
magic_enum::detail::is_sparse_v
constexpr bool is_sparse_v
Definition: magic_enum.hpp:866
magic_enum::detail::static_str< 0 >::size
constexpr std::uint16_t size() const noexcept
Definition: magic_enum.hpp:290
lexy::_detail::make_index_sequence
typename _make_index_sequence< Size >::type make_index_sequence
Definition: integer_sequence.hpp:55
magic_enum::bitwise_operators::operator&=
constexpr E & operator&=(E &lhs, E rhs) noexcept
Definition: magic_enum.hpp:1447
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:1169
magic_enum::customize::detail::customize_tag
customize_tag
Definition: magic_enum.hpp:177
lexy::count
constexpr auto count
Sink that counts all arguments.
Definition: fold.hpp:88
magic_enum::customize::enum_type_name
constexpr customize_t enum_type_name() noexcept
Definition: magic_enum.hpp:207
magic_enum::detail::is_reflected_v
constexpr bool is_reflected_v
Definition: magic_enum.hpp:877
lexy::_detail::void_t
void void_t
Definition: detect.hpp:12
magic_enum::detail::log2
constexpr I log2(I value) noexcept
Definition: magic_enum.hpp:391
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:408
magic_enum::detail::static_str::data
constexpr const char_type * data() const noexcept
Definition: magic_enum.hpp:263
magic_enum::detail::enum_subtype::common
@ common
magic_enum::detail::static_str
Definition: magic_enum.hpp:253
magic_enum::detail::enum_name_v
constexpr auto enum_name_v
Definition: magic_enum.hpp:618
magic_enum::enum_contains
constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t< E, bool >
Definition: magic_enum.hpp:1381
magic_enum::detail::str_view::str_
const char * str_
Definition: magic_enum.hpp:248
magic_enum::detail::values
constexpr auto values() noexcept
Definition: magic_enum.hpp:742
magic_enum::as_flags
constexpr auto as_flags
Definition: magic_enum.hpp:1414
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:1176
magic_enum::customize::customize_t::customize_t
constexpr customize_t(const char_type *srt)
Definition: magic_enum.hpp:188
magic_enum::is_unscoped_enum_v
constexpr bool is_unscoped_enum_v
Definition: magic_enum.hpp:1137
magic_enum::customize::detail::customize_tag::invalid_tag
@ invalid_tag
magic_enum::detail::entries_v
constexpr auto entries_v
Definition: magic_enum.hpp:845
magic_enum::enum_underlying
constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E >>
Definition: magic_enum.hpp:1216
magic_enum::detail::entries
constexpr auto entries(std::index_sequence< I... >) noexcept
Definition: magic_enum.hpp:839
magic_enum::detail::values_v
constexpr auto values_v
Definition: magic_enum.hpp:812
magic_enum::underlying_type_t
typename underlying_type< T >::type underlying_type_t
Definition: magic_enum.hpp:1153
magic_enum::is_magic_enum_supported
constexpr bool is_magic_enum_supported
Definition: magic_enum.hpp:1126
magic_enum::enum_index
constexpr auto enum_index(E value) noexcept -> detail::enable_if_t< E, optional< std::size_t >>
Definition: magic_enum.hpp:1223
magic_enum::detail::valid_count_t
Definition: magic_enum.hpp:729
magic_enum::detail::cmp_less
constexpr bool cmp_less(L lhs, R rhs) noexcept
Definition: magic_enum.hpp:371
magic_enum::detail::str_view
Definition: magic_enum.hpp:247
magic_enum::enum_entries
constexpr auto enum_entries() noexcept -> detail::enable_if_t< E, detail::entries_t< E, S >>
Definition: magic_enum.hpp:1316
MAGIC_ENUM_ASSERT
#define MAGIC_ENUM_ASSERT(...)
Definition: magic_enum.hpp:65
magic_enum::is_scoped_enum_v
constexpr bool is_scoped_enum_v
Definition: magic_enum.hpp:1145
magic_enum::customize::customize_t::customize_t
constexpr customize_t(detail::customize_tag tag)
Definition: magic_enum.hpp:189
magic_enum::enum_values
constexpr auto enum_values() noexcept -> detail::enable_if_t< E, detail::values_t< E, S >>
Definition: magic_enum.hpp:1201
lexy::_detail::range_size
constexpr std::size_t range_size(Iterator begin, Sentinel end)
Definition: iterator.hpp:22
lexyd::digits
constexpr auto digits
Matches a non-empty list of digits.
Definition: digit.hpp:531
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:417
magic_enum::detail::type_name
constexpr auto type_name() noexcept
Definition: magic_enum.hpp:472
magic_enum::detail::subtype_v
constexpr auto subtype_v
Definition: magic_enum.hpp:809
f
static FILE * f
Definition: minitrace.cpp:74
magic_enum::detail::max_v
constexpr auto max_v
Definition: magic_enum.hpp:824
magic_enum::detail::min_v
constexpr auto min_v
Definition: magic_enum.hpp:821
magic_enum::detail::enum_concept
T enum_concept
Definition: magic_enum.hpp:892
magic_enum::bitwise_operators::operator~
constexpr E operator~(E rhs) noexcept
Definition: magic_enum.hpp:1422
magic_enum::detail::range_min
Definition: magic_enum.hpp:236
magic_enum::customize::enum_range
Definition: magic_enum.hpp:168
magic_enum::is_scoped_enum
Definition: magic_enum.hpp:1142
magic_enum::detail::ualue
constexpr U ualue(std::size_t i) noexcept
Definition: magic_enum.hpp:651
magic_enum::detail::static_str< 0 >::static_str
constexpr static_str(str_view) noexcept
Definition: magic_enum.hpp:284
wildcards::detail::is_set_state::first
@ first
magic_enum::detail::is_reflected
Definition: magic_enum.hpp:869
magic_enum::detail::count_v
constexpr auto count_v
Definition: magic_enum.hpp:818
magic_enum::customize::enum_range::min
static constexpr int min
Definition: magic_enum.hpp:169
magic_enum::detail::type_name_v
constexpr auto type_name_v
Definition: magic_enum.hpp:490
magic_enum::detail::is_scoped_enum
Definition: magic_enum.hpp:895
magic_enum::customize::customize_t
Definition: magic_enum.hpp:185
magic_enum::enum_name
constexpr auto enum_name() noexcept -> detail::enable_if_t< decltype(V), string_view >
Definition: magic_enum.hpp:1275
magic_enum::detail::enum_constant
std::integral_constant< E, V > enum_constant
Definition: magic_enum.hpp:224
std
Definition: std.hpp:30
magic_enum::detail::find
constexpr std::size_t find(string_view str, char_type c) noexcept
Definition: magic_enum.hpp:308
magic_enum::detail::names_v
constexpr auto names_v
Definition: magic_enum.hpp:833
magic_enum::detail::reflected_max
constexpr int reflected_max() noexcept
Definition: magic_enum.hpp:685
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:1329
magic_enum::detail::enable_if_enum
Definition: magic_enum.hpp:880
magic_enum::customize::default_tag
constexpr auto default_tag
Definition: magic_enum.hpp:195
magic_enum::detail::always_false_v
constexpr bool always_false_v
Definition: magic_enum.hpp:227
magic_enum::detail::range_max
Definition: magic_enum.hpp:242
magic_enum::underlying_type
Definition: magic_enum.hpp:1150
magic_enum::detail::valid_count_t::count
std::size_t count
Definition: magic_enum.hpp:730
magic_enum
Definition: magic_enum.hpp:122
magic_enum::enum_names
constexpr auto enum_names() noexcept -> detail::enable_if_t< E, detail::names_t< E, S >>
Definition: magic_enum.hpp:1307
magic_enum::detail::is_valid
constexpr bool is_valid() noexcept
Definition: magic_enum.hpp:621
detail::value_t
value_t
the JSON type enumeration
Definition: json.hpp:2872
detail::bool_constant
std::integral_constant< bool, Value > bool_constant
Definition: json.hpp:4156
magic_enum::bitwise_operators::operator&
constexpr E operator&(E lhs, E rhs) noexcept
Definition: magic_enum.hpp:1432
magic_enum::detail::static_str::static_str
constexpr static_str(string_view str) noexcept
Definition: magic_enum.hpp:259
magic_enum::detail::reflected_min
constexpr int reflected_min() noexcept
Definition: magic_enum.hpp:669
magic_enum::detail::enum_subtype
enum_subtype
Definition: magic_enum.hpp:645
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:271
magic_enum::enum_constant
detail::enum_constant< V > enum_constant
Definition: magic_enum.hpp:1156
magic_enum::enum_type_name
constexpr auto enum_type_name() noexcept -> detail::enable_if_t< E, string_view >
Definition: magic_enum.hpp:1160
lexyd::p
constexpr auto p
Parses the production.
Definition: production.hpp:127
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:303
magic_enum::detail::supported
Definition: magic_enum.hpp:216
magic_enum::detail::entries_t
decltype((entries_v< D, S >)) entries_t
Definition: magic_enum.hpp:848
magic_enum::detail::values_t
decltype((values_v< D, S >)) values_t
Definition: magic_enum.hpp:815
magic_enum::enum_integer
constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E >>
Definition: magic_enum.hpp:1210
lexy::_detail::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:184
detail::enable_if_t
typename std::enable_if< B, T >::type enable_if_t
Definition: json.hpp:3095
magic_enum::detail::enable_if_enum< true, R >::type
R type
Definition: magic_enum.hpp:884
magic_enum::detail::static_str::chars_
char_type chars_[static_cast< std::size_t >(N)+1]
Definition: magic_enum.hpp:276


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:07