diff --git a/include/magic_enum/magic_enum.hpp b/include/magic_enum/magic_enum.hpp index 985f7dd5c..b23e3baa2 100644 --- a/include/magic_enum/magic_enum.hpp +++ b/include/magic_enum/magic_enum.hpp @@ -869,28 +869,16 @@ constexpr bool is_sparse() noexcept { template > inline constexpr bool is_sparse_v = is_sparse(); -template > -constexpr U values_ors() noexcept { - static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); - - auto ors = U{0}; - for (std::size_t i = 0; i < count_v; ++i) { - ors |= static_cast(values_v[i]); - } - - return ors; -} - template -struct is_valid_enum +struct is_reflected #if defined(MAGIC_ENUM_NO_CHECK_VALID_ENUM_TYPE) : std::true_type {}; #else - : std::bool_constant && (count_v > 0)> {}; + : std::bool_constant && (count_v != 0)> {}; #endif template -inline constexpr auto is_valid_enum_v = is_valid_enum, S>{}; +inline constexpr bool is_reflected_v = is_reflected, S>{}; template struct enable_if_enum {}; @@ -1191,7 +1179,7 @@ template > template > [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::is_sparse_v) { return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; @@ -1206,7 +1194,7 @@ template > template > [[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); return enum_value(I); @@ -1216,7 +1204,7 @@ template > [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::values_v; } @@ -1239,12 +1227,9 @@ template > [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; using U = underlying_type_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. - } else if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( [](std::size_t i) { return optional{i}; }, @@ -1272,7 +1257,7 @@ template > template [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_index(value); } @@ -1281,7 +1266,7 @@ template template >> [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t {\ using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); constexpr auto index = enum_index(V); static_assert(index, "magic_enum::enum_index enum value does not have a index."); @@ -1303,7 +1288,7 @@ template template > [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if (const auto i = enum_index(value)) { return detail::names_v[*i]; @@ -1316,7 +1301,7 @@ template > template [[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_name(value); } @@ -1325,7 +1310,7 @@ template template > [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::names_v; } @@ -1334,7 +1319,7 @@ template > template > [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::entries_v; } @@ -1347,32 +1332,27 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{}; template > [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. - } else { - if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) - return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( - [](D v) { return optional{v}; }, - static_cast(value), - detail::default_result_type_lambda>); + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + [](D v) { return optional{v}; }, + static_cast(value), + detail::default_result_type_lambda>); #else - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (value == static_cast>(enum_value(i))) { - return static_cast(value); - } - } - return {}; // Invalid value or out of range. -#endif - } else { - if (value >= detail::min_v && value <= detail::max_v) { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast>(enum_value(i))) { return static_cast(value); } - return {}; // Invalid value or out of range. } + return {}; // Invalid value or out of range. +#endif + } else { + if (value >= detail::min_v && value <= detail::max_v) { + return static_cast(value); + } + return {}; // Invalid value or out of range. } } @@ -1381,27 +1361,23 @@ template > template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. #if defined(MAGIC_ENUM_ENABLE_HASH) - } else if constexpr (detail::is_default_predicate()) { - return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( - [](std::size_t i) { return optional{detail::values_v[i]}; }, - value, - detail::default_result_type_lambda>, - [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); + if constexpr (detail::is_default_predicate()) { + return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{detail::values_v[i]}; }, + value, + detail::default_result_type_lambda>, + [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); + } #endif - } else { - 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); - } + 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 {}; // Invalid value or out of range. } + return {}; // Invalid value or out of range. } // Checks whether enum contains value with such value. diff --git a/include/magic_enum/magic_enum_flags.hpp b/include/magic_enum/magic_enum_flags.hpp index 3bb5cdfb9..7dfb70236 100644 --- a/include/magic_enum/magic_enum_flags.hpp +++ b/include/magic_enum/magic_enum_flags.hpp @@ -45,6 +45,22 @@ namespace magic_enum { +namespace detail { + +template > +constexpr U values_ors() noexcept { + static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); + + auto ors = U{0}; + for (std::size_t i = 0; i < count_v; ++i) { + ors |= static_cast(values_v[i]); + } + + return ors; +} + +} // namespace magic_enum::detail + // Returns name from enum-flags value. // If enum-flags value does not have name or value out of range, returns empty string. template @@ -52,7 +68,7 @@ template using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); string name; auto check_value = U{0}; @@ -83,7 +99,7 @@ template using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::count_v == 0) { static_cast(value); @@ -119,7 +135,7 @@ template > using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::count_v == 0) { static_cast(value); diff --git a/include/magic_enum/magic_enum_switch.hpp b/include/magic_enum/magic_enum_switch.hpp index 5b4e85d94..0f97a22a7 100644 --- a/include/magic_enum/magic_enum_switch.hpp +++ b/include/magic_enum/magic_enum_switch.hpp @@ -58,7 +58,7 @@ using invoke_result_t = typename invoke_result::type; template constexpr auto common_invocable(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::invocable_index requires enum type."); + static_assert(std::is_enum_v, "magic_enum::detail::invocable_index requires enum type."); if constexpr (count_v == 0) { return identity{}; @@ -69,7 +69,7 @@ constexpr auto common_invocable(std::index_sequence) noexcept { template constexpr auto result_type() noexcept { - static_assert(is_enum_v, "magic_enum::detail::result_type requires enum type."); + static_assert(std::is_enum_v, "magic_enum::detail::result_type requires enum type."); constexpr auto seq = std::make_index_sequence>{}; using R = typename decltype(common_invocable(seq))::type; @@ -137,7 +137,7 @@ template ; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( @@ -161,7 +161,7 @@ template ; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( diff --git a/include/magic_enum/magic_enum_utility.hpp b/include/magic_enum/magic_enum_utility.hpp index bc917b705..2e3e65ce0 100644 --- a/include/magic_enum/magic_enum_utility.hpp +++ b/include/magic_enum/magic_enum_utility.hpp @@ -67,7 +67,7 @@ template , typename F, constexpr auto enum_for_each(F&& f) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_for_each requires enum type."); - static_assert(detail::is_valid_enum_v, "magic_enum requires enum implementation and valid max and min."); + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); constexpr auto sep = std::make_index_sequence>{}; if constexpr (detail::all_invocable(sep)) { diff --git a/test/test.cpp b/test/test.cpp index b831f557d..7e6255cf8 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1257,20 +1257,20 @@ TEST_CASE("valid_enum") { enum class Empty3 {}; enum class Empty4 : uint32_t {}; - //REQUIRE(magic_enum::detail::is_valid_enum_v>); - //REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); - REQUIRE(magic_enum::detail::is_valid_enum_v>); + //REQUIRE(magic_enum::detail::is_reflected_v>); + //REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); + REQUIRE(magic_enum::detail::is_reflected_v>); }