From 9ed88dea3ba28e189f7f48d8fd847d2d981663d9 Mon Sep 17 00:00:00 2001 From: neargye Date: Sun, 30 Aug 2020 10:45:18 +0300 Subject: [PATCH] clean-up --- include/magic_enum.hpp | 460 ++++++++++++++++++++--------------------- 1 file changed, 228 insertions(+), 232 deletions(-) diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 004c6f4..6421434 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -42,15 +42,20 @@ #include #include #include -#include -#include #include #include +#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +#include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +#include +#endif #if defined(__clang__) # pragma clang diagnostic push #elif defined(__GNUC__) # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. #elif defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 26495) // Variable 'static_string::chars' is uninitialized. @@ -80,110 +85,6 @@ # define MAGIC_ENUM_RANGE_MAX 128 #endif -#if !defined(NEARGYE_DETAIL_N) -# define NEARGYE_DETAIL_N 1 -namespace neargye::detail { - -template -struct identity { - using type = T; -}; - -template -struct static_string { - constexpr explicit static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} { - assert(str.size() == N); - } - - constexpr const char* data() const noexcept { return chars.data(); } - - constexpr std::size_t size() const noexcept { return N; } - - constexpr operator std::string_view() const noexcept { return {data(), size()}; } - - private: - template - constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]..., '\0'}} {} - - const std::array chars; -}; - -template <> -struct static_string<0> { - constexpr explicit static_string(std::string_view) noexcept {} - - constexpr const char* data() const noexcept { return nullptr; } - - constexpr std::size_t size() const noexcept { return 0; } - - constexpr operator std::string_view() const noexcept { return {}; } -}; - -constexpr std::string_view enum_name(std::string_view name) noexcept { - for (std::size_t i = name.size(); i > 0; --i) { - if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || - (name[i - 1] >= 'a' && name[i - 1] <= 'z') || - (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || - (name[i - 1] == '_'))) { - name.remove_prefix(i); - break; - } - } - - if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || - (name.front() >= 'A' && name.front() <= 'Z') || - (name.front() == '_'))) { - return name; - } - - return {}; // Invalid name. -} - -template -constexpr auto n() noexcept { -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || defined(_MSC_VER) && _MSC_VER >= 1910 -# if defined(__clang__) - constexpr std::string_view name{__PRETTY_FUNCTION__ + 32, sizeof(__PRETTY_FUNCTION__) - 35}; -# elif defined(__GNUC__) - constexpr std::string_view name{__PRETTY_FUNCTION__ + 47, sizeof(__PRETTY_FUNCTION__) - 50}; -# elif defined(_MSC_VER) - constexpr std::string_view name{__FUNCSIG__ + 65, sizeof(__FUNCSIG__) - 83 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)}; -# endif - - return static_string{name}; -#else - return std::string_view{}; // Unsupported compiler. -#endif -} - -#if defined(_MSC_VER) -template > -#else -template -#endif -inline constexpr auto type_name_v = n(); - -template -constexpr auto n() noexcept { - static_assert(std::is_enum_v && std::is_same_v>); -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 -# if defined(__clang__) || defined(__GNUC__) - constexpr auto name = enum_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); -# elif defined(_MSC_VER) - constexpr auto name = enum_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); -# endif - return static_string{name}; -#else - return std::string_view{}; // Unsupported compiler. -#endif -} - -template -inline constexpr auto enum_name_v = n(); - -} // namespace neargye::detail -#endif - namespace magic_enum { // 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. @@ -205,13 +106,29 @@ static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits::max)(), static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); -namespace detail { +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. +#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +MAGIC_ENUM_USING_ALIAS_OPTIONAL +#else +template +using optional = std::optional; +#endif -using ::neargye::detail::identity; -using ::neargye::detail::static_string; -using ::neargye::detail::n; -using ::neargye::detail::type_name_v; -using ::neargye::detail::enum_name_v; +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +MAGIC_ENUM_USING_ALIAS_STRING_VIEW +#else +using string_view = std::string_view; +#endif + +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING) +MAGIC_ENUM_USING_ALIAS_STRING +#else +using string = std::string; +#endif + +namespace detail { template struct supported @@ -221,22 +138,35 @@ struct supported : std::false_type {}; #endif -template -inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; - -constexpr std::size_t find(std::string_view str, char c) noexcept { -#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) -// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc - for (std::size_t i = 0; i < str.size(); ++i) { - if (str[i] == c) { - return i; - } +template +struct static_string { + constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_index_sequence{}} { + assert(str.size() == N); } - return std::string_view::npos; -#else - return str.find_first_of(c); -#endif -} + + constexpr const char* data() const noexcept { return chars.data(); } + + constexpr std::size_t size() const noexcept { return N; } + + constexpr operator string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_string(string_view str, std::index_sequence) noexcept : chars{{str[I]..., '\0'}} {} + + const std::array chars; +}; + +template <> +struct static_string<0> { + constexpr explicit static_string(string_view) noexcept {} + + constexpr const char* data() const noexcept { return nullptr; } + + constexpr std::size_t size() const noexcept { return 0; } + + constexpr operator string_view() const noexcept { return {}; } +}; struct char_equal_to { constexpr bool operator()(char lhs, char rhs) const noexcept { @@ -244,9 +174,57 @@ struct char_equal_to { } }; +constexpr string_view pretty_name(string_view name) noexcept { + for (std::size_t i = name.size(); i > 0; --i) { + if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || + (name[i - 1] >= 'a' && name[i - 1] <= 'z') || + (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || + (name[i - 1] == '_'))) { + name.remove_prefix(i); + break; + } + } + + if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || + (name.front() >= 'A' && name.front() <= 'Z') || + (name.front() == '_'))) { + return name; + } + + return {}; // Invalid name. +} + +constexpr std::size_t find(string_view str, char c) noexcept { +#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 +// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc +// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + constexpr auto workaroung = true; +#else + constexpr auto workaroung = false; +#endif + if constexpr (workaroung) { + for (std::size_t i = 0; i < str.size(); ++i) { + if (str[i] == c) { + return i; + } + } + + return string_view::npos; + } else { + return str.find_first_of(c); + } +} + template -constexpr bool cmp_equal(std::string_view lhs, std::string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v) { - if constexpr (std::is_same_v, char_equal_to>) { +constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v) { +#if defined(_MSC_VER) && _MSC_VER < 1920 + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr auto workaroung = true; +#else + constexpr auto workaroung = false; +#endif + if constexpr (std::is_same_v, char_equal_to> && !workaroung) { static_cast(p); return lhs == rhs; } else { @@ -309,6 +287,47 @@ constexpr bool is_pow2(T x) noexcept { } } +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED +# if defined(__clang__) + constexpr string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; +# elif defined(__GNUC__) + constexpr string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51}; +# elif defined(_MSC_VER) + constexpr string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57}; +# endif + return static_string{name}; +#else + return string_view{}; // Unsupported compiler. +#endif +} + +template +inline constexpr auto type_name_v = n(); + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED +# if defined(__clang__) || defined(__GNUC__) + constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); +# elif defined(_MSC_VER) + constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); +# endif + return static_string{name}; +#else + return string_view{}; // Unsupported compiler. +#endif +} + +template +inline constexpr auto enum_name_v = n(); + template constexpr bool is_valid() noexcept { static_assert(is_enum_v, "magic_enum::detail::is_valid requires enum type."); @@ -454,7 +473,7 @@ template constexpr auto names(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); - return std::array{{enum_name_v[I]>...}}; + return std::array{{enum_name_v[I]>...}}; } template @@ -467,7 +486,7 @@ template constexpr auto entries(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); - return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; } template @@ -609,15 +628,10 @@ using underlying_type_t = typename underlying_type::type; // Returns string name of enum type. template -[[nodiscard]] constexpr std::string_view enum_type_name() noexcept { +[[nodiscard]] constexpr string_view enum_type_name() noexcept { using D = std::decay_t; static_assert(std::is_enum_v, "Requires enum type."); -#if defined(_MSC_VER) - // TODO: https://github.com/Neargye/nameof/issues/22 - constexpr std::string_view name = std::string_view{detail::type_name_v}.substr(5, detail::type_name_v.size() - 5); -#else - constexpr std::string_view name = detail::type_name_v; -#endif + constexpr string_view name = detail::type_name_v; static_assert(name.size() > 0, "Enum type does not have a name."); return name; @@ -655,10 +669,10 @@ template // Returns string name from static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. template -[[nodiscard]] constexpr std::string_view enum_name() noexcept { +[[nodiscard]] constexpr string_view enum_name() noexcept { using D = std::decay_t; static_assert(std::is_enum_v, "Requires enum type."); - constexpr std::string_view name = detail::enum_name_v; + constexpr string_view name = detail::enum_name_v; static_assert(name.size() > 0, "Enum value does not have a name."); return name; @@ -667,7 +681,7 @@ template // Returns string name from enum value. // If enum value does not have name or value out of range, returns empty string. template -[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { +[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { using D = std::decay_t; if (const auto i = detail::endex(value); i != detail::invalid_index_v) { @@ -694,22 +708,22 @@ template } // Obtains enum value from integer value. -// Returns std::optional with enum value. +// Returns optional with enum value. template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { using D = std::decay_t; if (detail::undex(value) != detail::invalid_index_v) { return static_cast(value); } - return std::nullopt; // Invalid value or out of range. + return {}; // Invalid value or out of range. } // Obtains enum value from string name. -// Returns std::optional with enum value. +// Returns optional with enum value. template -[[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { +[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { static_assert(std::is_invocable_r_v, "magic_enum::enum_cast requires bool(char, char) invocable predicate."); using D = std::decay_t; @@ -719,13 +733,13 @@ template } } - return std::nullopt; // Invalid value or out of range. + return {}; // Invalid value or out of range. } // Obtains enum value from string name. -// Returns std::optional with enum value. +// Returns optional with enum value. template -[[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t>> { +[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t>> { using D = std::decay_t; return enum_cast(value, detail::char_equal_to{}); @@ -738,16 +752,16 @@ template } // Obtains index in enum values from enum value. -// Returns std::optional with index. +// Returns optional with index. template -[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { using D = std::decay_t; if (const auto i = detail::endex(value); i != detail::invalid_index_v) { return i; } - return std::nullopt; // Value out of range. + return {}; // Invalid value or out of range. } // Checks whether enum contains enumerator with such enum value. @@ -768,7 +782,7 @@ template // Checks whether enum contains enumerator with such string name. template -[[nodiscard]] constexpr auto enum_contains(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { using D = std::decay_t; static_assert(std::is_invocable_r_v, "magic_enum::enum_contains requires bool(char, char) invocable predicate."); @@ -777,7 +791,7 @@ template // Checks whether enum contains enumerator with such string name. template -[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_t { +[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t { using D = std::decay_t; return enum_cast(value).has_value(); @@ -803,7 +817,7 @@ std::basic_ostream& operator<<(std::basic_ostream& o } template , int> = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, std::optional value) { +std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { if (value.has_value()) { os << value.value(); } @@ -891,11 +905,11 @@ template // Returns string name from enum-flags value. // If enum-flags value does not have name or value out of range, returns empty string. template -[[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_flags_t { +[[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_flags_t { using D = std::decay_t; using U = underlying_type_t; - std::string name; + string name; auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (const auto v = enum_value(i); (static_cast(value) & static_cast(v)) != 0) { @@ -932,149 +946,131 @@ template } // Obtains enum-flags value from integer value. -// Returns std::optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t>> { +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t>> { using D = std::decay_t; using U = underlying_type_t; - if constexpr (Strict) { + if constexpr (detail::is_sparse_v) { + auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { - if (value == static_cast(enum_value(i))) { - return static_cast(value); + if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { + check_value |= v; } } + + if (check_value != 0 && check_value == value) { + return static_cast(value); + } } else { - if constexpr (detail::is_sparse_v) { - auto check_value = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { - check_value |= v; - } - } + constexpr auto min = detail::min_v; + constexpr auto max = detail::value_ors(); - if (check_value != 0 && check_value == value) { - return static_cast(value); - } - } else { - constexpr auto min = detail::min_v; - constexpr auto max = detail::value_ors(); - - if (value >= min && value <= max) { - return static_cast(value); - } + if (value >= min && value <= max) { + return static_cast(value); } } - return std::nullopt; + return {}; // Invalid value or out of range. } // Obtains enum-flags value from string name. -// Returns std::optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t>> { +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t>> { static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_cast requires bool(char, char) invocable predicate."); using D = std::decay_t; + using U = underlying_type_t; - if constexpr (Strict) { + auto result = U{0}; + while (!value.empty()) { + const auto d = detail::find(value, '|'); + const auto s = (d == string_view::npos) ? value : value.substr(0, d); + auto f = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { - if (detail::cmp_equal(value, detail::names_v[i], p)) { - return enum_value(i); - } - } - return std::nullopt; - } else { - using U = underlying_type_t; - auto result = U{0}; - while (!value.empty()) { - const auto d = detail::find(value, '|'); - const auto s = (d == std::string_view::npos) ? value : value.substr(0, d); - auto f = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (detail::cmp_equal(s, detail::names_v[i], p)) { - f = static_cast(enum_value(i)); - result |= f; - break; - } - } - if (f == U{0}) { - return std::nullopt; - } else { + if (detail::cmp_equal(s, detail::names_v[i], p)) { + f = static_cast(enum_value(i)); result |= f; + break; } - value.remove_prefix((d == std::string_view::npos) ? value.size() : d + 1); } - - if (result == U{0}) { - return std::nullopt; + if (f == U{0}) { + return {}; // Invalid value or out of range. } else { - return static_cast(result); + result |= f; } + value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); + } + + if (result == U{0}) { + return {}; // Invalid value or out of range. + } else { + return static_cast(result); } } // Obtains enum-flags value from string name. -// Returns std::optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_flags_t>> { +// Returns optional with enum-flags value. +template +[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_flags_t>> { using D = std::decay_t; - return enum_cast(value, detail::char_equal_to{}); + return enum_cast(value, detail::char_equal_to{}); } // Returns integer value from enum value. using magic_enum::enum_integer; // Obtains index in enum-flags values from enum-flags value. -// Returns std::optional with index. +// Returns optional with index. template -[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_flags_t> { +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_flags_t> { using D = std::decay_t; if (detail::is_pow2(value)) { for (std::size_t i = 0; i < detail::count_v; ++i) { - auto v = enum_value(i); - if (v == value) { + if (enum_value(i) == value) { return i; } } } - return std::nullopt; // Value out of range. + return {}; // Invalid value or out of range. } // Checks whether enum-flags contains enumerator with such enum-flags value. -template +template [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t { using D = std::decay_t; using U = underlying_type_t; - return enum_cast(static_cast(value)).has_value(); + return enum_cast(static_cast(value)).has_value(); } // Checks whether enum-flags contains enumerator with such integer value. -template +template [[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t { using D = std::decay_t; - return enum_cast(value).has_value(); + return enum_cast(value).has_value(); } // Checks whether enum-flags contains enumerator with such string name. -template -[[nodiscard]] constexpr auto enum_contains(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t { +template +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t { static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate."); using D = std::decay_t; - return enum_cast(value, std::move_if_noexcept(p)).has_value(); + return enum_cast(value, std::move_if_noexcept(p)).has_value(); } // Checks whether enum-flags contains enumerator with such string name. -template -[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t { +template +[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_flags_t { using D = std::decay_t; - return enum_cast(value).has_value(); + return enum_cast(value).has_value(); } } // namespace magic_enum::flags @@ -1098,7 +1094,7 @@ std::basic_ostream& operator<<(std::basic_ostream& o } template = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, std::optional value) { +std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { if (value.has_value()) { os << value.value(); }