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

Add enum fusing function (#127)

This commit is contained in:
Pavel I. Kryukov 2022-02-10 20:58:59 +03:00 committed by GitHub
parent 22242a613a
commit 1f8e29b140
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 0 deletions

View file

@ -32,6 +32,7 @@ Header-only C++17 library provides static reflection for enums, work with any en
* `enum_index` obtains index in enum value sequence from enum value.
* `enum_contains` checks whether enum contains enumerator with such value.
* `enum_type_name` returns name of enum type.
* `enum_fuse` allows multidimensional switch/cases.
* `is_unscoped_enum` checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration).
* `is_scoped_enum` checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations).
* `underlying_type` improved UB-free "SFINAE-friendly" [underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type).
@ -137,6 +138,16 @@ enum class Color { RED = 2, BLUE = 4, GREEN = 8 };
// color_entries[0].second -> "RED"
```
* Enum fusion for multi-level switch/case statements
```cpp
switch (magic_enum::enum_fuse(color1, color2)) {
case magic_enum::enum_fuse(RED, BLUE): // ...
case magic_enum::enum_fuse(RED, RED): // ...
// ...
}
```
* Ostream operator for enum
```cpp

View file

@ -12,6 +12,7 @@
* [`enum_index` obtains index in enum value sequence from enum value.](#enum_index)
* [`enum_contains` checks whether enum contains enumerator with such value.](#enum_contains)
* [`enum_type_name` returns type name of enum.](#enum_type_name)
* [`enum_fuse` returns a bijective mix of enum values.](#enum_fuse)
* [`is_unscoped_enum` checks whether type is an Unscoped enumeration.](#is_unscoped_enum)
* [`is_scoped_enum` checks whether type is an Scoped enumeration.](#is_scoped_enum)
* [`underlying_type` improved UB-free "SFINAE-friendly" underlying_type.](#underlying_type)
@ -325,6 +326,25 @@ constexpr string_view enum_type_name() noexcept;
// color_name -> "Color"
```
## `enum_fuse`
```cpp
template<typename ... Es>
[[nodiscard]] constexpr size_t enum_fuse(Es ... values);
```
* Returns a bijective mix of several enum values with [Cantor pairing function](https://en.wikipedia.org/wiki/Pairing_function). This can be used to emulate 2D switch/case statements.
* Examples
```cpp
switch (magic_enum::enum_fuse(color1, color2)) {
case magic_enum::enum_fuse(RED, BLUE): // ...
case magic_enum::enum_fuse(RED, RED): // ...
// ...
}
```
## `is_unscoped_enum`
```cpp

View file

@ -609,6 +609,15 @@ struct underlying_type {};
template <typename T>
struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
constexpr size_t cantor_pair(size_t v1, size_t v2) noexcept {
return (((v1 + v2) * (v1 + v2 + 1)) >> 1) + v2;
}
template<typename ... Ts>
constexpr size_t cantor_pair(size_t v1, size_t head, Ts ... tail) noexcept {
return cantor_pair(cantor_pair(v1, head), tail...);
}
} // namespace magic_enum::detail
// Checks is magic_enum supported compiler.
@ -878,6 +887,13 @@ template <typename E>
return {}; // Invalid value or out of range.
}
template<typename ... Es>
[[nodiscard]] constexpr size_t enum_fuse(Es ... enums) {
static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 enums");
// Add 1 to prevent matching 2D fusions with 3D fusions etc.
return detail::cantor_pair((enum_index(enums).value() + 1)...);
}
// 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

@ -1014,4 +1014,44 @@ TEST_CASE("constexpr_for") {
});
}
static int switch_case_2d(Color color, Directions number)
{
switch (magic_enum::enum_fuse(color, number))
{
case magic_enum::enum_fuse(Color::RED, Directions::Up):
return 1;
case magic_enum::enum_fuse(Color::BLUE, Directions::Down):
return 2;
default:
return 0;
}
}
enum class Index { zero = 0, one = 1, two = 2 };
static int switch_case_3d(Color color, Directions number, Index index)
{
switch (magic_enum::enum_fuse(color, number, index))
{
case magic_enum::enum_fuse(Color::RED, Directions::Up, Index::zero):
return 1;
// model accidental removal of last index, must not match anything
case magic_enum::enum_fuse(Color::BLUE, Directions::Up):
return 2;
default:
return 0;
}
}
TEST_CASE("multdimensional-switch-case") {
REQUIRE(switch_case_2d(Color::RED, Directions::Up) == 1);
REQUIRE(switch_case_2d(Color::RED, Directions::Down) == 0);
REQUIRE(switch_case_2d(Color::BLUE, Directions::Up) == 0);
REQUIRE(switch_case_2d(Color::BLUE, Directions::Down) == 2);
REQUIRE(switch_case_3d(Color::RED, Directions::Up, Index::zero) == 1);
REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::zero) == 0);
REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::one) == 0);
REQUIRE(switch_case_3d(Color::BLUE, Directions::Up, Index::two) == 0);
}
#endif