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