Skip to content

Commit

Permalink
clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
Neargye committed Dec 17, 2023
1 parent e09f257 commit e26b05e
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 89 deletions.
106 changes: 41 additions & 65 deletions include/magic_enum/magic_enum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,28 +869,16 @@ constexpr bool is_sparse() noexcept {
template <typename E, enum_subtype S = subtype_v<E>>
inline constexpr bool is_sparse_v = is_sparse<E, S>();

template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
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<E, S>; ++i) {
ors |= static_cast<U>(values_v<E, S>[i]);
}

return ors;
}

template <typename E, enum_subtype S>
struct is_valid_enum
struct is_reflected
#if defined(MAGIC_ENUM_NO_CHECK_VALID_ENUM_TYPE)
: std::true_type {};
#else
: std::bool_constant<std::is_enum_v<E> && (count_v<E, S> > 0)> {};
: std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
#endif

template <typename E, enum_subtype S>
inline constexpr auto is_valid_enum_v = is_valid_enum<std::decay_t<E>, S>{};
inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};

template <bool, typename R>
struct enable_if_enum {};
Expand Down Expand Up @@ -1191,7 +1179,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::is_sparse_v<D, S>) {
return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
Expand All @@ -1206,7 +1194,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");

return enum_value<D, S>(I);
Expand All @@ -1216,7 +1204,7 @@ template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

return detail::values_v<D, S>;
}
Expand All @@ -1239,12 +1227,9 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
#if defined(MAGIC_ENUM_ENABLE_HASH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<std::size_t>{i}; },
Expand Down Expand Up @@ -1272,7 +1257,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <detail::enum_subtype S, typename E>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

return enum_index<D, S>(value);
}
Expand All @@ -1281,7 +1266,7 @@ template <detail::enum_subtype S, typename E>
template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
using D = std::decay_t<decltype(V)>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
constexpr auto index = enum_index<D, S>(V);
static_assert(index, "magic_enum::enum_index enum value does not have a index.");

Expand All @@ -1303,7 +1288,7 @@ template <auto V>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if (const auto i = enum_index<D, S>(value)) {
return detail::names_v<D, S>[*i];
Expand All @@ -1316,7 +1301,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <detail::enum_subtype S, typename E>
[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t<E, string_view> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

return enum_name<D, S>(value);
}
Expand All @@ -1325,7 +1310,7 @@ template <detail::enum_subtype S, typename E>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

return detail::names_v<D, S>;
}
Expand All @@ -1334,7 +1319,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

return detail::entries_v<D, S>;
}
Expand All @@ -1347,32 +1332,27 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{};
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
#if defined(MAGIC_ENUM_ENABLE_HASH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
[](D v) { return optional<D>{v}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
[](D v) { return optional<D>{v}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
#else
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
return static_cast<D>(value);
}
}
return {}; // Invalid value or out of range.
#endif
} else {
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
return static_cast<D>(value);
}
return {}; // Invalid value or out of range.
}
return {}; // Invalid value or out of range.
#endif
} else {
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
return static_cast<D>(value);
}
return {}; // Invalid value or out of range.
}
}

Expand All @@ -1381,27 +1361,23 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
[[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> {
using D = std::decay_t<E>;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
#if defined(MAGIC_ENUM_ENABLE_HASH)
} else if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
value,
detail::default_result_type_lambda<optional<D>>,
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
value,
detail::default_result_type_lambda<optional<D>>,
[&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<D, S>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
return enum_value<D, S>(i);
}
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
return enum_value<D, S>(i);
}
return {}; // Invalid value or out of range.
}
return {}; // Invalid value or out of range.
}

// Checks whether enum contains value with such value.
Expand Down
22 changes: 19 additions & 3 deletions include/magic_enum/magic_enum_flags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,30 @@

namespace magic_enum {

namespace detail {

template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
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<E, S>; ++i) {
ors |= static_cast<U>(values_v<E, S>[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 <typename E>
[[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast<char_type>('|')) -> detail::enable_if_t<E, string> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

string name;
auto check_value = U{0};
Expand Down Expand Up @@ -83,7 +99,7 @@ template <typename E>
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
Expand Down Expand Up @@ -119,7 +135,7 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");

if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
Expand Down
8 changes: 4 additions & 4 deletions include/magic_enum/magic_enum_switch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ using invoke_result_t = typename invoke_result<F, V>::type;

template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
static_assert(std::is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");

if constexpr (count_v<E, S> == 0) {
return identity<nonesuch>{};
Expand All @@ -69,7 +69,7 @@ constexpr auto common_invocable(std::index_sequence<I...>) noexcept {

template <typename E, enum_subtype S, typename Result, typename F>
constexpr auto result_type() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
static_assert(std::is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");

constexpr auto seq = std::make_index_sequence<count_v<E, S>>{};
using R = typename decltype(common_invocable<E, S, F>(seq))::type;
Expand Down Expand Up @@ -137,7 +137,7 @@ template <typename Result = detail::default_result_type, typename E, detail::enu
constexpr decltype(auto) enum_switch(F&& f, E value) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "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<D, S>, detail::case_call_t::value>(
Expand All @@ -161,7 +161,7 @@ template <typename Result, typename E, detail::enum_subtype S = detail::subtype_
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "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<D, S>, detail::case_call_t::value>(
Expand Down
2 changes: 1 addition & 1 deletion include/magic_enum/magic_enum_utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F,
constexpr auto enum_for_each(F&& f) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
static_assert(detail::is_valid_enum_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
constexpr auto sep = std::make_index_sequence<detail::count_v<D, S>>{};

if constexpr (detail::all_invocable<D, S, F>(sep)) {
Expand Down
32 changes: 16 additions & 16 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1257,20 +1257,20 @@ TEST_CASE("valid_enum") {
enum class Empty3 {};
enum class Empty4 : uint32_t {};

//REQUIRE(magic_enum::detail::is_valid_enum_v<Forward1, as_flags<true>>);
//REQUIRE(magic_enum::detail::is_valid_enum_v<Forward1, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward2, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward2, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward3, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward3, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward4, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Forward4, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty1, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty1, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty2, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty2, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty3, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty3, as_flags<false>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty4, as_flags<true>>);
REQUIRE(magic_enum::detail::is_valid_enum_v<Empty4, as_flags<false>>);
//REQUIRE(magic_enum::detail::is_reflected_v<Forward1, as_flags<true>>);
//REQUIRE(magic_enum::detail::is_reflected_v<Forward1, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward2, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward2, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward3, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward3, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward4, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Forward4, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty1, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty1, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty2, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty2, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty3, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty3, as_flags<false>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty4, as_flags<true>>);
REQUIRE(magic_enum::detail::is_reflected_v<Empty4, as_flags<false>>);
}

0 comments on commit e26b05e

Please sign in to comment.