mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-09 23:34:23 +00:00
parent
596f00c0db
commit
8bd403f888
10 changed files with 502 additions and 298 deletions
|
|
@ -6,7 +6,7 @@ package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "magic_enum",
|
name = "magic_enum",
|
||||||
hdrs = ["include/magic_enum.hpp", "include/magic_enum_fuse.hpp"],
|
hdrs = ["include/magic_enum.hpp", "include/magic_enum_format.hpp", "include/magic_enum_fuse.hpp", "include/magic_enum_switch.hpp"],
|
||||||
includes = ["include"],
|
includes = ["include"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,6 @@ Header-only C++17 library provides static reflection for enums, work with any en
|
||||||
* Enum switch runtime value as constexpr constant
|
* Enum switch runtime value as constexpr constant
|
||||||
```cpp
|
```cpp
|
||||||
Color color = Color::RED;
|
Color color = Color::RED;
|
||||||
|
|
||||||
magic_enum::enum_switch([] (auto val) {
|
magic_enum::enum_switch([] (auto val) {
|
||||||
constexpr Color c_color = val;
|
constexpr Color c_color = val;
|
||||||
// ...
|
// ...
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
* [`enum_count` returns number of enum values.](#enum_count)
|
* [`enum_count` returns number of enum values.](#enum_count)
|
||||||
* [`enum_integer` obtains integer value from enum value.](#enum_integer)
|
* [`enum_integer` obtains integer value from enum value.](#enum_integer)
|
||||||
* [`enum_name` returns name from enum value.](#enum_name)
|
* [`enum_name` returns name from enum value.](#enum_name)
|
||||||
* [`enum_flags_name` returns name from enum-flags value.](#enum_flags_name)
|
|
||||||
* [`enum_names` obtains string enum name sequence.](#enum_names)
|
* [`enum_names` obtains string enum name sequence.](#enum_names)
|
||||||
* [`enum_entries` obtains pair (value enum, string enum name) sequence.](#enum_entries)
|
* [`enum_entries` obtains pair (value enum, string enum name) sequence.](#enum_entries)
|
||||||
* [`enum_index` obtains index in enum value sequence from enum value.](#enum_index)
|
* [`enum_index` obtains index in enum value sequence from enum value.](#enum_index)
|
||||||
|
|
@ -15,6 +14,7 @@
|
||||||
* [`enum_fuse` returns a bijective mix of enum values.](#enum_fuse)
|
* [`enum_fuse` returns a bijective mix of enum values.](#enum_fuse)
|
||||||
* [`enum_switch` allows runtime enum value transformation to constexpr context.](#enum_switch)
|
* [`enum_switch` allows runtime enum value transformation to constexpr context.](#enum_switch)
|
||||||
* [`enum_for_each` calls a function with all enum constexpr value.](#enum_for_each)
|
* [`enum_for_each` calls a function with all enum constexpr value.](#enum_for_each)
|
||||||
|
* [`enum_flags` API from enum-flags.](#enum_flags)
|
||||||
* [`is_unscoped_enum` checks whether type is an Unscoped enumeration.](#is_unscoped_enum)
|
* [`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)
|
* [`is_scoped_enum` checks whether type is an Scoped enumeration.](#is_scoped_enum)
|
||||||
* [`underlying_type` improved UB-free "SFINAE-friendly" underlying_type.](#underlying_type)
|
* [`underlying_type` improved UB-free "SFINAE-friendly" underlying_type.](#underlying_type)
|
||||||
|
|
@ -219,25 +219,6 @@ constexpr string_view enum_name() noexcept;
|
||||||
// color_name -> "BLUE"
|
// color_name -> "BLUE"
|
||||||
```
|
```
|
||||||
|
|
||||||
## `enum_flags_name`
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
template <typename E>
|
|
||||||
string enum_flags_name(E value);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Returns name from enum-flags value as `string` with null-terminated string.
|
|
||||||
|
|
||||||
* If enum-flags value does not have name or [out of range](limitations.md), returns empty string.
|
|
||||||
|
|
||||||
* Examples
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
auto directions_name = magic_enum::enum_flags_name(Directions::Up | Directions::Right);
|
|
||||||
// directions_name -> "Directions::Up | Directions::Right"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## `enum_names`
|
## `enum_names`
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|
@ -383,20 +364,21 @@ constexpr Result enum_switch(Lambda&& lambda, E value);
|
||||||
|
|
||||||
template <typename Result, typename E, typename Lambda>
|
template <typename Result, typename E, typename Lambda>
|
||||||
constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result);
|
constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result);
|
||||||
|
|
||||||
template <typename E, typename Result = void, typename BinaryPredicate = std::equal_to<>, typename Lambda>
|
|
||||||
constexpr Result enum_switch(Lambda&& lambda, string_view name, BinaryPredicate&& p = {});
|
|
||||||
|
|
||||||
template <typename E, typename Result, typename BinaryPredicate = std::equal_to<>, typename Lambda>
|
|
||||||
constexpr Result enum_switch(Lambda&& lambda, string_view name, Result&& result, BinaryPredicate&& p = {});
|
|
||||||
|
|
||||||
template <typename E, typename Result = void, typename Lambda>
|
|
||||||
constexpr Result enum_switch(Lambda&& lambda, underlying_type_t<E> value);
|
|
||||||
|
|
||||||
template <typename E, typename Result, typename Lambda>
|
|
||||||
constexpr Result enum_switch(Lambda&& lambda, underlying_type_t<E> value, Result&& result);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* You should add the required file `<magic_enum_switch.hpp>`.
|
||||||
|
|
||||||
|
* Examples
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Color color = Color::RED;
|
||||||
|
|
||||||
|
magic_enum::enum_switch([] (auto val) {
|
||||||
|
constexpr Color c_color = val;
|
||||||
|
// ...
|
||||||
|
}, color);
|
||||||
|
```
|
||||||
|
|
||||||
## `enum_for_each`
|
## `enum_for_each`
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|
@ -404,6 +386,51 @@ template <typename E, typename Lambda>
|
||||||
constexpr auto enum_for_each(Lambda&& lambda);
|
constexpr auto enum_for_each(Lambda&& lambda);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Examples
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
magic_enum::enum_for_each<Color>([] (auto val) {
|
||||||
|
constexpr Color c_color = val;
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## `enum_flags`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename E>
|
||||||
|
string enum_flags_name(E value);
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr optional<E> enum_flags_cast(underlying_type_t<E> value) noexcept;
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr optional<E> enum_flags_cast(string_view value) noexcept;
|
||||||
|
|
||||||
|
template <typename E, typename BinaryPredicate>
|
||||||
|
constexpr optional<E> enum_flags_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr bool enum_flags_contains(E value) noexcept;
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr bool enum_flags_contains(underlying_type_t<E> value) noexcept;
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
constexpr bool enum_flags_contains(string_view value) noexcept;
|
||||||
|
|
||||||
|
template <typename E, typename BinaryPredicate>
|
||||||
|
constexpr optional<E> enum_flags_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Examples
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto directions_name = magic_enum::enum_flags_name(Directions::Up | Directions::Right);
|
||||||
|
// directions_name -> "Directions::Up | Directions::Right"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## `is_unscoped_enum`
|
## `is_unscoped_enum`
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@
|
||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#define MAGIC_ENUM_ENABLE_HASH
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum_switch.hpp>
|
||||||
|
|
||||||
enum class Color { RED, BLUE, GREEN };
|
enum class Color { RED, BLUE, GREEN };
|
||||||
|
|
||||||
|
|
@ -64,9 +64,9 @@ int main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
magic_enum::enum_switch<Color>(switcher1, 2 /* GREEN */); // prints nothing
|
magic_enum::enum_switch(switcher1, Color::GREEN); // prints nothing
|
||||||
magic_enum::enum_switch<Color>(switcher1, 1 /* BLUE */); // prints "Blue"
|
magic_enum::enum_switch(switcher1, Color::BLUE); // prints "Blue"
|
||||||
magic_enum::enum_switch<Color>(switcher1, 0 /* RED */); // prints "Red"
|
magic_enum::enum_switch(switcher1, Color::RED); // prints "Red"
|
||||||
|
|
||||||
// explicit result type
|
// explicit result type
|
||||||
auto switcher2 = overloaded{
|
auto switcher2 = overloaded{
|
||||||
|
|
@ -86,23 +86,18 @@ int main() {
|
||||||
assert(empty.empty());
|
assert(empty.empty());
|
||||||
|
|
||||||
// result with default object
|
// result with default object
|
||||||
std::cout << magic_enum::enum_switch<Color, std::string>(switcher2, -3, "unrecognized") << std::endl; // prints "unrecognized"
|
std::cout << magic_enum::enum_switch<std::string>(switcher2, static_cast<Color>(-3), "unrecognized") << std::endl; // prints "unrecognized"
|
||||||
|
|
||||||
auto switcher3 = overloaded{
|
auto switcher3 = overloaded{
|
||||||
[] (magic_enum::enum_constant<Color::RED>) {
|
[] (magic_enum::enum_constant<Color::RED>) -> std::optional<std::string> {
|
||||||
return "red result";
|
return "red result";
|
||||||
},
|
},
|
||||||
[] (magic_enum::enum_constant<Color::BLUE>) {
|
[] (magic_enum::enum_constant<Color::BLUE>) -> std::optional<std::string> {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::cout << std::boolalpha;
|
std::cout << std::boolalpha;
|
||||||
std::cout << magic_enum::enum_switch<Color>(switcher3, "GREEN", std::make_optional("cica")).value() << std::endl; // prints default: "cica"
|
|
||||||
std::cout << magic_enum::enum_switch<Color>(switcher3, "RED", std::make_optional("cica")).value() << std::endl; // prints: "red result"
|
|
||||||
std::cout << magic_enum::enum_switch<Color>(switcher3, "BLUE", std::make_optional("cica")).has_value() << std::endl; // prints: false
|
|
||||||
std::cout << magic_enum::enum_switch<Color>(switcher3, "red", std::make_optional("cica"), magic_enum::case_insensitive).value() << std::endl; // prints: "red result"
|
|
||||||
|
|
||||||
std::cout << magic_enum::enum_switch(switcher3, Color::GREEN, std::make_optional("cica")).value() << std::endl; // prints default: "cica"
|
std::cout << magic_enum::enum_switch(switcher3, Color::GREEN, std::make_optional("cica")).value() << std::endl; // prints default: "cica"
|
||||||
std::cout << magic_enum::enum_switch(switcher3, Color::RED, std::make_optional("cica")).value() << std::endl; // prints: "red result"
|
std::cout << magic_enum::enum_switch(switcher3, Color::RED, std::make_optional("cica")).value() << std::endl; // prints: "red result"
|
||||||
std::cout << magic_enum::enum_switch(switcher3, Color::BLUE, std::make_optional("cica")).has_value() << std::endl; // prints: false
|
std::cout << magic_enum::enum_switch(switcher3, Color::BLUE, std::make_optional("cica")).has_value() << std::endl; // prints: false
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,11 @@ namespace detail {
|
||||||
template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
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>;
|
using enum_constant = std::integral_constant<E, V>;
|
||||||
|
|
||||||
|
enum class value_type {
|
||||||
|
default_value,
|
||||||
|
flags_value
|
||||||
|
};
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
inline constexpr bool always_false_v = false;
|
inline constexpr bool always_false_v = false;
|
||||||
|
|
||||||
|
|
@ -695,8 +700,14 @@ struct enable_if_enum<true, R> {
|
||||||
static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
|
static_assert(supported<R>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>>
|
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
|
||||||
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;
|
using enable_if_t = typename enable_if_enum<std::is_enum_v<D> && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;
|
||||||
|
|
||||||
|
template <typename T, typename R, value_type VT, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
|
||||||
|
using enable_if_default_t = typename enable_if_enum<std::is_enum_v<D> && VT == value_type::default_value && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;
|
||||||
|
|
||||||
|
template <typename T, typename R, value_type VT, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
|
||||||
|
using enable_if_flags_t = typename enable_if_enum<std::is_enum_v<D> && VT == value_type::flags_value && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
|
template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
|
||||||
using enum_concept = T;
|
using enum_concept = T;
|
||||||
|
|
@ -719,10 +730,7 @@ struct underlying_type {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
|
struct underlying_type<T, true> : std::underlying_type<std::decay_t<T>> {};
|
||||||
|
|
||||||
#if defined(MAGIC_ENUM_NO_HASH)
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
template <typename T>
|
|
||||||
inline constexpr bool has_hash = false;
|
|
||||||
#else
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr bool has_hash = true;
|
inline constexpr bool has_hash = true;
|
||||||
|
|
||||||
|
|
@ -846,7 +854,8 @@ constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class case_call_t {
|
enum class case_call_t {
|
||||||
index, value
|
index,
|
||||||
|
value
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T = void>
|
template <typename T = void>
|
||||||
|
|
@ -856,7 +865,7 @@ template <>
|
||||||
inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
|
inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
|
||||||
|
|
||||||
template <auto* Arr, typename Hash>
|
template <auto* Arr, typename Hash>
|
||||||
constexpr bool no_duplicate() noexcept {
|
constexpr bool has_duplicate() noexcept {
|
||||||
using value_t = std::decay_t<decltype((*Arr)[0])>;
|
using value_t = std::decay_t<decltype((*Arr)[0])>;
|
||||||
using hash_value_t = std::invoke_result_t<Hash, value_t>;
|
using hash_value_t = std::invoke_result_t<Hash, value_t>;
|
||||||
std::array<hash_value_t, Arr->size()> hashes{};
|
std::array<hash_value_t, Arr->size()> hashes{};
|
||||||
|
|
@ -887,41 +896,43 @@ constexpr bool no_duplicate() noexcept {
|
||||||
T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \
|
T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \
|
||||||
T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255)
|
T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255)
|
||||||
|
|
||||||
#define MAGIC_ENUM_CASE(val) \
|
#define MAGIC_ENUM_CASE(val) \
|
||||||
case cases[val]: \
|
case cases[val]: \
|
||||||
if constexpr ((val) + Page < size) { \
|
if constexpr ((val) + Page < size) { \
|
||||||
if (!pred(values[val + Page], searched)) { \
|
if (!pred(values[val + Page], searched)) { \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
if constexpr (CallValue == case_call_t::index) { \
|
if constexpr (CallValue == case_call_t::index) { \
|
||||||
if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
|
if constexpr (std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + Page>>) { \
|
||||||
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
|
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page>{}); \
|
||||||
} else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
|
} else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
|
||||||
assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \
|
assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \
|
||||||
} \
|
} \
|
||||||
} else if constexpr (CallValue == case_call_t::value) { \
|
} else if constexpr (CallValue == case_call_t::value) { \
|
||||||
if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
|
if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
|
||||||
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
|
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), enum_constant<values[val + Page]>{}); \
|
||||||
} else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
|
} else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
|
||||||
assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \
|
assert(false && "magic_enum::detail::constexpr_switch wrong result type."); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
break; \
|
break; \
|
||||||
} else [[fallthrough]];
|
} else [[fallthrough]];
|
||||||
|
|
||||||
template <auto* GlobValues,
|
template <auto* GlobValues,
|
||||||
case_call_t CallValue,
|
case_call_t CallValue,
|
||||||
std::size_t Page = 0,
|
std::size_t Page = 0,
|
||||||
typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,
|
typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,
|
||||||
typename Lambda, typename ResultGetterType = decltype(default_result_type_lambda<>),
|
typename BinaryPredicate = std::equal_to<>,
|
||||||
typename BinaryPredicate = std::equal_to<>>
|
typename Lambda,
|
||||||
|
typename ResultGetterType>
|
||||||
constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(
|
constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(
|
||||||
Lambda&& lambda,
|
Lambda&& lambda,
|
||||||
typename std::decay_t<decltype(*GlobValues)>::value_type searched,
|
typename std::decay_t<decltype(*GlobValues)>::value_type searched,
|
||||||
ResultGetterType&& def = default_result_type_lambda<>,
|
ResultGetterType&& def,
|
||||||
BinaryPredicate&& pred = {}) {
|
BinaryPredicate&& pred = {}) {
|
||||||
using result_t = std::invoke_result_t<ResultGetterType>;
|
using result_t = std::invoke_result_t<ResultGetterType>;
|
||||||
using hash_t = std::conditional_t<no_duplicate<GlobValues, Hash>(), Hash, typename Hash::secondary_hash>;
|
using hash_t = std::conditional_t<has_duplicate<GlobValues, Hash>(), Hash, typename Hash::secondary_hash>;
|
||||||
|
static_assert(has_duplicate<GlobValues, hash_t>(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues.");
|
||||||
constexpr std::array values = *GlobValues;
|
constexpr std::array values = *GlobValues;
|
||||||
constexpr std::size_t size = values.size();
|
constexpr std::size_t size = values.size();
|
||||||
constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
|
constexpr std::array cases = calculate_cases<GlobValues, hash_t>(Page);
|
||||||
|
|
@ -939,28 +950,36 @@ constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(
|
||||||
|
|
||||||
#undef MAGIC_ENUM_FOR_EACH_256
|
#undef MAGIC_ENUM_FOR_EACH_256
|
||||||
#undef MAGIC_ENUM_CASE
|
#undef MAGIC_ENUM_CASE
|
||||||
|
|
||||||
|
#else
|
||||||
|
template <typename T>
|
||||||
|
inline constexpr bool has_hash = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename E, typename Lambda, std::size_t... I>
|
template <typename E, typename F, std::size_t... I>
|
||||||
constexpr auto for_each(Lambda&& lambda, std::index_sequence<I...>) {
|
constexpr auto for_each(F&& f, std::index_sequence<I...>) {
|
||||||
static_assert(is_enum_v<E>, "magic_enum::detail::for_each requires enum type.");
|
static_assert(is_enum_v<E>, "magic_enum::detail::for_each requires enum type.");
|
||||||
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<Lambda, enum_constant<values_v<E>[I]>>> || ...);
|
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<F, enum_constant<values_v<E>[I]>>> || ...);
|
||||||
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<Lambda, enum_constant<values_v<E>[0]>>, std::invoke_result_t<Lambda, enum_constant<values_v<E>[I]>>> && ...);
|
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<F, enum_constant<values_v<E>[0]>>, std::invoke_result_t<F, enum_constant<values_v<E>[I]>>> && ...);
|
||||||
|
|
||||||
if constexpr (has_void_return) {
|
if constexpr (has_void_return) {
|
||||||
(lambda(enum_constant<values_v<E>[I]>{}), ...);
|
(f(enum_constant<values_v<E>[I]>{}), ...);
|
||||||
} else if constexpr (all_same_return) {
|
} else if constexpr (all_same_return) {
|
||||||
return std::array{lambda(enum_constant<values_v<E>[I]>{})...};
|
return std::array{f(enum_constant<values_v<E>[I]>{})...};
|
||||||
} else {
|
} else {
|
||||||
return std::tuple{lambda(enum_constant<values_v<E>[I]>{})...};
|
return std::tuple{f(enum_constant<values_v<E>[I]>{})...};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E, typename Lambda, std::size_t... I>
|
template <typename E, typename F, std::size_t... I>
|
||||||
constexpr bool all_invocable(std::index_sequence<I...>) {
|
constexpr bool all_invocable(std::index_sequence<I...>) {
|
||||||
static_assert(is_enum_v<E>, "magic_enum::detail::all_invocable requires enum type.");
|
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]>> && ...);
|
if constexpr (count_v<E> == 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return (std::is_invocable_v<F, enum_constant<values_v<E>[I]>> && ...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace magic_enum::detail
|
} // namespace magic_enum::detail
|
||||||
|
|
@ -1066,18 +1085,18 @@ template <typename E>
|
||||||
if constexpr (detail::count_v<D> == 0) {
|
if constexpr (detail::count_v<D> == 0) {
|
||||||
return {}; // Empty enum.
|
return {}; // Empty enum.
|
||||||
} else if constexpr (detail::is_sparse_v<D> || detail::is_flags_v<D>) {
|
} else if constexpr (detail::is_sparse_v<D> || detail::is_flags_v<D>) {
|
||||||
#if defined(MAGIC_ENUM_NO_HASH)
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
|
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>>);
|
||||||
|
#else
|
||||||
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 (enum_value<D>(i) == value) {
|
if (enum_value<D>(i) == value) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}; // Invalid value or out of range.
|
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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
const auto v = static_cast<U>(value);
|
const auto v = static_cast<U>(value);
|
||||||
|
|
@ -1109,8 +1128,8 @@ template <auto V>
|
||||||
|
|
||||||
// Returns name from enum value.
|
// Returns name from enum value.
|
||||||
// If enum value does not have name or value out of range, returns empty string.
|
// If enum value does not have name or value out of range, returns empty string.
|
||||||
template <typename E>
|
template <typename E, detail::value_type VT = detail::value_type::default_value>
|
||||||
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
|
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_default_t<E, string_view, VT> {
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
if (const auto i = enum_index<D>(value)) {
|
if (const auto i = enum_index<D>(value)) {
|
||||||
|
|
@ -1119,38 +1138,61 @@ template <typename E>
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns name from enum value.
|
||||||
|
// If enum value does not have name or value out of range, returns empty string.
|
||||||
|
template <detail::value_type VT, typename E>
|
||||||
|
[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_default_t<E, string_view, VT> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
return enum_name<D, VT>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns name from enum value.
|
||||||
|
// If enum value does not have name or value out of range, returns empty string.
|
||||||
|
template <typename E, detail::value_type VT>
|
||||||
|
[[nodiscard]] auto enum_name(E value) -> detail::enable_if_flags_t<E, string, VT> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
using U = underlying_type_t<D>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_name requires enum-flags type.");
|
||||||
|
|
||||||
|
string name;
|
||||||
|
auto check_value = U{0};
|
||||||
|
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
||||||
|
if (const auto v = static_cast<U>(enum_value<D>(i)); (static_cast<U>(value) & v) != 0) {
|
||||||
|
check_value |= v;
|
||||||
|
const auto n = detail::names_v<D>[i];
|
||||||
|
if (!name.empty()) {
|
||||||
|
name.append(1, '|');
|
||||||
|
}
|
||||||
|
name.append(n.data(), n.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_value != 0 && check_value == static_cast<U>(value)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}; // Invalid value or out of range.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns name from enum value.
|
||||||
|
// If enum value does not have name or value out of range, returns empty string.
|
||||||
|
template <detail::value_type VT, typename E>
|
||||||
|
[[nodiscard]] auto enum_name(E value) -> detail::enable_if_flags_t<E, string, VT> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_name requires enum-flags type.");
|
||||||
|
|
||||||
|
return enum_name<D, VT>(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns name from enum-flags value.
|
// Returns name from enum-flags value.
|
||||||
// If enum-flags value does not have name or value out of range, returns empty string.
|
// If enum-flags value does not have name or value out of range, returns empty string.
|
||||||
template <typename E>
|
template <typename E>
|
||||||
[[nodiscard]] auto enum_flags_name(E value) -> detail::enable_if_t<E, string> {
|
[[nodiscard]] auto enum_flags_name(E value) -> detail::enable_if_t<E, string> {
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = underlying_type_t<D>;
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_name requires enum-flags type.");
|
||||||
|
|
||||||
if constexpr (detail::is_flags_v<D>) {
|
return enum_name<D, detail::value_type::flags_value>(value);
|
||||||
string name;
|
|
||||||
auto check_value = U{0};
|
|
||||||
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
|
||||||
if (const auto v = static_cast<U>(enum_value<D>(i)); (static_cast<U>(value) & v) != 0) {
|
|
||||||
check_value |= v;
|
|
||||||
const auto n = detail::names_v<D>[i];
|
|
||||||
if (!name.empty()) {
|
|
||||||
name.append(1, '|');
|
|
||||||
}
|
|
||||||
name.append(n.data(), n.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check_value != 0 && check_value == static_cast<U>(value)) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {}; // Invalid value or out of range.
|
|
||||||
} else {
|
|
||||||
if (const auto name = enum_name<D>(value); !name.empty()) {
|
|
||||||
return {name.data(), name.size()};
|
|
||||||
}
|
|
||||||
return {}; // Invalid value or out of range.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns std::array with names, sorted by enum value.
|
// Returns std::array with names, sorted by enum value.
|
||||||
|
|
@ -1170,15 +1212,15 @@ inline constexpr auto case_insensitive = detail::case_insensitive{};
|
||||||
|
|
||||||
// Obtains enum value from integer value.
|
// Obtains enum value from integer value.
|
||||||
// Returns optional with enum value.
|
// Returns optional with enum value.
|
||||||
template <typename E>
|
template <typename E, detail::value_type VT = detail::value_type::default_value>
|
||||||
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = underlying_type_t<D>;
|
using U = underlying_type_t<D>;
|
||||||
|
|
||||||
if constexpr (detail::count_v<D> == 0) {
|
if constexpr (detail::count_v<D> == 0) {
|
||||||
return {}; // Empty enum.
|
return {}; // Empty enum.
|
||||||
} else if constexpr (detail::is_sparse_v<D>) {
|
} else if constexpr (VT == detail::value_type::flags_value && detail::is_flags_v<D>) {
|
||||||
if constexpr (detail::is_flags_v<D>) {
|
if constexpr (detail::is_sparse_v<D>) {
|
||||||
auto check_value = U{0};
|
auto check_value = U{0};
|
||||||
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 (const auto v = static_cast<U>(enum_value<D>(i)); (value & v) != 0) {
|
if (const auto v = static_cast<U>(enum_value<D>(i)); (value & v) != 0) {
|
||||||
|
|
@ -1191,42 +1233,51 @@ template <typename E>
|
||||||
}
|
}
|
||||||
return {}; // Invalid value or out of range.
|
return {}; // Invalid value or out of range.
|
||||||
} else {
|
} else {
|
||||||
#if defined(MAGIC_ENUM_NO_HASH)
|
constexpr auto min = detail::min_v<D>;
|
||||||
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
constexpr auto max = detail::values_ors<D>();
|
||||||
if (value == static_cast<U>(enum_value<D>(i))) {
|
|
||||||
return static_cast<D>(value);
|
if (value >= min && value <= max) {
|
||||||
}
|
return static_cast<D>(value);
|
||||||
}
|
}
|
||||||
return {}; // Invalid value or out of range.
|
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 {
|
} else {
|
||||||
constexpr auto min = detail::min_v<D>;
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
constexpr auto max = detail::is_flags_v<D> ? detail::values_ors<D>() : detail::max_v<D>;
|
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
|
||||||
|
[](D v) { return optional<D>{v}; },
|
||||||
if (value >= min && value <= max) {
|
static_cast<D>(value),
|
||||||
return static_cast<D>(value);
|
detail::default_result_type_lambda<optional<D>>);
|
||||||
|
#else
|
||||||
|
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.
|
return {}; // Invalid value or out of range.
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtains enum-flags value from integer value.
|
||||||
|
// Returns optional with enum-flags value.
|
||||||
|
template <typename E>
|
||||||
|
[[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_cast requires enum-flags type.");
|
||||||
|
|
||||||
|
return enum_cast<D, detail::value_type::flags_value>(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Obtains enum value from name.
|
// Obtains enum value from name.
|
||||||
// Returns optional with enum value.
|
// Returns optional with enum value.
|
||||||
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
template <typename E, detail::value_type VT = detail::value_type::default_value, typename BinaryPredicate = std::equal_to<>>
|
||||||
[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate&& p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
||||||
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");
|
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = underlying_type_t<D>;
|
using U = underlying_type_t<D>;
|
||||||
|
|
||||||
if constexpr (detail::count_v<D> == 0) {
|
if constexpr (detail::count_v<D> == 0) {
|
||||||
return {}; // Empty enum.
|
return {}; // Empty enum.
|
||||||
} else if constexpr (detail::is_flags_v<D>) {
|
} else if constexpr (VT == detail::value_type::flags_value && detail::is_flags_v<D>) {
|
||||||
auto result = U{0};
|
auto result = U{0};
|
||||||
while (!value.empty()) {
|
while (!value.empty()) {
|
||||||
const auto d = detail::find(value, '|');
|
const auto d = detail::find(value, '|');
|
||||||
|
|
@ -1249,21 +1300,14 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||||
return static_cast<D>(result);
|
return static_cast<D>(result);
|
||||||
}
|
}
|
||||||
return {}; // Invalid value or out of range.
|
return {}; // Invalid value or out of range.
|
||||||
} else if constexpr (detail::count_v<D> > 0) {
|
} else {
|
||||||
if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
|
if constexpr (detail::is_default_predicate<BinaryPredicate>() && detail::has_hash<D>) {
|
||||||
#if defined(MAGIC_ENUM_NO_HASH)
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
return detail::constexpr_switch<&detail::names_v<D>, detail::case_call_t::index>(
|
||||||
if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {
|
[](std::size_t i) { return optional<D>{detail::values_v<D>[i]}; },
|
||||||
return enum_value<D>(i);
|
value,
|
||||||
}
|
detail::default_result_type_lambda<optional<D>>,
|
||||||
}
|
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
|
||||||
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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
for (std::size_t i = 0; i < detail::count_v<D>; ++i) {
|
||||||
|
|
@ -1276,113 +1320,84 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether enum contains enumerator with such enum value.
|
// Obtains enum-flags value from name.
|
||||||
template <typename E>
|
// Returns optional with enum-flags value.
|
||||||
|
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||||
|
[[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_cast requires enum-flags type.");
|
||||||
|
|
||||||
|
return enum_cast<D, detail::value_type::flags_value>(value, std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether enum contains value with such value.
|
||||||
|
template <typename E, detail::value_type VT = detail::value_type::default_value>
|
||||||
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
|
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = underlying_type_t<D>;
|
using U = underlying_type_t<D>;
|
||||||
|
|
||||||
return static_cast<bool>(enum_cast<D>(static_cast<U>(value)));
|
return static_cast<bool>(enum_cast<D, VT>(static_cast<U>(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether enum contains enumerator with such integer value.
|
// Checks whether enum-flags contains value with such value.
|
||||||
template <typename E>
|
template <typename E>
|
||||||
|
[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_contains requires enum-flags type.");
|
||||||
|
|
||||||
|
return enum_contains<D, detail::value_type::flags_value>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether enum contains value with such integer value.
|
||||||
|
template <typename E, detail::value_type VT = detail::value_type::default_value>
|
||||||
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
|
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
return static_cast<bool>(enum_cast<D>(value));
|
return static_cast<bool>(enum_cast<D, VT>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether enum-flags contains value with such integer value.
|
||||||
|
template <typename E>
|
||||||
|
[[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_contains requires enum-flags type.");
|
||||||
|
|
||||||
|
return enum_contains<D, detail::value_type::flags_value>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether enum contains enumerator with such name.
|
// Checks whether enum contains enumerator with such name.
|
||||||
|
template <typename E, detail::value_type VT = detail::value_type::default_value, typename BinaryPredicate = std::equal_to<>>
|
||||||
|
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
return static_cast<bool>(enum_cast<D, VT>(value, std::move(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether enum-flags contains enumerator with such name.
|
||||||
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||||
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate&& p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
|
[[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
|
||||||
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");
|
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(detail::is_flags_v<D>, "magic_enum::enum_flags_contains requires enum-flags type.");
|
||||||
|
|
||||||
return static_cast<bool>(enum_cast<D>(value, std::forward<BinaryPredicate>(p)));
|
return enum_contains<D, detail::value_type::flags_value>(value, std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Result = void, typename E, typename Lambda>
|
template <typename E, typename F, detail::enable_if_t<E, int> = 0>
|
||||||
constexpr auto enum_switch(Lambda&& lambda, E value) -> detail::enable_if_t<E, Result> {
|
constexpr auto enum_for_each(F&& f) {
|
||||||
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),
|
|
||||||
value,
|
|
||||||
detail::default_result_type_lambda<Result>);
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
value,
|
|
||||||
[&result] { return std::forward<Result>(result); });
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename E, typename Result = void, typename BinaryPredicate = std::equal_to<>, typename Lambda>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return detail::default_result_type_lambda<Result>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename E, typename Result, typename BinaryPredicate = std::equal_to<>, typename Lambda>
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
return std::forward<Result>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return detail::default_result_type_lambda<Result>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
return std::forward<Result>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
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>;
|
using D = std::decay_t<E>;
|
||||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
|
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>>{};
|
constexpr auto sep = std::make_index_sequence<detail::count_v<D>>{};
|
||||||
|
|
||||||
if constexpr (detail::all_invocable<D, Lambda>(sep)) {
|
if constexpr (detail::all_invocable<D, F>(sep)) {
|
||||||
return detail::for_each<D>(std::forward<Lambda>(lambda), sep);
|
return detail::for_each<D>(std::forward<F>(f), sep);
|
||||||
} else {
|
} else {
|
||||||
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
|
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool AsFlags = true>
|
||||||
|
inline constexpr auto as_flags = AsFlags ? detail::value_type::flags_value : detail::value_type::default_value;
|
||||||
|
|
||||||
#if !defined(MAGIC_ENUM_NO_STREAMS)
|
#if !defined(MAGIC_ENUM_NO_STREAMS)
|
||||||
|
|
||||||
namespace ostream_operators {
|
namespace ostream_operators {
|
||||||
|
|
@ -1393,7 +1408,7 @@ std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& o
|
||||||
using U = underlying_type_t<D>;
|
using U = underlying_type_t<D>;
|
||||||
|
|
||||||
if constexpr (detail::supported<D>::value) {
|
if constexpr (detail::supported<D>::value) {
|
||||||
if (const auto name = enum_flags_name<D>(value); !name.empty()) {
|
if (const auto name = enum_name<D, as_flags<detail::is_flags_v<D>>>(value); !name.empty()) {
|
||||||
for (const auto c : name) {
|
for (const auto c : name) {
|
||||||
os.put(c);
|
os.put(c);
|
||||||
}
|
}
|
||||||
|
|
@ -1418,7 +1433,7 @@ std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& i
|
||||||
|
|
||||||
std::basic_string<Char, Traits> s;
|
std::basic_string<Char, Traits> s;
|
||||||
is >> s;
|
is >> s;
|
||||||
if (const auto v = enum_cast<D>(s)) {
|
if (const auto v = enum_cast<D, as_flags<detail::is_flags_v<D>>>(s)) {
|
||||||
value = *v;
|
value = *v;
|
||||||
} else {
|
} else {
|
||||||
is.setstate(std::basic_ios<Char>::failbit);
|
is.setstate(std::basic_ios<Char>::failbit);
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,6 @@
|
||||||
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
|
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
|
||||||
#endif // MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT
|
#endif // MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT
|
||||||
|
|
||||||
#if !defined(MAGIC_ENUM_NO_EXCEPTIONS) && (defined(__cpp_exceptions) || defined(_EXCEPTIONS) || defined(_HAS_EXCEPTIONS))
|
|
||||||
# define MAGIC_ENUM_THROW throw std::format_error
|
|
||||||
#else
|
|
||||||
# define MAGIC_ENUM_THROW std::terminate(); (void)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace magic_enum::customize {
|
namespace magic_enum::customize {
|
||||||
// customize enum to enable/disable automatic std::format
|
// customize enum to enable/disable automatic std::format
|
||||||
template <typename E>
|
template <typename E>
|
||||||
|
|
@ -62,18 +56,15 @@ namespace magic_enum::customize {
|
||||||
template <typename E>
|
template <typename E>
|
||||||
struct std::formatter<E, std::enable_if_t<std::is_enum_v<E> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {
|
struct std::formatter<E, std::enable_if_t<std::is_enum_v<E> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {
|
||||||
auto format(E e, format_context& ctx) {
|
auto format(E e, format_context& ctx) {
|
||||||
|
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
if constexpr (magic_enum::detail::is_flags_v<D>) {
|
|
||||||
if (auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
|
if constexpr (detail::supported<D>::value) {
|
||||||
return this->std::formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
if (const auto name = magic_enum::enum_name<D, magic_enum::as_flags<magic_enum::detail::is_flags_v<D>>>(e); !name.empty()) {
|
||||||
}
|
return std::formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||||
} else {
|
|
||||||
if (auto name = magic_enum::enum_name<D>(e); !name.empty()) {
|
|
||||||
return this->std::formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constexpr auto type_name = magic_enum::enum_type_name<E>();
|
return std::formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
|
||||||
MAGIC_ENUM_THROW("Type of " + std::string{type_name.data(), type_name.size()} + " enum value: " + std::to_string(magic_enum::enum_integer<D>(e)) + " is not exists.");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
139
include/magic_enum_switch.hpp
Normal file
139
include/magic_enum_switch.hpp
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
// __ __ _ ______ _____
|
||||||
|
// | \/ | (_) | ____| / ____|_ _
|
||||||
|
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||||
|
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||||
|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||||
|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||||
|
// __/ | https://github.com/Neargye/magic_enum
|
||||||
|
// |___/ version 0.8.1
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP
|
||||||
|
#define NEARGYE_MAGIC_ENUM_SWITCH_HPP
|
||||||
|
|
||||||
|
#include "magic_enum.hpp"
|
||||||
|
|
||||||
|
namespace magic_enum {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct default_result_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct identity {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nonesuch {};
|
||||||
|
|
||||||
|
template <typename F, typename V, bool = std::is_invocable_v<F, V>>
|
||||||
|
struct invoke_result : identity<nonesuch> {};
|
||||||
|
|
||||||
|
template <typename F, typename V>
|
||||||
|
struct invoke_result<F, V, true> : std::invoke_result<F, V> {};
|
||||||
|
|
||||||
|
template <typename F, typename V>
|
||||||
|
using invoke_result_t = typename invoke_result<F, V>::type;
|
||||||
|
|
||||||
|
template <typename E, typename F, std::size_t... I>
|
||||||
|
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
|
||||||
|
static_assert(is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
|
||||||
|
|
||||||
|
if constexpr (count_v<E> == 0) {
|
||||||
|
return identity<nonesuch>{};
|
||||||
|
} else {
|
||||||
|
return std::common_type<invoke_result_t<F, enum_constant<values_v<E>[I]>>...>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, typename Result, typename F>
|
||||||
|
constexpr auto result_type() noexcept {
|
||||||
|
static_assert(is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
|
||||||
|
|
||||||
|
constexpr auto seq = std::make_index_sequence<detail::count_v<E>>{};
|
||||||
|
using R = typename decltype(common_invocable<E, F>(seq))::type;
|
||||||
|
if constexpr (std::is_same_v<Result, default_result_type>) {
|
||||||
|
if constexpr (std::is_same_v<R, nonesuch>) {
|
||||||
|
return identity<void>{};
|
||||||
|
} else {
|
||||||
|
return identity<R>{};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if constexpr (std::is_convertible_v<R, Result>) {
|
||||||
|
return identity<Result>{};
|
||||||
|
} else if constexpr (std::is_convertible_v<Result, R>) {
|
||||||
|
return identity<R>{};
|
||||||
|
} else {
|
||||||
|
return identity<nonesuch>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Result, typename F, typename D = std::decay_t<T>, typename R = typename decltype(result_type<D, Result, F>())::type>
|
||||||
|
using result_t = std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
|
||||||
|
|
||||||
|
} // namespace magic_enum::detail
|
||||||
|
|
||||||
|
template <typename Result = detail::default_result_type, typename E, typename F, typename R = detail::result_t<E, Result, F>>
|
||||||
|
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||||
|
|
||||||
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
|
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
|
||||||
|
std::forward<F>(f),
|
||||||
|
value,
|
||||||
|
detail::default_result_type_lambda<R>);
|
||||||
|
#else
|
||||||
|
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires defined MAGIC_ENUM_ENABLE_HASH");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Result, typename E, typename F, typename R = detail::result_t<E, Result, F>>
|
||||||
|
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||||
|
|
||||||
|
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||||
|
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
|
||||||
|
std::forward<F>(f),
|
||||||
|
value,
|
||||||
|
[&result]() -> R { return std::forward<Result>(result); });
|
||||||
|
#else
|
||||||
|
static_assert(detail::has_hash<D>, "magic_enum::enum_switch requires defined MAGIC_ENUM_ENABLE_HASH");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace magic_enum
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct std::common_type<magic_enum::detail::nonesuch, magic_enum::detail::nonesuch> : magic_enum::detail::identity<magic_enum::detail::nonesuch> {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct std::common_type<T, magic_enum::detail::nonesuch> : magic_enum::detail::identity<T> {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct std::common_type<magic_enum::detail::nonesuch, T> : magic_enum::detail::identity<T> {};
|
||||||
|
|
||||||
|
#endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP
|
||||||
|
|
@ -545,14 +545,14 @@ TEST_CASE("enum_name") {
|
||||||
Color cb = Color::BLUE;
|
Color cb = Color::BLUE;
|
||||||
REQUIRE(cr_name == "red");
|
REQUIRE(cr_name == "red");
|
||||||
REQUIRE(enum_name<Color&>(cb) == "BLUE");
|
REQUIRE(enum_name<Color&>(cb) == "BLUE");
|
||||||
REQUIRE(enum_name(cm[1]) == "GREEN");
|
REQUIRE(enum_name<as_flags<false>>(cm[1]) == "GREEN");
|
||||||
REQUIRE(enum_name(static_cast<Color>(0)).empty());
|
REQUIRE(enum_name<detail::value_type::default_value>(static_cast<Color>(0)).empty());
|
||||||
|
|
||||||
constexpr Numbers no = Numbers::one;
|
constexpr Numbers no = Numbers::one;
|
||||||
constexpr auto no_name = enum_name(no);
|
constexpr auto no_name = enum_name(no);
|
||||||
REQUIRE(no_name == "one");
|
REQUIRE(no_name == "one");
|
||||||
REQUIRE(enum_name(Numbers::two) == "two");
|
REQUIRE(enum_name<Numbers, as_flags<false>>(Numbers::two) == "two");
|
||||||
REQUIRE(enum_name(Numbers::three) == "three");
|
REQUIRE(enum_name<as_flags<false>, Numbers>(Numbers::three) == "three");
|
||||||
REQUIRE(enum_name(Numbers::many).empty());
|
REQUIRE(enum_name(Numbers::many).empty());
|
||||||
REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
|
REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
|
||||||
|
|
||||||
|
|
@ -1083,22 +1083,6 @@ constexpr std::string_view DoWork<Color::GREEN>() {
|
||||||
return "override";
|
return "override";
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("enum_switch") {
|
|
||||||
constexpr auto bind_enum_switch = [] (Color c) {
|
|
||||||
|
|
||||||
return enum_switch([](auto val) {
|
|
||||||
return DoWork<val>();
|
|
||||||
}, c, string_view{"unrecognized"});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto def = bind_enum_switch(Color::BLUE);
|
|
||||||
REQUIRE(def == "default");
|
|
||||||
REQUIRE(bind_enum_switch(Color::RED) == "default");
|
|
||||||
REQUIRE(bind_enum_switch(Color::GREEN) == "override");
|
|
||||||
REQUIRE(bind_enum_switch(static_cast<Color>(0)) == "unrecognized");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("enum_for_each") {
|
TEST_CASE("enum_for_each") {
|
||||||
SECTION("no return type") {
|
SECTION("no return type") {
|
||||||
underlying_type_t<Color> sum{};
|
underlying_type_t<Color> sum{};
|
||||||
|
|
@ -1207,6 +1191,8 @@ TEST_CASE("multdimensional-switch-case") {
|
||||||
#include <magic_enum_format.hpp>
|
#include <magic_enum_format.hpp>
|
||||||
|
|
||||||
TEST_CASE("format-base") {
|
TEST_CASE("format-base") {
|
||||||
|
REQUIRE(std::format("{}", Color::RED) == "red");
|
||||||
|
REQUIRE(std::format("{}", Color{0}) == "0");
|
||||||
REQUIRE(std::format("Test-{:~^10}.", Color::RED) == "Test-~~~red~~~~.");
|
REQUIRE(std::format("Test-{:~^10}.", Color::RED) == "Test-~~~red~~~~.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ struct MyOpt {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MyString {
|
struct MyString {
|
||||||
|
using value_type = char; // required
|
||||||
|
static constexpr auto npos = std::string_view::npos; // required
|
||||||
|
|
||||||
MyString() : str{} {} // required
|
MyString() : str{} {} // required
|
||||||
MyString(const char* s, std::size_t l) : str{s, l} {} // required
|
MyString(const char* s, std::size_t l) : str{s, l} {} // required
|
||||||
bool empty() const { return str.empty(); } // required
|
bool empty() const { return str.empty(); } // required
|
||||||
|
|
|
||||||
|
|
@ -93,12 +93,20 @@ TEST_CASE("enum_cast") {
|
||||||
REQUIRE(cr.value() == Color::RED);
|
REQUIRE(cr.value() == Color::RED);
|
||||||
REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
|
REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
|
||||||
REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
||||||
REQUIRE(enum_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == (Color::BLUE | Color::RED));
|
REQUIRE_FALSE(enum_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).has_value());
|
||||||
REQUIRE(enum_cast<Color&>("GREEN|RED").value() == (Color::GREEN | Color::RED));
|
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED").has_value());
|
||||||
REQUIRE(enum_cast<Color&>("GREEN|RED|RED").value() == (Color::GREEN | Color::RED));
|
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|RED").has_value());
|
||||||
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|None").has_value());
|
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|None").has_value());
|
||||||
REQUIRE_FALSE(enum_cast<Color>("None").has_value());
|
REQUIRE_FALSE(enum_cast<Color>("None").has_value());
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_cast<Color&>("GREEN").value() == Color::GREEN);
|
||||||
|
REQUIRE(enum_flags_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
||||||
|
REQUIRE(enum_flags_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == (Color::BLUE | Color::RED));
|
||||||
|
REQUIRE(enum_flags_cast<Color&>("GREEN|RED").value() == (Color::GREEN | Color::RED));
|
||||||
|
REQUIRE(enum_flags_cast<Color&>("GREEN|RED|RED").value() == (Color::GREEN | Color::RED));
|
||||||
|
REQUIRE_FALSE(enum_flags_cast<Color&>("GREEN|RED|None").has_value());
|
||||||
|
REQUIRE_FALSE(enum_flags_cast<Color>("None").has_value());
|
||||||
|
|
||||||
constexpr auto no = enum_cast<Numbers>("one");
|
constexpr auto no = enum_cast<Numbers>("one");
|
||||||
REQUIRE(no.value() == Numbers::one);
|
REQUIRE(no.value() == Numbers::one);
|
||||||
REQUIRE(enum_cast<Numbers>("two").value() == Numbers::two);
|
REQUIRE(enum_cast<Numbers>("two").value() == Numbers::two);
|
||||||
|
|
@ -122,7 +130,7 @@ TEST_CASE("enum_cast") {
|
||||||
REQUIRE_FALSE(enum_cast<Language>("None").has_value());
|
REQUIRE_FALSE(enum_cast<Language>("None").has_value());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr auto nto = enum_cast<number>("three|one");
|
constexpr auto nto = enum_flags_cast<number>("three|one");
|
||||||
REQUIRE(enum_cast<number>("one").value() == number::one);
|
REQUIRE(enum_cast<number>("one").value() == number::one);
|
||||||
REQUIRE(enum_cast<number>("two").value() == number::two);
|
REQUIRE(enum_cast<number>("two").value() == number::two);
|
||||||
REQUIRE(enum_cast<number>("three").value() == number::three);
|
REQUIRE(enum_cast<number>("three").value() == number::three);
|
||||||
|
|
@ -137,11 +145,18 @@ TEST_CASE("enum_cast") {
|
||||||
REQUIRE(cr.value() == Color::RED);
|
REQUIRE(cr.value() == Color::RED);
|
||||||
REQUIRE(enum_cast<Color&>(2).value() == Color::GREEN);
|
REQUIRE(enum_cast<Color&>(2).value() == Color::GREEN);
|
||||||
REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
||||||
REQUIRE(enum_cast<Color>(1 | 2).value() == (Color::GREEN | Color::RED));
|
REQUIRE_FALSE(enum_cast<Color>(1 | 2).has_value());
|
||||||
REQUIRE(enum_cast<Color>(1 | 2 | 1).value() == (Color::GREEN | Color::RED));
|
REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 1).has_value());
|
||||||
REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 8).has_value());
|
REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 8).has_value());
|
||||||
REQUIRE_FALSE(enum_cast<Color>(0).has_value());
|
REQUIRE_FALSE(enum_cast<Color>(0).has_value());
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_cast<Color&>(2).value() == Color::GREEN);
|
||||||
|
REQUIRE(enum_flags_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
||||||
|
REQUIRE(enum_flags_cast<Color>(1 | 2).value() == (Color::GREEN | Color::RED));
|
||||||
|
REQUIRE(enum_flags_cast<Color>(1 | 2 | 1).value() == (Color::GREEN | Color::RED));
|
||||||
|
REQUIRE_FALSE(enum_flags_cast<Color>(1 | 2 | 8).has_value());
|
||||||
|
REQUIRE_FALSE(enum_flags_cast<Color>(0).has_value());
|
||||||
|
|
||||||
constexpr auto no = enum_cast<Numbers>(2);
|
constexpr auto no = enum_cast<Numbers>(2);
|
||||||
REQUIRE(no.value() == Numbers::one);
|
REQUIRE(no.value() == Numbers::one);
|
||||||
REQUIRE(enum_cast<Numbers>(4).value() == Numbers::two);
|
REQUIRE(enum_cast<Numbers>(4).value() == Numbers::two);
|
||||||
|
|
@ -166,7 +181,7 @@ TEST_CASE("enum_cast") {
|
||||||
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
|
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr auto nto = enum_cast<number>(2 | 8);
|
constexpr auto nto = enum_flags_cast<number>(2 | 8);
|
||||||
REQUIRE(enum_cast<number>(1 << 1).value() == number::one);
|
REQUIRE(enum_cast<number>(1 << 1).value() == number::one);
|
||||||
REQUIRE(enum_cast<number>(1 << 2).value() == number::two);
|
REQUIRE(enum_cast<number>(1 << 2).value() == number::two);
|
||||||
REQUIRE(enum_cast<number>(1 << 3).value() == number::three);
|
REQUIRE(enum_cast<number>(1 << 3).value() == number::three);
|
||||||
|
|
@ -230,11 +245,20 @@ TEST_CASE("enum_contains") {
|
||||||
REQUIRE(cr);
|
REQUIRE(cr);
|
||||||
REQUIRE(enum_contains<Color&>(cg));
|
REQUIRE(enum_contains<Color&>(cg));
|
||||||
REQUIRE(enum_contains(cm[2]));
|
REQUIRE(enum_contains(cm[2]));
|
||||||
REQUIRE(enum_contains<Color>(Color::RED | Color::GREEN));
|
REQUIRE(enum_contains<Color, as_flags<>>(Color::RED | Color::GREEN));
|
||||||
REQUIRE(enum_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
|
REQUIRE(enum_contains<Color, as_flags<true>>(Color::RED | Color::GREEN | Color::GREEN));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color::GREEN));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
|
||||||
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color{8}));
|
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color{8}));
|
||||||
REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
|
REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_contains<Color&>(cg));
|
||||||
|
REQUIRE(enum_flags_contains(cm[2]));
|
||||||
|
REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN));
|
||||||
|
REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains<Color>(Color::RED | Color{8}));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains(static_cast<Color>(0)));
|
||||||
|
|
||||||
constexpr auto no = enum_contains(Numbers::one);
|
constexpr auto no = enum_contains(Numbers::one);
|
||||||
REQUIRE(no);
|
REQUIRE(no);
|
||||||
REQUIRE(enum_contains(Numbers::two));
|
REQUIRE(enum_contains(Numbers::two));
|
||||||
|
|
@ -265,19 +289,31 @@ TEST_CASE("enum_contains") {
|
||||||
REQUIRE(enum_contains<number&>(number::two));
|
REQUIRE(enum_contains<number&>(number::two));
|
||||||
REQUIRE(enum_contains(number::one));
|
REQUIRE(enum_contains(number::one));
|
||||||
REQUIRE(enum_contains(number::four));
|
REQUIRE(enum_contains(number::four));
|
||||||
REQUIRE(nto);
|
REQUIRE_FALSE(nto);
|
||||||
REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
|
REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_contains(number::three | number::one));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("integer") {
|
SECTION("integer") {
|
||||||
REQUIRE(enum_contains<Color>(1));
|
REQUIRE(enum_contains<Color>(1));
|
||||||
REQUIRE(enum_contains<Color&>(2));
|
REQUIRE(enum_contains<Color&>(2));
|
||||||
REQUIRE(enum_contains<Color>(4));
|
REQUIRE(enum_contains<const Color>(4));
|
||||||
REQUIRE(enum_contains<Color>(1 | 2));
|
REQUIRE(enum_contains<Color, as_flags<>>(1 | 2));
|
||||||
REQUIRE(enum_contains<Color>(1 | 2 | 1));
|
REQUIRE(enum_contains<Color, as_flags<true>>(1 | 2 | 1));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color>(1 | 2));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color>(1 | 2 | 1));
|
||||||
REQUIRE_FALSE(enum_contains<Color>(1 | 2 | 8));
|
REQUIRE_FALSE(enum_contains<Color>(1 | 2 | 8));
|
||||||
REQUIRE_FALSE(enum_contains<Color>(0));
|
REQUIRE_FALSE(enum_contains<Color>(0));
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_contains<Color>(1));
|
||||||
|
REQUIRE(enum_flags_contains<Color&>(2));
|
||||||
|
REQUIRE(enum_flags_contains<Color>(4));
|
||||||
|
REQUIRE(enum_flags_contains<Color>(1 | 2));
|
||||||
|
REQUIRE(enum_flags_contains<Color>(1 | 2 | 1));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains<Color>(1 | 2 | 8));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains<Color>(0));
|
||||||
|
|
||||||
constexpr auto no = enum_contains<Numbers>(1 << 1);
|
constexpr auto no = enum_contains<Numbers>(1 << 1);
|
||||||
REQUIRE(no);
|
REQUIRE(no);
|
||||||
REQUIRE(enum_contains<Numbers>(1 << 2));
|
REQUIRE(enum_contains<Numbers>(1 << 2));
|
||||||
|
|
@ -305,9 +341,9 @@ TEST_CASE("enum_contains") {
|
||||||
REQUIRE(enum_contains<number>(1 << 2));
|
REQUIRE(enum_contains<number>(1 << 2));
|
||||||
REQUIRE(enum_contains<number>(1 << 3));
|
REQUIRE(enum_contains<number>(1 << 3));
|
||||||
REQUIRE(enum_contains<number>(1 << 4));
|
REQUIRE(enum_contains<number>(1 << 4));
|
||||||
REQUIRE(enum_contains<number>(8 | 2 | 16));
|
REQUIRE_FALSE(enum_contains<number>(8 | 2 | 16));
|
||||||
REQUIRE(enum_contains<number>(8 | 16 | 16));
|
REQUIRE_FALSE(enum_contains<number>(8 | 16 | 16));
|
||||||
REQUIRE(nto);
|
REQUIRE_FALSE(nto);
|
||||||
REQUIRE_FALSE(enum_contains<number>(8 | 64));
|
REQUIRE_FALSE(enum_contains<number>(8 | 64));
|
||||||
REQUIRE_FALSE(enum_contains<number>(0));
|
REQUIRE_FALSE(enum_contains<number>(0));
|
||||||
}
|
}
|
||||||
|
|
@ -316,13 +352,24 @@ TEST_CASE("enum_contains") {
|
||||||
constexpr auto cr = "RED";
|
constexpr auto cr = "RED";
|
||||||
REQUIRE(enum_contains<Color>(cr));
|
REQUIRE(enum_contains<Color>(cr));
|
||||||
REQUIRE(enum_contains<Color&>("GREEN"));
|
REQUIRE(enum_contains<Color&>("GREEN"));
|
||||||
REQUIRE(enum_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
REQUIRE(enum_contains<const Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||||
REQUIRE(enum_contains<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
REQUIRE(enum_contains<Color&, as_flags<>>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||||
REQUIRE(enum_contains<Color&>("GREEN|RED"));
|
REQUIRE(enum_contains<Color&, as_flags<true>>("GREEN|RED"));
|
||||||
REQUIRE(enum_contains<Color&>("GREEN|RED|RED"));
|
REQUIRE(enum_contains<Color, as_flags<true>>("GREEN|RED|RED"));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED"));
|
||||||
|
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED|RED"));
|
||||||
REQUIRE_FALSE(enum_contains<Color>("GREEN|RED|None"));
|
REQUIRE_FALSE(enum_contains<Color>("GREEN|RED|None"));
|
||||||
REQUIRE_FALSE(enum_contains<Color>("None"));
|
REQUIRE_FALSE(enum_contains<Color>("None"));
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_contains<Color&>("GREEN"));
|
||||||
|
REQUIRE(enum_flags_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||||
|
REQUIRE(enum_flags_contains<Color>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||||
|
REQUIRE(enum_flags_contains<Color>("GREEN|RED"));
|
||||||
|
REQUIRE(enum_flags_contains<Color>("GREEN|RED|RED"));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains<Color>("GREEN|RED|None"));
|
||||||
|
REQUIRE_FALSE(enum_flags_contains<Color>("None"));
|
||||||
|
|
||||||
constexpr auto no = std::string_view{"one"};
|
constexpr auto no = std::string_view{"one"};
|
||||||
REQUIRE(enum_contains<Numbers>(no));
|
REQUIRE(enum_contains<Numbers>(no));
|
||||||
REQUIRE(enum_contains<Numbers>("two"));
|
REQUIRE(enum_contains<Numbers>("two"));
|
||||||
|
|
@ -351,8 +398,10 @@ TEST_CASE("enum_contains") {
|
||||||
REQUIRE(enum_contains<number>("two"));
|
REQUIRE(enum_contains<number>("two"));
|
||||||
REQUIRE(enum_contains<number>("three"));
|
REQUIRE(enum_contains<number>("three"));
|
||||||
REQUIRE(enum_contains<number>("four"));
|
REQUIRE(enum_contains<number>("four"));
|
||||||
REQUIRE(nto);
|
REQUIRE_FALSE(nto);
|
||||||
REQUIRE_FALSE(enum_contains<number>("None"));
|
REQUIRE_FALSE(enum_contains<number>("None"));
|
||||||
|
|
||||||
|
REQUIRE(enum_flags_contains<number>("three|one"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue