1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-09 23:34:23 +00:00
This commit is contained in:
Daniil Goncharov 2022-08-17 21:38:30 +04:00 committed by GitHub
parent 8f9f4afee7
commit d26a7a2293
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -166,8 +166,8 @@ constexpr customize_t enum_type_name() noexcept {
namespace detail {
template <auto V, typename = std::enable_if_t<std::is_enum_v<std::decay_t<decltype(V)>>>>
using enum_constant = std::integral_constant<std::decay_t<decltype(V)>, V>;
template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
using enum_constant = std::integral_constant<E, V>;
template <typename... T>
inline constexpr bool always_false_v = false;
@ -696,7 +696,7 @@ struct enable_if_enum<true, R> {
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>>
using enable_if_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>> && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;
template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>
template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
using enum_concept = T;
template <typename T, bool = std::is_enum_v<T>>
@ -717,6 +717,13 @@ struct underlying_type {};
template <typename T>
struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
#if defined(MAGIC_ENUM_NO_HASH)
template <typename T>
inline constexpr bool has_hash = false;
#else
template <typename T>
inline constexpr bool has_hash = true;
template <typename Value, typename = void>
struct constexpr_hash_t;
@ -930,6 +937,7 @@ constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(
#undef MAGIC_ENUM_FOR_EACH_256
#undef MAGIC_ENUM_CASE
#endif
template <typename E, typename Lambda, std::size_t... I>
constexpr auto for_each(Lambda&& lambda, std::index_sequence<I...>) {
@ -946,6 +954,13 @@ constexpr auto for_each(Lambda&& lambda, std::index_sequence<I...>) {
}
}
template <typename E, typename Lambda, std::size_t... I>
constexpr bool all_invocable(std::index_sequence<I...>) {
static_assert(is_enum_v<E>, "magic_enum::detail::all_invocable requires enum type.");
return (std::is_invocable_v<Lambda, enum_constant<values_v<E>[I]>> && ...);
}
} // namespace magic_enum::detail
// Checks is magic_enum supported compiler.
@ -1049,10 +1064,19 @@ template <typename E>
if constexpr (detail::count_v<D> == 0) {
return {}; // Empty enum.
} else if constexpr (detail::is_sparse_v<D> || detail::is_flags_v<D>) {
#if defined(MAGIC_ENUM_NO_HASH)
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
if (enum_value<D>(i) == value) {
return i;
}
}
return {}; // Invalid value or out of range.
#else
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::index>(
[](std::size_t i) { return optional<std::size_t>{i}; },
value,
detail::default_result_type_lambda<optional<std::size_t>>);
#endif
} else {
const auto v = static_cast<U>(value);
if (v >= detail::min_v<D> && v <= detail::max_v<D>) {
@ -1120,7 +1144,10 @@ template <typename E>
return {}; // Invalid value or out of range.
} else {
return string{enum_name<D>(value)};
if (const auto name = enum_name<D>(value); !name.empty()) {
return {name.data(), name.size()};
}
return {}; // Invalid value or out of range.
}
}
@ -1150,9 +1177,8 @@ template <typename E>
return {}; // Empty enum.
} else if constexpr (detail::is_sparse_v<D>) {
if constexpr (detail::is_flags_v<D>) {
constexpr auto count = detail::count_v<D>;
auto check_value = U{0};
for (std::size_t i = 0; i < count; ++i) {
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
if (const auto v = static_cast<U>(enum_value<D>(i)); (value & v) != 0) {
check_value |= v;
}
@ -1163,10 +1189,19 @@ template <typename E>
}
return {}; // Invalid value or out of range.
} else {
#if defined(MAGIC_ENUM_NO_HASH)
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
if (value == static_cast<U>(enum_value<D>(i))) {
return static_cast<D>(value);
}
}
return {}; // Invalid value or out of range.
#else
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
[](D v) { return optional<D>{v}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
#endif
}
} else {
constexpr auto min = detail::min_v<D>;
@ -1214,11 +1249,20 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
return {}; // Invalid value or out of range.
} else if constexpr (detail::count_v<D> > 0) {
if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
#if defined(MAGIC_ENUM_NO_HASH)
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {
return enum_value<D>(i);
}
}
return {}; // Invalid value or out of range.
#else
return detail::constexpr_switch<&detail::names_v<D>, detail::case_call_t::index>(
[](std::size_t i) { return optional<D>{detail::values_v<D>[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>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {
@ -1259,6 +1303,7 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
template <typename Result = void, typename E, typename Lambda>
constexpr auto enum_switch(Lambda&& lambda, E value) -> detail::enable_if_t<E, Result> {
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
std::forward<Lambda>(lambda),
@ -1269,6 +1314,7 @@ constexpr auto enum_switch(Lambda&& lambda, E value) -> detail::enable_if_t<E, R
template <typename Result, typename E, typename Lambda>
constexpr auto enum_switch(Lambda&& lambda, E value, Result&& result) -> detail::enable_if_t<E, Result> {
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
std::forward<Lambda>(lambda),
@ -1280,6 +1326,7 @@ template <typename E, typename Result = void, typename BinaryPredicate = std::eq
constexpr auto enum_switch(Lambda&& lambda, string_view name, BinaryPredicate&& p = {}) -> detail::enable_if_t<E, Result, BinaryPredicate> {
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_switch requires bool(char, char) invocable predicate.");
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
if (const auto v = enum_cast<D>(name, std::forward<BinaryPredicate>(p))) {
return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v);
@ -1291,6 +1338,7 @@ template <typename E, typename Result, typename BinaryPredicate = std::equal_to<
constexpr auto enum_switch(Lambda&& lambda, string_view name, Result&& result, BinaryPredicate&& p = {}) -> detail::enable_if_t<E, Result, BinaryPredicate> {
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_switch requires bool(char, char) invocable predicate.");
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
if (const auto v = enum_cast<D>(name, std::forward<BinaryPredicate>(p))) {
return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v, std::forward<Result>(result));
@ -1301,6 +1349,7 @@ constexpr auto enum_switch(Lambda&& lambda, string_view name, Result&& result, B
template <typename E, typename Result = void, typename Lambda>
constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value) -> detail::enable_if_t<E, Result> {
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
if (const auto v = enum_cast<D>(value)) {
return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v);
@ -1311,6 +1360,7 @@ constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value) -> detai
template <typename E, typename Result, typename Lambda>
constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value, Result&& result) -> detail::enable_if_t<E, Result> {
using D = std::decay_t<E>;
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires no defined MAGIC_ENUM_NO_HASH");
if (const auto v = enum_cast<D>(value)) {
return enum_switch<Result, D>(std::forward<Lambda>(lambda), *v, std::forward<Result>(result));
@ -1318,12 +1368,17 @@ constexpr auto enum_switch(Lambda&& lambda, underlying_type_t<E> value, Result&&
return std::forward<Result>(result);
}
template <typename E, typename Lambda>
template <typename E, typename Lambda, detail::enable_if_t<E, int> = 0>
constexpr auto enum_for_each(Lambda&& lambda) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
constexpr auto sep = std::make_index_sequence<detail::count_v<D>>{};
return detail::for_each<D>(std::forward<Lambda>(lambda), std::make_index_sequence<detail::count_v<D>>{});
if constexpr (detail::all_invocable<D, Lambda>(sep)) {
return detail::for_each<D>(std::forward<Lambda>(lambda), sep);
} else {
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
}
}
namespace ostream_operators {