1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-10 23:44:29 +00:00
This commit is contained in:
neargye 2020-07-04 15:13:15 +05:00
parent d9f4cd5e74
commit d2904860b8
2 changed files with 34 additions and 33 deletions

View file

@ -299,6 +299,9 @@ constexpr auto values(std::integer_sequence<int, I...>) noexcept {
template <typename E> template <typename E>
inline constexpr auto values_v = values<E>(std::make_integer_sequence<int, range_size<E, reflected_min_v<E>, reflected_max_v<E>>()>{}); inline constexpr auto values_v = values<E>(std::make_integer_sequence<int, range_size<E, reflected_min_v<E>, reflected_max_v<E>>()>{});
template <typename T, typename D = std::decay_t<T>>
using values_t = decltype((values_v<D>));
template <typename E> template <typename E>
inline constexpr std::size_t count_v = values_v<E>.size(); inline constexpr std::size_t count_v = values_v<E>.size();
@ -338,6 +341,9 @@ constexpr auto names(std::index_sequence<I...>) noexcept {
template <typename E> template <typename E>
inline constexpr auto names_v = names<E>(std::make_index_sequence<count_v<E>>{}); inline constexpr auto names_v = names<E>(std::make_index_sequence<count_v<E>>{});
template <typename T, typename D = std::decay_t<T>>
using names_t = decltype((names_v<D>));
template <typename E, std::size_t... I> template <typename E, std::size_t... I>
constexpr auto entries(std::index_sequence<I...>) noexcept { constexpr auto entries(std::index_sequence<I...>) noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::entries requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::entries requires enum type.");
@ -348,6 +354,9 @@ constexpr auto entries(std::index_sequence<I...>) noexcept {
template <typename E> template <typename E>
inline constexpr auto entries_v = entries<E>(std::make_index_sequence<count_v<E>>{}); inline constexpr auto entries_v = entries<E>(std::make_index_sequence<count_v<E>>{});
template <typename T, typename D = std::decay_t<T>>
using entries_t = decltype((entries_v<D>));
template <typename E> template <typename E>
inline constexpr bool is_sparse_v = range_size_v<E> != count_v<E>; inline constexpr bool is_sparse_v = range_size_v<E> != count_v<E>;
@ -375,8 +384,19 @@ constexpr int endex(E value) noexcept {
return undex<E>(static_cast<std::underlying_type_t<E>>(value)); return undex<E>(static_cast<std::underlying_type_t<E>>(value));
} }
template <bool, typename T, typename R>
struct enable_if_enum {};
template <typename T, typename R> template <typename T, typename R>
using enable_if_enum_t = std::enable_if_t<std::is_enum_v<std::decay_t<T>>, R>; struct enable_if_enum<true, T, R> {
using type = R;
using D = std::decay_t<T>;
static_assert(supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
};
template <typename T, typename R = void>
using enable_if_enum_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, T, R>::type;
template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>> template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>
using enum_concept = T; using enum_concept = T;
@ -433,8 +453,9 @@ using underlying_type_t = typename underlying_type<T>::type;
// Returns string name of enum type. // Returns string name of enum type.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_enum_t<E, std::string_view> { [[nodiscard]] constexpr std::string_view enum_type_name() noexcept {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "Requires enum type.");
constexpr std::string_view name = detail::type_name_v<D>; constexpr std::string_view name = detail::type_name_v<D>;
static_assert(name.size() > 0, "Enum type does not have a name."); static_assert(name.size() > 0, "Enum type does not have a name.");
@ -445,8 +466,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t<E, std::size_t> { [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t<E, std::size_t> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::count_v<D>; return detail::count_v<D>;
} }
@ -456,8 +475,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> { [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::is_sparse_v<D>) { if constexpr (detail::is_sparse_v<D>) {
return assert(index < detail::count_v<D>), detail::values_v<D>[index]; return assert(index < detail::count_v<D>), detail::values_v<D>[index];
@ -469,10 +486,8 @@ template <typename E>
// Obtains value enum sequence. // Obtains value enum sequence.
// Returns std::array with enum values, sorted by enum value. // Returns std::array with enum values, sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, decltype(detail::values_v<std::decay_t<E>>)&> { [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, detail::values_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::values_v<D>; return detail::values_v<D>;
} }
@ -480,9 +495,9 @@ template <typename E>
// Returns string enum name from static storage enum variable. // Returns string enum name from static storage enum variable.
// This version is much lighter on the compile times and is not restricted to the enum_range limitation. // This version is much lighter on the compile times and is not restricted to the enum_range limitation.
template <auto V> template <auto V>
[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t<decltype(V), std::string_view> { [[nodiscard]] constexpr std::string_view enum_name() noexcept {
using D = std::decay_t<decltype(V)>; using D = std::decay_t<decltype(V)>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); static_assert(std::is_enum_v<D>, "Requires enum type.");
constexpr std::string_view name = detail::enum_name_v<std::decay_t<D>, V>; constexpr std::string_view name = detail::enum_name_v<std::decay_t<D>, V>;
static_assert(name.size() > 0, "Enum value does not have a name."); static_assert(name.size() > 0, "Enum value does not have a name.");
@ -494,8 +509,6 @@ template <auto V>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, std::string_view> { [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, std::string_view> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
if (const auto i = detail::endex<D>(value); i != -1) { if (const auto i = detail::endex<D>(value); i != -1) {
return detail::names_v<D>[i]; return detail::names_v<D>[i];
@ -507,10 +520,8 @@ template <typename E>
// Obtains string enum name sequence. // Obtains string enum name sequence.
// Returns std::array with string enum names, sorted by enum value. // Returns std::array with string enum names, sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, decltype(detail::names_v<std::decay_t<E>>)&> { [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, detail::names_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::names_v<D>; return detail::names_v<D>;
} }
@ -518,10 +529,8 @@ template <typename E>
// Obtains pair (value enum, string enum name) sequence. // Obtains pair (value enum, string enum name) sequence.
// Returns std::array with std::pair (value enum, string enum name), sorted by enum value. // Returns std::array with std::pair (value enum, string enum name), sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, decltype(detail::entries_v<std::decay_t<E>>)&> { [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, detail::entries_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::entries_v<D>; return detail::entries_v<D>;
} }
@ -531,8 +540,6 @@ template <typename E>
template <typename E, typename BinaryPredicate> template <typename E, typename BinaryPredicate>
[[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate."); static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");
for (std::size_t i = 0; i < detail::count_v<D>; ++i) { for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
@ -547,8 +554,6 @@ template <typename E, typename BinaryPredicate>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
for (std::size_t i = 0; i < detail::count_v<D>; ++i) { for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
if (value == detail::names_v<D>[i]) { if (value == detail::names_v<D>[i]) {
@ -564,8 +569,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
if (detail::undex<D>(value) != -1) { if (detail::undex<D>(value) != -1) {
return static_cast<D>(value); return static_cast<D>(value);
@ -585,8 +588,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> { [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
if (const auto i = detail::endex<D>(value); i != -1) { if (const auto i = detail::endex<D>(value); i != -1) {
return i; return i;
@ -599,8 +600,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::endex<D>(value) != -1; return detail::endex<D>(value) != -1;
} }
@ -609,8 +608,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return detail::undex<D>(value) != -1; return detail::undex<D>(value) != -1;
} }
@ -619,8 +616,6 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert(detail::supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(detail::count_v<D> > 0, "magic_enum requires enum implementation and valid max and min.");
return enum_cast<D>(value).has_value(); return enum_cast<D>(value).has_value();
} }

View file

@ -310,6 +310,8 @@ TEST_CASE("enum_value") {
} }
TEST_CASE("enum_values") { TEST_CASE("enum_values") {
REQUIRE(std::is_same_v<decltype(magic_enum::enum_values<Color>()), const std::array<Color, 3>&>);
constexpr auto s1 = enum_values<Color&>(); constexpr auto s1 = enum_values<Color&>();
REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}}); REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}});
@ -406,6 +408,8 @@ TEST_CASE("enum_name") {
} }
TEST_CASE("enum_names") { TEST_CASE("enum_names") {
REQUIRE(std::is_same_v<decltype(magic_enum::enum_names<Color>()), const std::array<std::string_view, 3>&>);
constexpr auto s1 = enum_names<Color&>(); constexpr auto s1 = enum_names<Color&>();
REQUIRE(s1 == std::array<std::string_view, 3>{{"RED", "GREEN", "BLUE"}}); REQUIRE(s1 == std::array<std::string_view, 3>{{"RED", "GREEN", "BLUE"}});
@ -420,6 +424,8 @@ TEST_CASE("enum_names") {
} }
TEST_CASE("enum_entries") { TEST_CASE("enum_entries") {
REQUIRE(std::is_same_v<decltype(magic_enum::enum_entries<Color>()), const std::array<std::pair<Color, std::string_view>, 3>&>);
constexpr auto s1 = enum_entries<Color&>(); constexpr auto s1 = enum_entries<Color&>();
REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "RED"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}}); REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "RED"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});