1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-09 23:34:23 +00:00

add compile time enum_index (#159)

This commit is contained in:
Daniil Goncharov 2022-03-09 10:07:09 +02:00 committed by GitHub
parent 04a3d32d0f
commit b0c0e02bdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 28 deletions

View file

@ -108,11 +108,14 @@ constexpr optional<E> enum_cast(string_view value, BinaryPredicate p) noexcept(i
```cpp
template <typename E>
constexpr E enum_value(size_t index) noexcept;
template <typename E, size_t I>
constexpr E enum_value() noexcept;
```
* Returns enum value at specified index.
* No bounds checking is performed: the behavior is undefined if `index >= number of enum values`.
* `enum_value(value)` no bounds checking is performed: the behavior is undefined if `index >= number of enum values`.
* `enum_value<value>()` check if `I >= number of enum values`, occurs the compilation error `magic_enum::enum_value out of range`.
* Examples
@ -120,7 +123,12 @@ constexpr E enum_value(size_t index) noexcept;
int i = 1;
Color color = magic_enum::enum_value<Color>(i);
// color -> Color::BLUE
````
```
```cpp
Color color = magic_enum::enum_value<Color, 1>();
// color -> Color::BLUE
```
## `enum_values`
@ -184,27 +192,23 @@ constexpr string_view enum_name() noexcept;
* Returns name from enum value as `string_view` with null-terminated string.
* If enum value does not have name or [out of range](limitations.md), `enum_name(value)` returns empty string.
* If enum value does not have name, `enum_name<value>()` occurs the compilation error `"Enum value does not have a name."`.
* If enum value does not have name, `enum_name<value>()` occurs the compilation error `magic_enum::enum_name enum value does not have a name`.
* `enum_name<value>()` is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md).
* Examples
* Enum value to string.
```cpp
Color color = Color::RED;
auto color_name = magic_enum::enum_name(color);
// color_name -> "RED"
```
```cpp
Color color = Color::RED;
auto color_name = magic_enum::enum_name(color);
// color_name -> "RED"
```
* Static storage enum variable to string.
```cpp
constexpr Color color = Color::BLUE;
constexpr auto color_name = magic_enum::enum_name<color>();
// color_name -> "BLUE"
```
```cpp
constexpr Color color = Color::BLUE;
constexpr auto color_name = magic_enum::enum_name<color>();
// color_name -> "BLUE"
```
## `enum_flags_name`
@ -264,19 +268,27 @@ constexpr array<pair<E, string_view>, N> enum_entries() noexcept;
```cpp
template <typename E>
constexpr optional<size_t> enum_index() noexcept;
constexpr optional<size_t> enum_index(E value) noexcept;
template <auto V>
constexpr size_t enum_index() noexcept;
```
* Obtains index in enum values from enum value.
* Returns `optional<size_t>` with index.
* `enum_index(value)` returns `optional<size_t>` with index.
* `enum_index<value>()` returns index. If enum value does not have a index, occurs the compilation error `magic_enum::enum_index enum value does not have a index`.
* Examples
```cpp
constexpr auto color_index = magic_enum::enum_index(Color::BLUE);
// color_index -> color_index.value() -> 1
// color_index -> color_index.has_value() -> true
// color_index.value() -> 1
// color_index.has_value() -> true
```
```cpp
constexpr auto color_index = magic_enum::enum_index<Color::BLUE>();
// color_index -> 1
```
## `enum_contains`
@ -330,7 +342,7 @@ constexpr string_view enum_type_name() noexcept;
```cpp
template <typename... Es>
[[nodiscard]] constexpr optional<enum_fuse_t> enum_fuse(Es... values);
[[nodiscard]] constexpr optional<enum_fuse_t> enum_fuse(Es... values) noexcept;
```
* Returns a typesafe bijective mix of several enum values. This can be used to emulate 2D switch/case statements.
@ -339,7 +351,7 @@ template <typename... Es>
* Switch/case statement over an incomplete enum is a Visual Studio warning C4064
* You have to silent (/wd4064) or ignore it.
* Alternatively, define `MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE` to disable type-safety (`enum_fuse_t` equals `std::uintmax_t`).
* Alternatively, define `MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE` to disable type-safety (`enum_fuse_t` equals `uintmax_t`).
* Examples

View file

@ -661,7 +661,7 @@ using underlying_type_t = typename underlying_type<T>::type;
template <typename E>
[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_enum_t<E, string_view> {
constexpr string_view name = detail::type_name_v<std::decay_t<E>>;
static_assert(name.size() > 0, "Enum type does not have a name.");
static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name.");
return name;
}
@ -691,7 +691,10 @@ template <typename E>
// Returns enum value at specified index.
template <typename E, std::size_t I>
[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> {
return enum_value<std::decay_t<E>>(I);
using D = std::decay_t<E>;
static_assert(I < detail::count_v<D>, "magic_enum::enum_value out of range.");
return enum_value<D>(I);
}
// Returns std::array with enum values, sorted by enum value.
@ -705,7 +708,7 @@ template <typename E>
template <auto V>
[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t<decltype(V), string_view> {
constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;
static_assert(name.size() > 0, "Enum value does not have a name.");
static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");
return name;
}
@ -888,6 +891,15 @@ template <typename E>
return {}; // Invalid value or out of range.
}
// Obtains index in enum values from static storage enum variable.
template <auto V>
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_enum_t<decltype(V), std::size_t> {
constexpr auto index = enum_index<std::decay_t<decltype(V)>>(V);
static_assert(index.has_value(), "magic_enum::enum_index enum value does not have a index.");
return index.value();
}
// Checks whether enum contains enumerator with such enum value.
template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> {

View file

@ -230,12 +230,14 @@ TEST_CASE("enum_index") {
constexpr auto cr = enum_index(Color::RED);
Color cg = Color::GREEN;
REQUIRE(cr.value() == 0);
REQUIRE(enum_index<Color::RED>() == 0);
REQUIRE(enum_index<Color&>(cg).value() == 1);
REQUIRE(enum_index(cm[2]).value() == 2);
REQUIRE_FALSE(enum_index(static_cast<Color>(0)).has_value());
constexpr auto no = enum_index(Numbers::one);
REQUIRE(no.value() == 0);
REQUIRE(enum_index<Numbers::one>() == 0);
REQUIRE(enum_index(Numbers::two).value() == 1);
REQUIRE(enum_index(Numbers::three).value() == 2);
REQUIRE_FALSE(enum_index(Numbers::many).has_value());
@ -243,6 +245,7 @@ TEST_CASE("enum_index") {
constexpr auto dr = enum_index(Directions::Right);
Directions dl = Directions::Left;
REQUIRE(enum_index<Directions::Left>() == 0);
REQUIRE(enum_index<Directions&>(dl).value() == 0);
REQUIRE(enum_index<const Directions>(Directions::Down).value() == 1);
REQUIRE(enum_index(Directions::Up).value() == 2);
@ -260,6 +263,7 @@ TEST_CASE("enum_index") {
#endif
constexpr auto nt = enum_index(number::three);
REQUIRE(enum_index<number::one>() == 0);
REQUIRE(enum_index(number::one).value() == 0);
REQUIRE(enum_index(number::two).value() == 1);
REQUIRE(nt.value() == 2);