hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
magic_enum.h
Go to the documentation of this file.
1// __ __ _ ______ _____
2// | \/ | (_) | ____| / ____|_ _
3// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
4// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
5// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
6// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
7// __/ | https://github.com/Neargye/magic_enum
8// |___/ version 0.9.6
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 6
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
126namespace 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)
130MAGIC_ENUM_USING_ALIAS_OPTIONAL
131#else
132using 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)
137MAGIC_ENUM_USING_ALIAS_STRING_VIEW
138#else
139using 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)
144MAGIC_ENUM_USING_ALIAS_STRING
145#else
146using std::string;
147#endif
148
149using char_type = string_view::value_type;
150static_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");
151static_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
166namespace 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.
171template <typename E>
173 static constexpr int min = MAGIC_ENUM_RANGE_MIN;
174 static constexpr int max = MAGIC_ENUM_RANGE_MAX;
175};
176
177static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
178
179namespace detail {
180
181enum class customize_tag {
185};
186
187} // namespace magic_enum::customize::detail
188
189class 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.
204template <typename E>
205constexpr 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.
210template <typename E>
211constexpr customize_t enum_type_name() noexcept {
212 return default_tag;
213}
214
215} // namespace magic_enum::customize
216
217namespace detail {
218
219template <typename T>
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
227template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
228using enum_constant = std::integral_constant<E, V>;
229
230template <typename... T>
231inline constexpr bool always_false_v = false;
232
233template <typename T, typename = void>
234struct has_is_flags : std::false_type {};
235
236template <typename T>
237struct 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
239template <typename T, typename = void>
240struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
241
242template <typename T>
243struct 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
245template <typename T, typename = void>
246struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
247
248template <typename T>
249struct 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
251struct str_view {
252 const char* str_ = nullptr;
253 std::size_t size_ = 0;
254};
255
256template <std::uint16_t N>
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
283template <>
284class 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
299template <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
312constexpr 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
334template <typename BinaryPredicate>
335constexpr 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
340template <typename BinaryPredicate>
341constexpr 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
346template <typename BinaryPredicate>
347constexpr 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
374template <typename L, typename R>
375constexpr 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
394template <typename I>
395constexpr 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
411template <typename T, std::size_t N, std::size_t... I>
412constexpr 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
417template <typename T>
418inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;
419
420template <typename E>
421constexpr 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
475template <typename E>
476constexpr 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
493template <typename E>
494inline constexpr auto type_name_v = type_name<E>();
495
496template <auto V>
497constexpr 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)
568template <typename E, E V>
569constexpr 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
599template <typename E, E V>
600constexpr 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
621template <typename E, E V>
622inline constexpr auto enum_name_v = enum_name<E, V>();
623
624template <typename E, auto V>
625constexpr bool is_valid() noexcept {
626#if defined(__clang__) && __clang_major__ >= 16
627 // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
628 constexpr E v = __builtin_bit_cast(E, V);
629#else
630 constexpr E v = static_cast<E>(V);
631#endif
632 [[maybe_unused]] constexpr auto custom = customize::enum_name<E>(v);
633 static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
634 if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
635 constexpr auto name = custom.second;
636 static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
637 return name.size() != 0;
638 } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
639#if defined(MAGIC_ENUM_VS_2017_WORKAROUND)
640 return n<E, v>().size_ != 0;
641#else
642 return n<v>().size_ != 0;
643#endif
644 } else {
645 return false;
646 }
647}
648
649enum class enum_subtype {
650 common,
651 flags
652};
653
654template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
655constexpr U ualue(std::size_t i) noexcept {
656 if constexpr (std::is_same_v<U, bool>) { // bool special case
657 static_assert(O == 0, "magic_enum::detail::ualue requires valid offset.");
658
659 return static_cast<U>(i);
660 } else if constexpr (S == enum_subtype::flags) {
661 return static_cast<U>(U{1} << static_cast<U>(static_cast<int>(i) + O));
662 } else {
663 return static_cast<U>(static_cast<int>(i) + O);
664 }
665}
666
667template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
668constexpr E value(std::size_t i) noexcept {
669 return static_cast<E>(ualue<E, O, S>(i));
670}
671
672template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
673constexpr int reflected_min() noexcept {
674 if constexpr (S == enum_subtype::flags) {
675 return 0;
676 } else {
677 constexpr auto lhs = range_min<E>::value;
678 constexpr auto rhs = (std::numeric_limits<U>::min)();
679
680 if constexpr (cmp_less(rhs, lhs)) {
681 return lhs;
682 } else {
683 return rhs;
684 }
685 }
686}
687
688template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
689constexpr int reflected_max() noexcept {
690 if constexpr (S == enum_subtype::flags) {
691 return std::numeric_limits<U>::digits - 1;
692 } else {
693 constexpr auto lhs = range_max<E>::value;
694 constexpr auto rhs = (std::numeric_limits<U>::max)();
695
696 if constexpr (cmp_less(lhs, rhs)) {
697 return lhs;
698 } else {
699 return rhs;
700 }
701 }
702}
703
704#define MAGIC_ENUM_FOR_EACH_256(T) \
705 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) \
706 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) \
707 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) \
708 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) \
709 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) \
710 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) \
711 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) \
712 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)
713
714template <typename E, enum_subtype S, std::size_t Size, int Min, std::size_t I>
715constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
716#define MAGIC_ENUM_V(O) \
717 if constexpr ((I + O) < Size) { \
718 if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
719 valid[I + O] = true; \
720 ++count; \
721 } \
722 }
723
725
726 if constexpr ((I + 256) < Size) {
727 valid_count<E, S, Size, Min, I + 256>(valid, count);
728 }
729#undef MAGIC_ENUM_V
730}
731
732template <std::size_t N>
734 std::size_t count = 0;
735 bool valid[N] = {};
736};
737
738template <typename E, enum_subtype S, std::size_t Size, int Min>
739constexpr auto valid_count() noexcept {
741 valid_count<E, S, Size, Min, 0>(vc.valid, vc.count);
742 return vc;
743}
744
745template <typename E, enum_subtype S, std::size_t Size, int Min>
746constexpr auto values() noexcept {
747 constexpr auto vc = valid_count<E, S, Size, Min>();
748
749 if constexpr (vc.count > 0) {
750#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
751 std::array<E, vc.count> values = {};
752#else
753 E values[vc.count] = {};
754#endif
755 for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
756 if (vc.valid[i]) {
757 values[v++] = value<E, Min, S>(i);
758 }
759 }
760#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
761 return values;
762#else
763 return to_array(values, std::make_index_sequence<vc.count>{});
764#endif
765 } else {
766 return std::array<E, 0>{};
767 }
768}
769
770template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
771constexpr auto values() noexcept {
772 constexpr auto min = reflected_min<E, S>();
773 constexpr auto max = reflected_max<E, S>();
774 constexpr auto range_size = max - min + 1;
775 static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
776
777 return values<E, S, range_size, min>();
778}
779
780template <typename E, typename U = std::underlying_type_t<E>>
781constexpr enum_subtype subtype(std::true_type) noexcept {
782 if constexpr (std::is_same_v<U, bool>) { // bool special case
784 } else if constexpr (has_is_flags<E>::value) {
786 } else {
787#if defined(MAGIC_ENUM_AUTO_IS_FLAGS)
788 constexpr auto flags_values = values<E, enum_subtype::flags>();
789 constexpr auto default_values = values<E, enum_subtype::common>();
790 if (flags_values.size() == 0 || default_values.size() > flags_values.size()) {
792 }
793 for (std::size_t i = 0; i < default_values.size(); ++i) {
794 const auto v = static_cast<U>(default_values[i]);
795 if (v != 0 && (v & (v - 1)) != 0) {
797 }
798 }
799 return enum_subtype::flags;
800#else
802#endif
803 }
804}
805
806template <typename T>
807constexpr enum_subtype subtype(std::false_type) noexcept {
808 // For non-enum type return default common subtype.
810}
811
812template <typename E, typename D = std::decay_t<E>>
813inline constexpr auto subtype_v = subtype<D>(std::is_enum<D>{});
814
815template <typename E, enum_subtype S>
816inline constexpr auto values_v = values<E, S>();
817
818template <typename E, enum_subtype S, typename D = std::decay_t<E>>
819using values_t = decltype((values_v<D, S>));
820
821template <typename E, enum_subtype S>
822inline constexpr auto count_v = values_v<E, S>.size();
823
824template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
825inline constexpr auto min_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.front()) : U{0};
826
827template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
828inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.back()) : U{0};
829
830template <typename E, enum_subtype S, std::size_t... I>
831constexpr auto names(std::index_sequence<I...>) noexcept {
832 constexpr auto names = std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
833 return names;
834}
835
836template <typename E, enum_subtype S>
837inline constexpr auto names_v = names<E, S>(std::make_index_sequence<count_v<E, S>>{});
838
839template <typename E, enum_subtype S, typename D = std::decay_t<E>>
840using names_t = decltype((names_v<D, S>));
841
842template <typename E, enum_subtype S, std::size_t... I>
843constexpr auto entries(std::index_sequence<I...>) noexcept {
844 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]>}...}};
845 return entries;
846}
847
848template <typename E, enum_subtype S>
849inline constexpr auto entries_v = entries<E, S>(std::make_index_sequence<count_v<E, S>>{});
850
851template <typename E, enum_subtype S, typename D = std::decay_t<E>>
852using entries_t = decltype((entries_v<D, S>));
853
854template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
855constexpr bool is_sparse() noexcept {
856 if constexpr (count_v<E, S> == 0) {
857 return false;
858 } else if constexpr (std::is_same_v<U, bool>) { // bool special case
859 return false;
860 } else {
861 constexpr auto max = (S == enum_subtype::flags) ? log2(max_v<E, S>) : max_v<E, S>;
862 constexpr auto min = (S == enum_subtype::flags) ? log2(min_v<E, S>) : min_v<E, S>;
863 constexpr auto range_size = max - min + 1;
864
865 return range_size != count_v<E, S>;
866 }
867}
868
869template <typename E, enum_subtype S = subtype_v<E>>
870inline constexpr bool is_sparse_v = is_sparse<E, S>();
871
872template <typename E, enum_subtype S>
874#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
875 : std::true_type {};
876#else
877 : std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
878#endif
879
880template <typename E, enum_subtype S>
881inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};
882
883template <bool, typename R>
885
886template <typename R>
887struct enable_if_enum<true, R> {
888 using type = R;
889 static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
890};
891
892template <typename T, typename R, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
893using 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;
894
895template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
896using enum_concept = T;
897
898template <typename T, bool = std::is_enum_v<T>>
899struct is_scoped_enum : std::false_type {};
900
901template <typename T>
902struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
903
904template <typename T, bool = std::is_enum_v<T>>
905struct is_unscoped_enum : std::false_type {};
906
907template <typename T>
908struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};
909
910template <typename T, bool = std::is_enum_v<std::decay_t<T>>>
912
913template <typename T>
914struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
915
916#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
917
918template <typename Value, typename = void>
919struct constexpr_hash_t;
920
921template <typename Value>
922struct constexpr_hash_t<Value, std::enable_if_t<is_enum_v<Value>>> {
923 constexpr auto operator()(Value value) const noexcept {
924 using U = typename underlying_type<Value>::type;
925 if constexpr (std::is_same_v<U, bool>) { // bool special case
926 return static_cast<std::size_t>(value);
927 } else {
928 return static_cast<U>(value);
929 }
930 }
931 using secondary_hash = constexpr_hash_t;
932};
933
934template <typename Value>
935struct constexpr_hash_t<Value, std::enable_if_t<std::is_same_v<Value, string_view>>> {
936 static constexpr std::uint32_t crc_table[256] {
937 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
938 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
939 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
940 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
941 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
942 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
943 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
944 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
945 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
946 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
947 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
948 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
949 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
950 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
951 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
952 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
953 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
954 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
955 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
956 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
957 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
958 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
959 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
960 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
961 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
962 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
963 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
964 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
965 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
966 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
967 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
968 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
969 };
970 constexpr std::uint32_t operator()(string_view value) const noexcept {
971 auto crc = static_cast<std::uint32_t>(0xffffffffL);
972 for (const auto c : value) {
973 crc = (crc >> 8) ^ crc_table[(crc ^ static_cast<std::uint32_t>(c)) & 0xff];
974 }
975 return crc ^ 0xffffffffL;
976 }
977
978 struct secondary_hash {
979 constexpr std::uint32_t operator()(string_view value) const noexcept {
980 auto acc = static_cast<std::uint64_t>(2166136261ULL);
981 for (const auto c : value) {
982 acc = ((acc ^ static_cast<std::uint64_t>(c)) * static_cast<std::uint64_t>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
983 }
984 return static_cast<std::uint32_t>(acc);
985 }
986 };
987};
988
989template <typename Hash>
990inline constexpr Hash hash_v{};
991
992template <auto* GlobValues, typename Hash>
993constexpr auto calculate_cases(std::size_t Page) noexcept {
994 constexpr std::array values = *GlobValues;
995 constexpr std::size_t size = values.size();
996
997 using switch_t = std::invoke_result_t<Hash, typename decltype(values)::value_type>;
998 static_assert(std::is_integral_v<switch_t> && !std::is_same_v<switch_t, bool>);
999 const std::size_t values_to = (std::min)(static_cast<std::size_t>(256), size - Page);
1000
1001 std::array<switch_t, 256> result{};
1002 auto fill = result.begin();
1003 {
1004 auto first = values.begin() + static_cast<std::ptrdiff_t>(Page);
1005 auto last = values.begin() + static_cast<std::ptrdiff_t>(Page + values_to);
1006 while (first != last) {
1007 *fill++ = hash_v<Hash>(*first++);
1008 }
1009 }
1010
1011 // dead cases, try to avoid case collisions
1012 for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<switch_t>::max)(); *fill++ = ++last_value) {
1013 }
1014
1015 {
1016 auto it = result.begin();
1017 auto last_value = (std::numeric_limits<switch_t>::min)();
1018 for (; fill != result.end(); *fill++ = last_value++) {
1019 while (last_value == *it) {
1020 ++last_value, ++it;
1021 }
1022 }
1023 }
1024
1025 return result;
1026}
1027
1028template <typename R, typename F, typename... Args>
1029constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
1030 if constexpr (std::is_void_v<R>) {
1031 std::forward<F>(f)(std::forward<Args>(args)...);
1032 } else {
1033 return static_cast<R>(std::forward<F>(f)(std::forward<Args>(args)...));
1034 }
1035}
1036
1037enum class case_call_t {
1038 index,
1039 value
1040};
1041
1042template <typename T = void>
1043inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
1044
1045template <>
1046inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
1047
1048template <auto* Arr, typename Hash>
1049constexpr bool has_duplicate() noexcept {
1050 using value_t = std::decay_t<decltype((*Arr)[0])>;
1051 using hash_value_t = std::invoke_result_t<Hash, value_t>;
1052 std::array<hash_value_t, Arr->size()> hashes{};
1053 std::size_t size = 0;
1054 for (auto elem : *Arr) {
1055 hashes[size] = hash_v<Hash>(elem);
1056 for (auto i = size++; i > 0; --i) {
1057 if (hashes[i] < hashes[i - 1]) {
1058 auto tmp = hashes[i];
1059 hashes[i] = hashes[i - 1];
1060 hashes[i - 1] = tmp;
1061 } else if (hashes[i] == hashes[i - 1]) {
1062 return false;
1063 } else {
1064 break;
1065 }
1066 }
1067 }
1068 return true;
1069}
1070
1071#define MAGIC_ENUM_CASE(val) \
1072 case cases[val]: \
1073 if constexpr ((val) + Page < size) { \
1074 if (!pred(values[val + Page], searched)) { \
1075 break; \
1076 } \
1077 if constexpr (CallValue == case_call_t::index) { \
1078 if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1079 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
1080 } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
1081 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1082 } \
1083 } else if constexpr (CallValue == case_call_t::value) { \
1084 if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1085 return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
1086 } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
1087 MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
1088 } \
1089 } \
1090 break; \
1091 } else [[fallthrough]];
1092
1093template <auto* GlobValues,
1094 case_call_t CallValue,
1095 std::size_t Page = 0,
1096 typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,
1097 typename BinaryPredicate = std::equal_to<>,
1098 typename Lambda,
1099 typename ResultGetterType>
1100constexpr decltype(auto) constexpr_switch(
1101 Lambda&& lambda,
1102 typename std::decay_t<decltype(*GlobValues)>::value_type searched,
1103 ResultGetterType&& def,
1104 BinaryPredicate&& pred = {}) {
1105 using result_t = std::invoke_result_t<ResultGetterType>;
1106 using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash, typename Hash::secondary_hash>;
1107 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.");
1108 constexpr std::array values = *GlobValues;
1109 constexpr std::size_t size = values.size();
1110 constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
1111
1112 switch (hash_v<hash_t>(searched)) {
1113 MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE)
1114 default:
1115 if constexpr (size > 256 + Page) {
1116 return constexpr_switch<GlobValues, CallValue, Page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
1117 }
1118 break;
1119 }
1120 return def();
1121}
1122
1123#undef MAGIC_ENUM_CASE
1124
1125#endif
1126
1127} // namespace magic_enum::detail
1128
1129// Checks is magic_enum supported compiler.
1131
1132template <typename T>
1134
1135// Checks whether T is an Unscoped enumeration type.
1136// 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.
1137template <typename T>
1139
1140template <typename T>
1142
1143// Checks whether T is an Scoped enumeration type.
1144// 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.
1145template <typename T>
1147
1148template <typename T>
1150
1151// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.
1152// 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.
1153template <typename T>
1155
1156template <typename T>
1158
1159template <auto V>
1161
1162// Returns type name of enum.
1163template <typename E>
1164[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t<E, string_view> {
1165 constexpr string_view name = detail::type_name_v<std::decay_t<E>>;
1166 static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name.");
1167
1168 return name;
1169}
1170
1171// Returns number of enum values.
1172template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1173[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t<E, std::size_t> {
1174 return detail::count_v<std::decay_t<E>, S>;
1175}
1176
1177// Returns enum value at specified index.
1178// No bounds checking is performed: the behavior is undefined if index >= number of enum values.
1179template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1180[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
1181 using D = std::decay_t<E>;
1182 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1183
1184 if constexpr (detail::is_sparse_v<D, S>) {
1185 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
1186 } else {
1187 constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v<D, S>) : detail::min_v<D, S>;
1188
1189 return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
1190 }
1191}
1192
1193// Returns enum value at specified index.
1194template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
1195[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
1196 using D = std::decay_t<E>;
1197 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1198 static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");
1199
1200 return enum_value<D, S>(I);
1201}
1202
1203// Returns std::array with enum values, sorted by enum value.
1204template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1205[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
1206 using D = std::decay_t<E>;
1207 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1208
1209 return detail::values_v<D, S>;
1210}
1211
1212// Returns integer value from enum value.
1213template <typename E>
1214[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1215 return static_cast<underlying_type_t<E>>(value);
1216}
1217
1218// Returns underlying value from enum value.
1219template <typename E>
1220[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t<E, underlying_type_t<E>> {
1221 return static_cast<underlying_type_t<E>>(value);
1222}
1223
1224// Obtains index in enum values from enum value.
1225// Returns optional with index.
1226template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1227[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1228 using D = std::decay_t<E>;
1229 using U = underlying_type_t<D>;
1230 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1231
1232 if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
1233#if defined(MAGIC_ENUM_ENABLE_HASH)
1234 return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
1235 [](std::size_t i) { return optional<std::size_t>{i}; },
1236 value,
1237 detail::default_result_type_lambda<optional<std::size_t>>);
1238#else
1239 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1240 if (enum_value<D, S>(i) == value) {
1241 return i;
1242 }
1243 }
1244 return {}; // Invalid value or out of range.
1245#endif
1246 } else {
1247 const auto v = static_cast<U>(value);
1248 if (v >= detail::min_v<D, S> && v <= detail::max_v<D, S>) {
1249 return static_cast<std::size_t>(v - detail::min_v<D, S>);
1250 }
1251 return {}; // Invalid value or out of range.
1252 }
1253}
1254
1255// Obtains index in enum values from enum value.
1256// Returns optional with index.
1257template <detail::enum_subtype S, typename E>
1258[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
1259 using D = std::decay_t<E>;
1260 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1261
1262 return enum_index<D, S>(value);
1263}
1264
1265// Obtains index in enum values from static storage enum variable.
1266template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
1267[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
1268 using D = std::decay_t<decltype(V)>;
1269 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1270 constexpr auto index = enum_index<D, S>(V);
1271 static_assert(index, "magic_enum::enum_index enum value does not have a index.");
1272
1273 return *index;
1274}
1275
1276// Returns name from static storage enum variable.
1277// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
1278template <auto V>
1279[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t<decltype(V), string_view> {
1280 constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;
1281 static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");
1282
1283 return name;
1284}
1285
1286// Returns name from enum value.
1287// If enum value does not have name or value out of range, returns empty string.
1288template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1289[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
1290 using D = std::decay_t<E>;
1291 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1292
1293 if (const auto i = enum_index<D, S>(value)) {
1294 return detail::names_v<D, S>[*i];
1295 }
1296 return {};
1297}
1298
1299// Returns name from enum value.
1300// If enum value does not have name or value out of range, returns empty string.
1301template <detail::enum_subtype S, typename E>
1302[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t<E, string_view> {
1303 using D = std::decay_t<E>;
1304 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1305
1306 return enum_name<D, S>(value);
1307}
1308
1309// Returns std::array with names, sorted by enum value.
1310template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1311[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
1312 using D = std::decay_t<E>;
1313 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1314
1315 return detail::names_v<D, S>;
1316}
1317
1318// Returns std::array with pairs (value, name), sorted by enum value.
1319template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1320[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
1321 using D = std::decay_t<E>;
1322 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1323
1324 return detail::entries_v<D, S>;
1325}
1326
1327// Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
1329
1330// Obtains enum value from integer value.
1331// Returns optional with enum value.
1332template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1333[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
1334 using D = std::decay_t<E>;
1335 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1336
1337 if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
1338#if defined(MAGIC_ENUM_ENABLE_HASH)
1339 return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
1340 [](D v) { return optional<D>{v}; },
1341 static_cast<D>(value),
1342 detail::default_result_type_lambda<optional<D>>);
1343#else
1344 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1345 if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
1346 return static_cast<D>(value);
1347 }
1348 }
1349 return {}; // Invalid value or out of range.
1350#endif
1351 } else {
1352 if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
1353 return static_cast<D>(value);
1354 }
1355 return {}; // Invalid value or out of range.
1356 }
1357}
1358
1359// Obtains enum value from name.
1360// Returns optional with enum value.
1361template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
1362[[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> {
1363 using D = std::decay_t<E>;
1364 static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
1365
1366#if defined(MAGIC_ENUM_ENABLE_HASH)
1367 if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
1368 return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
1369 [](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
1370 value,
1371 detail::default_result_type_lambda<optional<D>>,
1372 [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
1373 }
1374#endif
1375 for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
1376 if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
1377 return enum_value<D, S>(i);
1378 }
1379 }
1380 return {}; // Invalid value or out of range.
1381}
1382
1383// Checks whether enum contains value with such value.
1384template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1385[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
1386 using D = std::decay_t<E>;
1387 using U = underlying_type_t<D>;
1388
1389 return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1390}
1391
1392// Checks whether enum contains value with such value.
1393template <detail::enum_subtype S, typename E>
1394[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
1395 using D = std::decay_t<E>;
1396 using U = underlying_type_t<D>;
1397
1398 return static_cast<bool>(enum_cast<D, S>(static_cast<U>(value)));
1399}
1400
1401// Checks whether enum contains value with such integer value.
1402template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1403[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
1404 using D = std::decay_t<E>;
1405
1406 return static_cast<bool>(enum_cast<D, S>(value));
1407}
1408
1409// Checks whether enum contains enumerator with such name.
1410template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
1411[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
1412 using D = std::decay_t<E>;
1413
1414 return static_cast<bool>(enum_cast<D, S>(value, std::move(p)));
1415}
1416
1417// Returns true if the enum integer value is in the range of values that can be reflected.
1418template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1419[[nodiscard]] constexpr auto enum_reflected(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
1420 using D = std::decay_t<E>;
1421
1422 if constexpr (detail::is_reflected_v<D, S>) {
1423 constexpr auto min = detail::reflected_min<E, S>();
1424 constexpr auto max = detail::reflected_max<E, S>();
1425 return value >= min && value <= max;
1426 } else {
1427 return false;
1428 }
1429}
1430
1431// Returns true if the enum value is in the range of values that can be reflected.
1432template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
1433[[nodiscard]] constexpr auto enum_reflected(E value) noexcept -> detail::enable_if_t<E, bool> {
1434 using D = std::decay_t<E>;
1435
1436 return enum_reflected<D, S>(static_cast<underlying_type_t<D>>(value));
1437}
1438
1439// Returns true if the enum value is in the range of values that can be reflected.
1440template <detail::enum_subtype S, typename E>
1441[[nodiscard]] constexpr auto enum_reflected(E value) noexcept -> detail::enable_if_t<E, bool> {
1442 using D = std::decay_t<E>;
1443
1444 return enum_reflected<D, S>(value);
1445}
1446
1447template <bool AsFlags = true>
1449
1450template <bool AsFlags = true>
1452
1453namespace bitwise_operators {
1454
1455template <typename E, detail::enable_if_t<E, int> = 0>
1456constexpr E operator~(E rhs) noexcept {
1457 return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));
1458}
1459
1460template <typename E, detail::enable_if_t<E, int> = 0>
1461constexpr E operator|(E lhs, E rhs) noexcept {
1462 return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));
1463}
1464
1465template <typename E, detail::enable_if_t<E, int> = 0>
1466constexpr E operator&(E lhs, E rhs) noexcept {
1467 return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));
1468}
1469
1470template <typename E, detail::enable_if_t<E, int> = 0>
1471constexpr E operator^(E lhs, E rhs) noexcept {
1472 return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));
1473}
1474
1475template <typename E, detail::enable_if_t<E, int> = 0>
1476constexpr E& operator|=(E& lhs, E rhs) noexcept {
1477 return lhs = (lhs | rhs);
1478}
1479
1480template <typename E, detail::enable_if_t<E, int> = 0>
1481constexpr E& operator&=(E& lhs, E rhs) noexcept {
1482 return lhs = (lhs & rhs);
1483}
1484
1485template <typename E, detail::enable_if_t<E, int> = 0>
1486constexpr E& operator^=(E& lhs, E rhs) noexcept {
1487 return lhs = (lhs ^ rhs);
1488}
1489
1490} // namespace magic_enum::bitwise_operators
1491
1492} // namespace magic_enum
1493
1494#if defined(__clang__)
1495# pragma clang diagnostic pop
1496#elif defined(__GNUC__)
1497# pragma GCC diagnostic pop
1498#elif defined(_MSC_VER)
1499# pragma warning(pop)
1500#endif
1501
1502#undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN
1503#undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
1504#undef MAGIC_ENUM_VS_2017_WORKAROUND
1505#undef MAGIC_ENUM_ARRAY_CONSTEXPR
1506#undef MAGIC_ENUM_FOR_EACH_256
1507
1508#endif // NEARGYE_MAGIC_ENUM_HPP
constexpr customize_t(detail::customize_tag tag)
Definition magic_enum.h:193
constexpr customize_t(string_view srt)
Definition magic_enum.h:191
constexpr customize_t(const char_type *srt)
Definition magic_enum.h:192
static constexpr char_type to_lower(char_type c) noexcept
Definition magic_enum.h:301
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.h:307
constexpr std::uint16_t size() const noexcept
Definition magic_enum.h:294
constexpr static_str(string_view) noexcept
Definition magic_enum.h:290
constexpr static_str(str_view) noexcept
Definition magic_enum.h:288
constexpr const char_type * data() const noexcept
Definition magic_enum.h:292
constexpr static_str(string_view str, std::integer_sequence< std::uint16_t, I... >) noexcept
Definition magic_enum.h:278
char_type chars_[static_cast< std::size_t >(N)+1]
Definition magic_enum.h:280
constexpr static_str(string_view str) noexcept
Definition magic_enum.h:263
constexpr std::uint16_t size() const noexcept
Definition magic_enum.h:269
constexpr static_str(str_view str) noexcept
Definition magic_enum.h:259
constexpr const char_type * data() const noexcept
Definition magic_enum.h:267
constexpr static_str(const char *str, std::integer_sequence< std::uint16_t, I... >) noexcept
Definition magic_enum.h:275
#define MAGIC_ENUM_RANGE_MIN
Definition magic_enum.h:104
#define MAGIC_ENUM_RANGE_MAX
Definition magic_enum.h:110
#define MAGIC_ENUM_ASSERT(...)
Definition magic_enum.h:69
#define MAGIC_ENUM_FOR_EACH_256(T)
Definition magic_enum.h:704
#define MAGIC_ENUM_V(O)
constexpr E & operator|=(E &lhs, E rhs) noexcept
constexpr E operator|(E lhs, E rhs) noexcept
constexpr E & operator^=(E &lhs, E rhs) noexcept
constexpr E & operator&=(E &lhs, E rhs) noexcept
constexpr E operator&(E lhs, E rhs) noexcept
constexpr E operator~(E rhs) noexcept
constexpr E operator^(E lhs, E rhs) noexcept
constexpr auto invalid_tag
Definition magic_enum.h:201
constexpr auto default_tag
Definition magic_enum.h:199
constexpr customize_t enum_type_name() noexcept
Definition magic_enum.h:211
constexpr bool is_default_predicate() noexcept
Definition magic_enum.h:335
constexpr auto type_name_v
Definition magic_enum.h:494
constexpr auto type_name() noexcept
Definition magic_enum.h:476
constexpr int reflected_min() noexcept
Definition magic_enum.h:673
constexpr std::size_t find(string_view str, char_type c) noexcept
Definition magic_enum.h:312
constexpr bool is_sparse_v
Definition magic_enum.h:870
constexpr auto names_v
Definition magic_enum.h:837
constexpr bool cmp_less(L lhs, R rhs) noexcept
Definition magic_enum.h:375
decltype((values_v< D, S >)) values_t
Definition magic_enum.h:819
constexpr int reflected_max() noexcept
Definition magic_enum.h:689
decltype((names_v< D, S >)) names_t
Definition magic_enum.h:840
constexpr bool is_reflected_v
Definition magic_enum.h:881
constexpr auto entries_v
Definition magic_enum.h:849
constexpr bool is_enum_v
Definition magic_enum.h:418
constexpr auto valid_count() noexcept
Definition magic_enum.h:739
constexpr auto count_v
Definition magic_enum.h:822
constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate &&p) noexcept(is_nothrow_invocable< BinaryPredicate >())
Definition magic_enum.h:347
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N], std::index_sequence< I... >) noexcept
Definition magic_enum.h:412
constexpr bool is_nothrow_invocable()
Definition magic_enum.h:341
constexpr auto min_v
Definition magic_enum.h:825
constexpr auto values_v
Definition magic_enum.h:816
constexpr auto max_v
Definition magic_enum.h:828
constexpr I log2(I value) noexcept
Definition magic_enum.h:395
constexpr U ualue(std::size_t i) noexcept
Definition magic_enum.h:655
constexpr bool is_valid() noexcept
Definition magic_enum.h:625
constexpr auto subtype_v
Definition magic_enum.h:813
constexpr bool is_sparse() noexcept
Definition magic_enum.h:855
constexpr E value(std::size_t i) noexcept
Definition magic_enum.h:668
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.h:893
decltype((entries_v< D, S >)) entries_t
Definition magic_enum.h:852
constexpr auto enum_name_v
Definition magic_enum.h:622
constexpr auto names(std::index_sequence< I... >) noexcept
Definition magic_enum.h:831
constexpr auto values() noexcept
Definition magic_enum.h:746
constexpr enum_subtype subtype(std::true_type) noexcept
Definition magic_enum.h:781
constexpr bool always_false_v
Definition magic_enum.h:231
constexpr auto n() noexcept
Definition magic_enum.h:421
std::integral_constant< E, V > enum_constant
Definition magic_enum.h:228
constexpr auto enum_name() noexcept
Definition magic_enum.h:600
constexpr auto entries(std::index_sequence< I... >) noexcept
Definition magic_enum.h:843
constexpr auto as_flags
constexpr auto enum_names() noexcept -> detail::enable_if_t< E, detail::names_t< E, S > >
constexpr bool is_unscoped_enum_v
typename underlying_type< T >::type underlying_type_t
constexpr auto as_common
constexpr auto enum_index() noexcept -> detail::enable_if_t< decltype(V), std::size_t >
detail::enum_constant< V > enum_constant
constexpr auto enum_entries() noexcept -> detail::enable_if_t< E, detail::entries_t< E, S > >
detail::enum_concept< T > Enum
constexpr bool is_magic_enum_supported
constexpr auto enum_reflected(underlying_type_t< E > value) noexcept -> detail::enable_if_t< E, bool >
constexpr auto enum_cast(underlying_type_t< E > value) noexcept -> detail::enable_if_t< E, optional< std::decay_t< E > > >
constexpr bool is_scoped_enum_v
constexpr auto enum_value() noexcept -> detail::enable_if_t< E, std::decay_t< E > >
constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t< E, bool >
constexpr auto enum_values() noexcept -> detail::enable_if_t< E, detail::values_t< E, S > >
constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E > >
constexpr auto case_insensitive
constexpr auto enum_type_name() noexcept -> detail::enable_if_t< E, string_view >
string_view::value_type char_type
Definition magic_enum.h:149
constexpr auto enum_count() noexcept -> detail::enable_if_t< E, std::size_t >
constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t< E, underlying_type_t< E > >
constexpr auto enum_name() noexcept -> detail::enable_if_t< decltype(V), string_view >