Path: blob/a-new-beginning/SharedDependencies/Sources/magic_enum/include/magic_enum.hpp
2 views
// __ __ _ ______ _____1// | \/ | (_) | ____| / ____|_ _2// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_3// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|4// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|5// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|6// __/ | https://github.com/Neargye/magic_enum7// |___/ version 0.7.38//9// Licensed under the MIT License <http://opensource.org/licenses/MIT>.10// SPDX-License-Identifier: MIT11// Copyright (c) 2019 - 2021 Daniil Goncharov <[email protected]>.12//13// Permission is hereby granted, free of charge, to any person obtaining a copy14// of this software and associated documentation files (the "Software"), to deal15// in the Software without restriction, including without limitation the rights16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell17// copies of the Software, and to permit persons to whom the Software is18// furnished to do so, subject to the following conditions:19//20// The above copyright notice and this permission notice shall be included in all21// copies or substantial portions of the Software.22//23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE29// SOFTWARE.3031#ifndef NEARGYE_MAGIC_ENUM_HPP32#define NEARGYE_MAGIC_ENUM_HPP3334#define MAGIC_ENUM_VERSION_MAJOR 035#define MAGIC_ENUM_VERSION_MINOR 736#define MAGIC_ENUM_VERSION_PATCH 33738#include <array>39#include <cassert>40#include <cstdint>41#include <cstddef>42#include <iosfwd>43#include <limits>44#include <type_traits>45#include <utility>4647#if defined(MAGIC_ENUM_CONFIG_FILE)48#include MAGIC_ENUM_CONFIG_FILE49#endif5051#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)52#include <optional>53#endif54#if !defined(MAGIC_ENUM_USING_ALIAS_STRING)55#include <string>56#endif57#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)58#include <string_view>59#endif6061#if defined(__clang__)62# pragma clang diagnostic push63#elif defined(__GNUC__)64# pragma GCC diagnostic push65# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.66#elif defined(_MSC_VER)67# pragma warning(push)68# pragma warning(disable : 26495) // Variable 'static_string<N>::chars_' is uninitialized.69# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.70# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.71#endif7273// Checks magic_enum compiler compatibility.74#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 191075# undef MAGIC_ENUM_SUPPORTED76# define MAGIC_ENUM_SUPPORTED 177#endif7879// Checks magic_enum compiler aliases compatibility.80#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 192081# undef MAGIC_ENUM_SUPPORTED_ALIASES82# define MAGIC_ENUM_SUPPORTED_ALIASES 183#endif8485// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128.86// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN.87#if !defined(MAGIC_ENUM_RANGE_MIN)88# define MAGIC_ENUM_RANGE_MIN -12889#endif9091// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128.92// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.93#if !defined(MAGIC_ENUM_RANGE_MAX)94# define MAGIC_ENUM_RANGE_MAX 12895#endif9697namespace magic_enum {9899// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL.100#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL)101MAGIC_ENUM_USING_ALIAS_OPTIONAL102#else103using std::optional;104#endif105106// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW.107#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW)108MAGIC_ENUM_USING_ALIAS_STRING_VIEW109#else110using std::string_view;111#endif112113// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING.114#if defined(MAGIC_ENUM_USING_ALIAS_STRING)115MAGIC_ENUM_USING_ALIAS_STRING116#else117using std::string;118#endif119120namespace customize {121122// 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.123// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.124// If need another range for specific enum type, add specialization enum_range for necessary enum type.125template <typename E>126struct enum_range {127static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_range requires enum type.");128inline static constexpr int min = MAGIC_ENUM_RANGE_MIN;129inline static constexpr int max = MAGIC_ENUM_RANGE_MAX;130static_assert(max > min, "magic_enum::customize::enum_range requires max > min.");131};132133static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0.");134static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits<std::int16_t>::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN.");135136static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0.");137static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits<std::int16_t>::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX.");138139static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");140141// If need custom names for enum, add specialization enum_name for necessary enum type.142template <typename E>143constexpr string_view enum_name(E) noexcept {144static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_name requires enum type.");145146return {};147}148149} // namespace magic_enum::customize150151namespace detail {152153template <typename T>154struct supported155#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)156: std::true_type {};157#else158: std::false_type {};159#endif160161struct char_equal_to {162constexpr bool operator()(char lhs, char rhs) const noexcept {163return lhs == rhs;164}165};166167template <std::size_t N>168class static_string {169public:170constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_index_sequence<N>{}} {171assert(str.size() == N);172}173174constexpr const char* data() const noexcept { return chars_; }175176constexpr std::size_t size() const noexcept { return N; }177178constexpr operator string_view() const noexcept { return {data(), size()}; }179180private:181template <std::size_t... I>182constexpr static_string(string_view str, std::index_sequence<I...>) noexcept : chars_{str[I]..., '\0'} {}183184char chars_[N + 1];185};186187template <>188class static_string<0> {189public:190constexpr explicit static_string(string_view) noexcept {}191192constexpr const char* data() const noexcept { return nullptr; }193194constexpr std::size_t size() const noexcept { return 0; }195196constexpr operator string_view() const noexcept { return {}; }197};198199constexpr string_view pretty_name(string_view name) noexcept {200for (std::size_t i = name.size(); i > 0; --i) {201if (!((name[i - 1] >= '0' && name[i - 1] <= '9') ||202(name[i - 1] >= 'a' && name[i - 1] <= 'z') ||203(name[i - 1] >= 'A' && name[i - 1] <= 'Z') ||204(name[i - 1] == '_'))) {205name.remove_prefix(i);206break;207}208}209210if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') ||211(name.front() >= 'A' && name.front() <= 'Z') ||212(name.front() == '_'))) {213return name;214}215216return {}; // Invalid name.217}218219constexpr std::size_t find(string_view str, char c) noexcept {220#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)221// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc222// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html223constexpr bool workaround = true;224#else225constexpr bool workaround = false;226#endif227if constexpr (workaround) {228for (std::size_t i = 0; i < str.size(); ++i) {229if (str[i] == c) {230return i;231}232}233234return string_view::npos;235} else {236return str.find_first_of(c);237}238}239240template <typename T, std::size_t N, std::size_t... I>241constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N], std::index_sequence<I...>) {242return {{a[I]...}};243}244245template <typename BinaryPredicate>246constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) {247#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)248// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html249// https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html250constexpr bool workaround = true;251#else252constexpr bool workaround = false;253#endif254constexpr bool default_predicate = std::is_same_v<std::decay_t<BinaryPredicate>, char_equal_to>;255256if constexpr (default_predicate && !workaround) {257static_cast<void>(p);258return lhs == rhs;259} else {260if (lhs.size() != rhs.size()) {261return false;262}263264const auto size = lhs.size();265for (std::size_t i = 0; i < size; ++i) {266if (!p(lhs[i], rhs[i])) {267return false;268}269}270271return true;272}273}274275template <typename L, typename R>276constexpr bool cmp_less(L lhs, R rhs) noexcept {277static_assert(std::is_integral_v<L> && std::is_integral_v<R>, "magic_enum::detail::cmp_less requires integral type.");278279if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {280// If same signedness (both signed or both unsigned).281return lhs < rhs;282} else if constexpr (std::is_signed_v<R>) {283// If 'right' is negative, then result is 'false', otherwise cast & compare.284return rhs > 0 && lhs < static_cast<std::make_unsigned_t<R>>(rhs);285} else {286// If 'left' is negative, then result is 'true', otherwise cast & compare.287return lhs < 0 || static_cast<std::make_unsigned_t<L>>(lhs) < rhs;288}289}290291template <typename I>292constexpr I log2(I value) noexcept {293static_assert(std::is_integral_v<I>, "magic_enum::detail::log2 requires integral type.");294295auto ret = I{0};296for (; value > I{1}; value >>= I{1}, ++ret) {}297298return ret;299}300301template <typename I>302constexpr bool is_pow2(I x) noexcept {303static_assert(std::is_integral_v<I>, "magic_enum::detail::is_pow2 requires integral type.");304305return x != 0 && (x & (x - 1)) == 0;306}307308template <typename T>309inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::decay_t<T>>;310311template <typename E>312constexpr auto n() noexcept {313static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");314#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED315# if defined(__clang__)316constexpr string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};317# elif defined(__GNUC__)318constexpr string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51};319# elif defined(_MSC_VER)320constexpr string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57};321# endif322return static_string<name.size()>{name};323#else324return string_view{}; // Unsupported compiler.325#endif326}327328template <typename E>329inline constexpr auto type_name_v = n<E>();330331template <typename E, E V>332constexpr auto n() noexcept {333static_assert(is_enum_v<E>, "magic_enum::detail::n requires enum type.");334constexpr auto custom_name = customize::enum_name<E>(V);335336if constexpr (custom_name.empty()) {337static_cast<void>(custom_name);338#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED339# if defined(__clang__) || defined(__GNUC__)340constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});341# elif defined(_MSC_VER)342constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});343# endif344return static_string<name.size()>{name};345#else346return string_view{}; // Unsupported compiler.347#endif348} else {349return static_string<custom_name.size()>{custom_name};350}351}352353template <typename E, E V>354inline constexpr auto enum_name_v = n<E, V>();355356template <typename E, auto V>357constexpr bool is_valid() noexcept {358static_assert(is_enum_v<E>, "magic_enum::detail::is_valid requires enum type.");359360return n<E, static_cast<E>(V)>().size() != 0;361}362363template <typename E, int O, bool IsFlags = false, typename U = std::underlying_type_t<E>>364constexpr E value(std::size_t i) noexcept {365static_assert(is_enum_v<E>, "magic_enum::detail::value requires enum type.");366367if constexpr (IsFlags) {368return static_cast<E>(U{1} << static_cast<U>(static_cast<int>(i) + O));369} else {370return static_cast<E>(static_cast<int>(i) + O);371}372}373374template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>375constexpr int reflected_min() noexcept {376static_assert(is_enum_v<E>, "magic_enum::detail::reflected_min requires enum type.");377378if constexpr (IsFlags) {379return 0;380} else {381constexpr auto lhs = customize::enum_range<E>::min;382static_assert(lhs > (std::numeric_limits<std::int16_t>::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN.");383constexpr auto rhs = (std::numeric_limits<U>::min)();384385if constexpr (cmp_less(lhs, rhs)) {386return rhs;387} else {388static_assert(!is_valid<E, value<E, lhs - 1, IsFlags>(0)>(), "magic_enum::enum_range detects enum value smaller than min range size.");389return lhs;390}391}392}393394template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>395constexpr int reflected_max() noexcept {396static_assert(is_enum_v<E>, "magic_enum::detail::reflected_max requires enum type.");397398if constexpr (IsFlags) {399return std::numeric_limits<U>::digits - 1;400} else {401constexpr auto lhs = customize::enum_range<E>::max;402static_assert(lhs < (std::numeric_limits<std::int16_t>::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX.");403constexpr auto rhs = (std::numeric_limits<U>::max)();404405if constexpr (cmp_less(lhs, rhs)) {406static_assert(!is_valid<E, value<E, lhs + 1, IsFlags>(0)>(), "magic_enum::enum_range detects enum value larger than max range size.");407return lhs;408} else {409return rhs;410}411}412}413414template <typename E, bool IsFlags = false>415inline constexpr auto reflected_min_v = reflected_min<E, IsFlags>();416417template <typename E, bool IsFlags = false>418inline constexpr auto reflected_max_v = reflected_max<E, IsFlags>();419420template <std::size_t N>421constexpr std::size_t values_count(const bool (&valid)[N]) noexcept {422auto count = std::size_t{0};423for (std::size_t i = 0; i < N; ++i) {424if (valid[i]) {425++count;426}427}428429return count;430}431432template <typename E, bool IsFlags, int Min, std::size_t... I>433constexpr auto values(std::index_sequence<I...>) noexcept {434static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");435constexpr bool valid[sizeof...(I)] = {is_valid<E, value<E, Min, IsFlags>(I)>()...};436constexpr std::size_t count = values_count(valid);437438if constexpr (count > 0) {439E values[count] = {};440for (std::size_t i = 0, v = 0; v < count; ++i) {441if (valid[i]) {442values[v++] = value<E, Min, IsFlags>(i);443}444}445446return to_array(values, std::make_index_sequence<count>{});447} else {448return std::array<E, 0>{};449}450}451452template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>453constexpr auto values() noexcept {454static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");455constexpr auto min = reflected_min_v<E, IsFlags>;456constexpr auto max = reflected_max_v<E, IsFlags>;457constexpr auto range_size = max - min + 1;458static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");459static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");460461return values<E, IsFlags, reflected_min_v<E, IsFlags>>(std::make_index_sequence<range_size>{});462}463464template <typename E, bool IsFlags = false>465inline constexpr auto values_v = values<E, IsFlags>();466467template <typename E, bool IsFlags = false, typename D = std::decay_t<E>>468using values_t = decltype((values_v<D, IsFlags>));469470template <typename E, bool IsFlags = false>471inline constexpr auto count_v = values_v<E, IsFlags>.size();472473template <typename E, bool IsFlags = false, typename U = std::underlying_type_t<E>>474inline constexpr auto min_v = (count_v<E, IsFlags> > 0) ? static_cast<U>(values_v<E, IsFlags>.front()) : U{0};475476template <typename E, bool IsFlags = false, typename U = std::underlying_type_t<E>>477inline constexpr auto max_v = (count_v<E, IsFlags> > 0) ? static_cast<U>(values_v<E, IsFlags>.back()) : U{0};478479template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>480constexpr std::size_t range_size() noexcept {481static_assert(is_enum_v<E>, "magic_enum::detail::range_size requires enum type.");482constexpr auto max = IsFlags ? log2(max_v<E, IsFlags>) : max_v<E, IsFlags>;483constexpr auto min = IsFlags ? log2(min_v<E, IsFlags>) : min_v<E, IsFlags>;484constexpr auto range_size = max - min + U{1};485static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");486static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");487488return static_cast<std::size_t>(range_size);489}490491template <typename E, bool IsFlags = false>492inline constexpr auto range_size_v = range_size<E, IsFlags>();493494template <typename E, bool IsFlags = false>495using index_t = std::conditional_t<range_size_v<E, IsFlags> < (std::numeric_limits<std::uint8_t>::max)(), std::uint8_t, std::uint16_t>;496497template <typename E, bool IsFlags = false>498inline constexpr auto invalid_index_v = (std::numeric_limits<index_t<E, IsFlags>>::max)();499500template <typename E, bool IsFlags, std::size_t... I>501constexpr auto indexes(std::index_sequence<I...>) noexcept {502static_assert(is_enum_v<E>, "magic_enum::detail::indexes requires enum type.");503constexpr auto min = IsFlags ? log2(min_v<E, IsFlags>) : min_v<E, IsFlags>;504[[maybe_unused]] auto i = index_t<E, IsFlags>{0};505506return std::array<decltype(i), sizeof...(I)>{{(is_valid<E, value<E, min, IsFlags>(I)>() ? i++ : invalid_index_v<E, IsFlags>)...}};507}508509template <typename E, bool IsFlags = false>510inline constexpr auto indexes_v = indexes<E, IsFlags>(std::make_index_sequence<range_size_v<E, IsFlags>>{});511512template <typename E, bool IsFlags, std::size_t... I>513constexpr auto names(std::index_sequence<I...>) noexcept {514static_assert(is_enum_v<E>, "magic_enum::detail::names requires enum type.");515516return std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, IsFlags>[I]>...}};517}518519template <typename E, bool IsFlags = false>520inline constexpr auto names_v = names<E, IsFlags>(std::make_index_sequence<count_v<E, IsFlags>>{});521522template <typename E, bool IsFlags = false, typename D = std::decay_t<E>>523using names_t = decltype((names_v<D, IsFlags>));524525template <typename E, bool IsFlags, std::size_t... I>526constexpr auto entries(std::index_sequence<I...>) noexcept {527static_assert(is_enum_v<E>, "magic_enum::detail::entries requires enum type.");528529return std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, IsFlags>[I], enum_name_v<E, values_v<E, IsFlags>[I]>}...}};530}531532template <typename E, bool IsFlags = false>533inline constexpr auto entries_v = entries<E, IsFlags>(std::make_index_sequence<count_v<E, IsFlags>>{});534535template <typename E, bool IsFlags = false, typename D = std::decay_t<E>>536using entries_t = decltype((entries_v<D, IsFlags>));537538template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>539constexpr bool is_sparse() noexcept {540static_assert(is_enum_v<E>, "magic_enum::detail::is_sparse requires enum type.");541542return range_size_v<E, IsFlags> != count_v<E, IsFlags>;543}544545template <typename E, bool IsFlags = false>546inline constexpr bool is_sparse_v = is_sparse<E, IsFlags>();547548template <typename E, typename U = std::underlying_type_t<E>>549constexpr std::size_t undex(U value) noexcept {550static_assert(is_enum_v<E>, "magic_enum::detail::undex requires enum type.");551552if (const auto i = static_cast<std::size_t>(value - min_v<E>); value >= min_v<E> && value <= max_v<E>) {553if constexpr (is_sparse_v<E>) {554if (const auto idx = indexes_v<E>[i]; idx != invalid_index_v<E>) {555return idx;556}557} else {558return i;559}560}561562return invalid_index_v<E>; // Value out of range.563}564565template <typename E, typename U = std::underlying_type_t<E>>566constexpr std::size_t endex(E value) noexcept {567static_assert(is_enum_v<E>, "magic_enum::detail::endex requires enum type.");568569return undex<E>(static_cast<U>(value));570}571572template <typename E, typename U = std::underlying_type_t<E>>573constexpr U value_ors() noexcept {574static_assert(is_enum_v<E>, "magic_enum::detail::endex requires enum type.");575576auto value = U{0};577for (std::size_t i = 0; i < count_v<E, true>; ++i) {578value |= static_cast<U>(values_v<E, true>[i]);579}580581return value;582}583584template <bool, typename T, typename R>585struct enable_if_enum {};586587template <typename T, typename R>588struct enable_if_enum<true, T, R> {589using type = R;590using D = std::decay_t<T>;591static_assert(supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");592};593594template <typename T, typename R = void>595using enable_if_enum_t = std::enable_if_t<std::is_enum_v<std::decay_t<T>>, R>;596597template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>598using enum_concept = T;599600template <typename T, bool = std::is_enum_v<T>>601struct is_scoped_enum : std::false_type {};602603template <typename T>604struct is_scoped_enum<T, true> : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};605606template <typename T, bool = std::is_enum_v<T>>607struct is_unscoped_enum : std::false_type {};608609template <typename T>610struct is_unscoped_enum<T, true> : std::bool_constant<std::is_convertible_v<T, std::underlying_type_t<T>>> {};611612template <typename T, bool = std::is_enum_v<std::decay_t<T>>>613struct underlying_type {};614615template <typename T>616struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};617618} // namespace magic_enum::detail619620// Checks is magic_enum supported compiler.621inline constexpr bool is_magic_enum_supported = detail::supported<void>::value;622623template <typename T>624using Enum = detail::enum_concept<T>;625626// Checks whether T is an Unscoped enumeration type.627// 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.628template <typename T>629struct is_unscoped_enum : detail::is_unscoped_enum<T> {};630631template <typename T>632inline constexpr bool is_unscoped_enum_v = is_unscoped_enum<T>::value;633634// Checks whether T is an Scoped enumeration type.635// 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.636template <typename T>637struct is_scoped_enum : detail::is_scoped_enum<T> {};638639template <typename T>640inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;641642// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.643// 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.644template <typename T>645struct underlying_type : detail::underlying_type<T> {};646647template <typename T>648using underlying_type_t = typename underlying_type<T>::type;649650// Returns type name of enum.651template <typename E>652[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_enum_t<E, string_view> {653using D = std::decay_t<E>;654constexpr string_view name = detail::type_name_v<D>;655static_assert(name.size() > 0, "Enum type does not have a name.");656657return name;658}659660// Returns number of enum values.661template <typename E>662[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t<E, std::size_t> {663using D = std::decay_t<E>;664665return detail::count_v<D>;666}667668// Returns enum value at specified index.669// No bounds checking is performed: the behavior is undefined if index >= number of enum values.670template <typename E>671[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> {672using D = std::decay_t<E>;673static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");674675if constexpr (detail::is_sparse_v<D>) {676return assert((index < detail::count_v<D>)), detail::values_v<D>[index];677} else {678return assert((index < detail::count_v<D>)), detail::value<D, detail::min_v<D>>(index);679}680}681682// Returns std::array with enum values, sorted by enum value.683template <typename E>684[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, detail::values_t<E>> {685using D = std::decay_t<E>;686static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");687688return detail::values_v<D>;689}690691// Returns name from static storage enum variable.692// This version is much lighter on the compile times and is not restricted to the enum_range limitation.693template <auto V>694[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t<decltype(V), string_view> {695using D = std::decay_t<decltype(V)>;696constexpr string_view name = detail::enum_name_v<D, V>;697static_assert(name.size() > 0, "Enum value does not have a name.");698699return name;700}701702// Returns name from enum value.703// If enum value does not have name or value out of range, returns empty string.704template <typename E>705[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, string_view> {706using D = std::decay_t<E>;707708if (const auto i = detail::endex<D>(value); i != detail::invalid_index_v<D>) {709return detail::names_v<D>[i];710}711712return {}; // Invalid value or out of range.713}714715// Returns std::array with names, sorted by enum value.716template <typename E>717[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, detail::names_t<E>> {718using D = std::decay_t<E>;719static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");720721return detail::names_v<D>;722}723724// Returns std::array with pairs (value, name), sorted by enum value.725template <typename E>726[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, detail::entries_t<E>> {727using D = std::decay_t<E>;728static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");729730return detail::entries_v<D>;731}732733// Obtains enum value from integer value.734// Returns optional with enum value.735template <typename E>736[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {737using D = std::decay_t<E>;738739if (detail::undex<D>(value) != detail::invalid_index_v<D>) {740return static_cast<D>(value);741}742743return {}; // Invalid value or out of range.744}745746// Obtains enum value from name.747// Returns optional with enum value.748template <typename E, typename BinaryPredicate>749[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {750static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");751using D = std::decay_t<E>;752753for (std::size_t i = 0; i < detail::count_v<D>; ++i) {754if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {755return enum_value<D>(i);756}757}758759return {}; // Invalid value or out of range.760}761762// Obtains enum value from name.763// Returns optional with enum value.764template <typename E>765[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {766using D = std::decay_t<E>;767768return enum_cast<D>(value, detail::char_equal_to{});769}770771// Returns integer value from enum value.772template <typename E>773[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t<E, underlying_type_t<E>> {774return static_cast<underlying_type_t<E>>(value);775}776777// Obtains index in enum values from enum value.778// Returns optional with index.779template <typename E>780[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, optional<std::size_t>> {781using D = std::decay_t<E>;782783if (const auto i = detail::endex<D>(value); i != detail::invalid_index_v<D>) {784return i;785}786787return {}; // Invalid value or out of range.788}789790// Checks whether enum contains enumerator with such enum value.791template <typename E>792[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> {793using D = std::decay_t<E>;794795return detail::endex<D>(value) != detail::invalid_index_v<D>;796}797798// Checks whether enum contains enumerator with such integer value.799template <typename E>800[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> {801using D = std::decay_t<E>;802803return detail::undex<D>(value) != detail::invalid_index_v<D>;804}805806// Checks whether enum contains enumerator with such name.807template <typename E, typename BinaryPredicate>808[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> {809static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");810using D = std::decay_t<E>;811812return enum_cast<D>(value, std::move_if_noexcept(p)).has_value();813}814815// Checks whether enum contains enumerator with such name.816template <typename E>817[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t<E, bool> {818using D = std::decay_t<E>;819820return enum_cast<D>(value).has_value();821}822823namespace ostream_operators {824825template <typename Char, typename Traits, typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>826std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {827using D = std::decay_t<E>;828using U = underlying_type_t<D>;829#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED830if (const auto name = magic_enum::enum_name<D>(value); !name.empty()) {831for (const auto c : name) {832os.put(c);833}834return os;835}836#endif837return (os << static_cast<U>(value));838}839840template <typename Char, typename Traits, typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>841std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {842return value.has_value() ? (os << value.value()) : os;843}844845} // namespace magic_enum::ostream_operators846847namespace bitwise_operators {848849template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>850constexpr E operator~(E rhs) noexcept {851return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));852}853854template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>855constexpr E operator|(E lhs, E rhs) noexcept {856return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));857}858859template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>860constexpr E operator&(E lhs, E rhs) noexcept {861return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));862}863864template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>865constexpr E operator^(E lhs, E rhs) noexcept {866return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));867}868869template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>870constexpr E& operator|=(E& lhs, E rhs) noexcept {871return lhs = (lhs | rhs);872}873874template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>875constexpr E& operator&=(E& lhs, E rhs) noexcept {876return lhs = (lhs & rhs);877}878879template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>880constexpr E& operator^=(E& lhs, E rhs) noexcept {881return lhs = (lhs ^ rhs);882}883884} // namespace magic_enum::bitwise_operators885886namespace flags {887888// Returns type name of enum.889using magic_enum::enum_type_name;890891// Returns number of enum-flags values.892template <typename E>893[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t<E, std::size_t> {894using D = std::decay_t<E>;895896return detail::count_v<D, true>;897}898899// Returns enum-flags value at specified index.900// No bounds checking is performed: the behavior is undefined if index >= number of enum-flags values.901template <typename E>902[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> {903using D = std::decay_t<E>;904static_assert(detail::count_v<D, true> > 0, "magic_enum::flags requires enum-flags implementation.");905906if constexpr (detail::is_sparse_v<D, true>) {907return assert((index < detail::count_v<D, true>)), detail::values_v<D, true>[index];908} else {909constexpr auto min = detail::log2(detail::min_v<D, true>);910911return assert((index < detail::count_v<D, true>)), detail::value<D, min, true>(index);912}913}914915// Returns std::array with enum-flags values, sorted by enum-flags value.916template <typename E>917[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, detail::values_t<E, true>> {918using D = std::decay_t<E>;919static_assert(detail::count_v<D, true> > 0, "magic_enum::flags requires enum-flags implementation.");920921return detail::values_v<D, true>;922}923924// Returns name from enum-flags value.925// If enum-flags value does not have name or value out of range, returns empty string.926template <typename E>927[[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_t<E, string> {928using D = std::decay_t<E>;929using U = underlying_type_t<D>;930931string name;932auto check_value = U{0};933for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {934if (const auto v = static_cast<U>(enum_value<D>(i)); (static_cast<U>(value) & v) != 0) {935check_value |= v;936const auto n = detail::names_v<D, true>[i];937if (!name.empty()) {938name.append(1, '|');939}940name.append(n.data(), n.size());941}942}943944if (check_value != 0 && check_value == static_cast<U>(value)) {945return name;946}947948return {}; // Invalid value or out of range.949}950951// Returns std::array with string names, sorted by enum-flags value.952template <typename E>953[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, detail::names_t<E, true>> {954using D = std::decay_t<E>;955static_assert(detail::count_v<D, true> > 0, "magic_enum::flags requires enum-flags implementation.");956957return detail::names_v<D, true>;958}959960// Returns std::array with pairs (value, name), sorted by enum-flags value.961template <typename E>962[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, detail::entries_t<E, true>> {963using D = std::decay_t<E>;964static_assert(detail::count_v<D, true> > 0, "magic_enum::flags requires enum-flags implementation.");965966return detail::entries_v<D, true>;967}968969// Obtains enum-flags value from integer value.970// Returns optional with enum-flags value.971template <typename E>972[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {973using D = std::decay_t<E>;974using U = underlying_type_t<D>;975976if constexpr (detail::is_sparse_v<D, true>) {977auto check_value = U{0};978for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {979if (const auto v = static_cast<U>(enum_value<D>(i)); (value & v) != 0) {980check_value |= v;981}982}983984if (check_value != 0 && check_value == value) {985return static_cast<D>(value);986}987} else {988constexpr auto min = detail::min_v<D, true>;989constexpr auto max = detail::value_ors<D>();990991if (value >= min && value <= max) {992return static_cast<D>(value);993}994}995996return {}; // Invalid value or out of range.997}998999// Obtains enum-flags value from name.1000// Returns optional with enum-flags value.1001template <typename E, typename BinaryPredicate>1002[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {1003static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::flags::enum_cast requires bool(char, char) invocable predicate.");1004using D = std::decay_t<E>;1005using U = underlying_type_t<D>;10061007auto result = U{0};1008while (!value.empty()) {1009const auto d = detail::find(value, '|');1010const auto s = (d == string_view::npos) ? value : value.substr(0, d);1011auto f = U{0};1012for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {1013if (detail::cmp_equal(s, detail::names_v<D, true>[i], p)) {1014f = static_cast<U>(enum_value<D>(i));1015result |= f;1016break;1017}1018}1019if (f == U{0}) {1020return {}; // Invalid value or out of range.1021}1022value.remove_prefix((d == string_view::npos) ? value.size() : d + 1);1023}10241025if (result == U{0}) {1026return {}; // Invalid value or out of range.1027} else {1028return static_cast<D>(result);1029}1030}10311032// Obtains enum-flags value from name.1033// Returns optional with enum-flags value.1034template <typename E>1035[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {1036using D = std::decay_t<E>;10371038return enum_cast<D>(value, detail::char_equal_to{});1039}10401041// Returns integer value from enum value.1042using magic_enum::enum_integer;10431044// Obtains index in enum-flags values from enum-flags value.1045// Returns optional with index.1046template <typename E>1047[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, optional<std::size_t>> {1048using D = std::decay_t<E>;1049using U = underlying_type_t<D>;10501051if (detail::is_pow2(static_cast<U>(value))) {1052for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {1053if (enum_value<D>(i) == value) {1054return i;1055}1056}1057}10581059return {}; // Invalid value or out of range.1060}10611062// Checks whether enum-flags contains enumerator with such enum-flags value.1063template <typename E>1064[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> {1065using D = std::decay_t<E>;1066using U = underlying_type_t<D>;10671068return enum_cast<D>(static_cast<U>(value)).has_value();1069}10701071// Checks whether enum-flags contains enumerator with such integer value.1072template <typename E>1073[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> {1074using D = std::decay_t<E>;10751076return enum_cast<D>(value).has_value();1077}10781079// Checks whether enum-flags contains enumerator with such name.1080template <typename E, typename BinaryPredicate>1081[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> {1082static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate.");1083using D = std::decay_t<E>;10841085return enum_cast<D>(value, std::move_if_noexcept(p)).has_value();1086}10871088// Checks whether enum-flags contains enumerator with such name.1089template <typename E>1090[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t<E, bool> {1091using D = std::decay_t<E>;10921093return enum_cast<D>(value).has_value();1094}10951096} // namespace magic_enum::flags10971098namespace flags::ostream_operators {10991100template <typename Char, typename Traits, typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>1101std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {1102using D = std::decay_t<E>;1103using U = underlying_type_t<D>;1104#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED1105if (const auto name = magic_enum::flags::enum_name<D>(value); !name.empty()) {1106for (const auto c : name) {1107os.put(c);1108}1109return os;1110}1111#endif1112return (os << static_cast<U>(value));1113}11141115template <typename Char, typename Traits, typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>1116std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {1117return value.has_value() ? (os << value.value()) : os;1118}11191120} // namespace magic_enum::flags::ostream_operators11211122namespace flags::bitwise_operators {11231124using namespace magic_enum::bitwise_operators;11251126} // namespace magic_enum::flags::bitwise_operators11271128} // namespace magic_enum11291130#if defined(__clang__)1131# pragma clang diagnostic pop1132#elif defined(__GNUC__)1133# pragma GCC diagnostic pop1134#elif defined(_MSC_VER)1135# pragma warning(pop)1136#endif11371138#endif // NEARGYE_MAGIC_ENUM_HPP113911401141