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-03-28 18:55:25 +04:00 committed by GitHub
parent 64bedded2a
commit cee99df7b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 11 deletions

View file

@ -170,6 +170,9 @@ constexpr size_t enum_count() noexcept;
```cpp
template <typename E>
constexpr underlying_type_t<E> enum_integer(E value) noexcept;
template <typename E>
constexpr underlying_type_t<E> enum_underlying(E value) noexcept;
```
* Returns integer value from enum value.

View file

@ -351,10 +351,14 @@ template <typename I>
constexpr I log2(I value) noexcept {
static_assert(std::is_integral_v<I>, "magic_enum::detail::log2 requires integral type.");
auto ret = I{0};
for (; value > I{1}; value >>= I{1}, ++ret) {}
if constexpr (std::is_same_v<I, bool>) { // bool special case
return assert(false), value;
} else {
auto ret = I{0};
for (; value > I{1}; value >>= I{1}, ++ret) {}
return ret;
return ret;
}
}
template <typename T>
@ -597,11 +601,18 @@ using entries_t = decltype((entries_v<D>));
template <typename E, typename U = std::underlying_type_t<E>>
constexpr bool is_sparse() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::is_sparse requires enum type.");
constexpr auto max = is_flags_v<E> ? log2(max_v<E>) : max_v<E>;
constexpr auto min = is_flags_v<E> ? log2(min_v<E>) : min_v<E>;
constexpr auto range_size = max - min + 1;
return range_size != count_v<E> && count_v<E> > 0;
if constexpr (count_v<E> == 0) {
return false;
} else if constexpr (std::is_same_v<U, bool>) { // bool special case
return false;
} else {
constexpr auto max = is_flags_v<E> ? log2(max_v<E>) : max_v<E>;
constexpr auto min = is_flags_v<E> ? log2(min_v<E>) : min_v<E>;
constexpr auto range_size = max - min + 1;
return range_size != count_v<E>;
}
}
template <typename E>
@ -660,8 +671,8 @@ template <typename Value>
struct constexpr_hash_t<Value, std::enable_if_t<is_enum_v<Value>>> {
constexpr auto operator()(Value value) const noexcept {
using U = typename underlying_type<Value>::type;
if constexpr (std::is_same_v<U, bool>) {
return static_cast<std::size_t>(static_cast<bool>(value));
if constexpr (std::is_same_v<U, bool>) { // bool special case
return static_cast<std::size_t>(value);
} else {
return static_cast<U>(value);
}
@ -961,6 +972,13 @@ template <typename E>
return static_cast<underlying_type_t<E>>(value);
}
// Returns underlying value from enum value.
template <typename E>
[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_enum_t<E, underlying_type_t<E>> {
return static_cast<underlying_type_t<E>>(value);
}
// Obtains index in enum values from enum value.
// Returns optional with index.
template <typename E>

View file

@ -103,6 +103,8 @@ struct magic_enum::customize::enum_range<Binary> {
static constexpr int max = 64;
};
enum class BoolTest : bool { Yay, Nay };
using namespace magic_enum;
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
@ -157,6 +159,8 @@ TEST_CASE("enum_cast") {
constexpr auto crc = magic_enum::enum_cast<crc_hack_2>("b5a7b602ab754d7ab30fb42c4fb28d82");
REQUIRE(crc.value() == crc_hack_2::b5a7b602ab754d7ab30fb42c4fb28d82);
REQUIRE(magic_enum::enum_cast<crc_hack_2>("d19f2e9e82d14b96be4fa12b8a27ee9f").value() == crc_hack_2::d19f2e9e82d14b96be4fa12b8a27ee9f);
REQUIRE(magic_enum::enum_cast<BoolTest>("Nay").has_value());
}
SECTION("integer") {
@ -196,6 +200,9 @@ TEST_CASE("enum_cast") {
REQUIRE(nt.value() == number::three);
REQUIRE_FALSE(enum_cast<number>(400).has_value());
REQUIRE_FALSE(enum_cast<number>(0).has_value());
REQUIRE(enum_cast<BoolTest>(false).has_value());
REQUIRE(enum_cast<BoolTest>(0).has_value());
}
}
@ -239,6 +246,8 @@ TEST_CASE("enum_integer") {
REQUIRE(nt == 300);
REQUIRE(enum_integer(number::four) == 400);
REQUIRE(enum_integer(static_cast<number>(0)) == 0);
REQUIRE(enum_integer(BoolTest::Yay) == false);
}
TEST_CASE("enum_index") {
@ -285,6 +294,8 @@ TEST_CASE("enum_index") {
REQUIRE(nt.value() == 2);
REQUIRE_FALSE(enum_index(number::four).has_value());
REQUIRE_FALSE(enum_index(static_cast<number>(0)).has_value());
REQUIRE(enum_index<BoolTest::Yay>() == 0);
}
TEST_CASE("enum_contains") {
@ -328,6 +339,8 @@ TEST_CASE("enum_contains") {
REQUIRE(nt);
REQUIRE_FALSE(enum_contains(number::four));
REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
REQUIRE(enum_contains(BoolTest::Yay));
}
SECTION("integer") {
@ -368,6 +381,9 @@ TEST_CASE("enum_contains") {
REQUIRE_FALSE(enum_contains<number>(number::four));
REQUIRE_FALSE(enum_contains<number>(111));
REQUIRE_FALSE(enum_contains<number>(0));
REQUIRE(enum_contains<BoolTest>(false));
REQUIRE(enum_contains<BoolTest>(0));
}
SECTION("string") {
@ -412,6 +428,8 @@ TEST_CASE("enum_contains") {
REQUIRE(nt);
REQUIRE_FALSE(enum_contains<number>("four"));
REQUIRE_FALSE(enum_contains<number>("None"));
REQUIRE(enum_contains<BoolTest>("Yay"));
}
}
@ -461,6 +479,9 @@ TEST_CASE("enum_value") {
REQUIRE(enum_value<number, 0>() == number::one);
REQUIRE(enum_value<number, 1>() == number::two);
REQUIRE(enum_value<number, 2>() == number::three);
REQUIRE(enum_value<BoolTest>(0) == BoolTest::Yay);
REQUIRE(enum_value<BoolTest, 0>() == BoolTest::Yay);
}
TEST_CASE("enum_values") {
@ -1101,7 +1122,7 @@ TEST_CASE("constexpr_for") {
});
}
#ifdef _MSC_VER
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4064)
#endif
@ -1130,7 +1151,7 @@ static int switch_case_3d(Color color, Directions direction, Index index) {
}
}
#ifdef _MSC_VER
#if defined(_MSC_VER)
# pragma warning(pop)
#endif