1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-10 23:44:29 +00:00
This commit is contained in:
neargye 2020-07-05 13:18:29 +05:00
parent 81f2888125
commit 604054df5a
2 changed files with 99 additions and 57 deletions

View file

@ -88,7 +88,7 @@ template <typename E>
constexpr array<E, N> enum_values() noexcept; constexpr array<E, N> enum_values() noexcept;
``` ```
* Returns `std::array<E, N>` with all enum value where `N = number of enum values`, sorted by enum value. * Returns `std::array<E, N>` with all enum values where `N = number of enum values`, sorted by enum value.
* Examples * Examples
@ -141,7 +141,7 @@ template <auto V>
constexpr string_view enum_name() noexcept; constexpr string_view enum_name() noexcept;
``` ```
* Returns `std::string_view` with null-terminated string enum name from enum value. * Returns `std::string_view` with null-terminated string name from enum value.
* 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 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 `"Enum value does not have a name."`.
@ -172,7 +172,7 @@ template <typename E>
constexpr array<string_view, N> enum_names() noexcept; constexpr array<string_view, N> enum_names() noexcept;
``` ```
* Returns `std::array<std::string_view, N>` with all string enum name where `N = number of enum values`, sorted by enum value. * Returns `std::array<std::string_view, N>` with all string names where `N = number of enum values`, sorted by enum value.
* Examples * Examples
@ -189,7 +189,7 @@ template <typename E>
constexpr array<pair<E, string_view>, N> enum_entries() noexcept; constexpr array<pair<E, string_view>, N> enum_entries() noexcept;
``` ```
* Returns `std::array<std::pair<E, std::string_view>, N>` with all `std::pair` (value enum, string enum name) where `N = number of enum values`, sorted by enum value. * Returns `std::array<std::pair<E, std::string_view>, N>` with all pairs (enum value, string name) where `N = number of enum values`, sorted by enum value.
* Examples * Examples
@ -207,7 +207,7 @@ template <typename E>
constexpr optional<size_t> enum_index() noexcept; constexpr optional<size_t> enum_index() noexcept;
``` ```
* Obtains index in enum value sequence from enum value. * Obtains index in enum values from enum value.
* Returns `std::optional<std::size_t>` with index. * Returns `std::optional<std::size_t>` with index.

View file

@ -204,6 +204,31 @@ constexpr bool cmp_less(L lhs, R rhs) noexcept {
} }
} }
template <typename T>
constexpr std::uint8_t log2(T value) noexcept {
if constexpr (std::is_enum_v<T>) {
using U = std::underlying_type_t<T>;
return log2<U>(static_cast<U>(value));
} else {
auto ret = std::uint8_t{0};
for (; value > static_cast<T>(1U); value >>= static_cast<T>(1U), ++ret) {};
return ret;
}
}
template <typename T>
constexpr bool is_pow2(T x) noexcept {
if constexpr (std::is_enum_v<T>) {
using U = std::underlying_type_t<T>;
return is_pow2<U>(static_cast<U>(x));
} else {
return x != 0 && (x & (x - 1)) == 0;
}
}
#if defined(NEARGYE_NAMEOF_HPP) #if defined(NEARGYE_NAMEOF_HPP)
using ::nameof::detail::type_name_v; using ::nameof::detail::type_name_v;
#else #else
@ -294,12 +319,12 @@ inline constexpr auto reflected_min_v = reflected_min<E, IsFlags>();
template <typename E, bool IsFlags = false> template <typename E, bool IsFlags = false>
inline constexpr auto reflected_max_v = reflected_max<E, IsFlags>(); inline constexpr auto reflected_max_v = reflected_max<E, IsFlags>();
template <typename E, bool IsFlags, int O, typename U = std::underlying_type_t<E>> template <typename E, int O, bool IsFlags = false, typename U = std::underlying_type_t<E>>
constexpr auto value(std::size_t i) noexcept { constexpr auto value(std::size_t i) noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::value requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::value requires enum type.");
if constexpr (IsFlags) { if constexpr (IsFlags) {
return static_cast<E>(static_cast<U>(1) << static_cast<U>(i)); return static_cast<E>(static_cast<U>(1) << static_cast<U>(i + O));
} else { } else {
return static_cast<E>(static_cast<int>(i) + O); return static_cast<E>(static_cast<int>(i) + O);
} }
@ -308,13 +333,13 @@ constexpr auto value(std::size_t i) noexcept {
template <typename E, bool IsFlags, int Min, int... I> template <typename E, bool IsFlags, int Min, int... I>
constexpr auto values(std::integer_sequence<int, I...>) noexcept { constexpr auto values(std::integer_sequence<int, I...>) noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");
constexpr std::array<bool, sizeof...(I)> valid{{is_valid<E, value<E, IsFlags, Min>(I)>()...}}; constexpr std::array<bool, sizeof...(I)> valid{{is_valid<E, value<E, Min, IsFlags>(I)>()...}};
constexpr std::size_t count = ((valid[I] ? 1 : 0) + ...); constexpr std::size_t count = ((valid[I] ? 1 : 0) + ...);
std::array<E, count> values{}; std::array<E, count> values{};
for (std::size_t i = 0, v = 0; v < count; ++i) { for (std::size_t i = 0, v = 0; v < count; ++i) {
if (valid[i]) { if (valid[i]) {
values[v++] = value<E, IsFlags, Min>(i); values[v++] = value<E, Min, IsFlags>(i);
} }
} }
@ -376,7 +401,7 @@ inline constexpr auto invalid_index_v = (std::numeric_limits<index_t<E>>::max)()
template <typename E, int... I> template <typename E, int... I>
constexpr auto indexes(std::integer_sequence<int, I...>) noexcept { constexpr auto indexes(std::integer_sequence<int, I...>) noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::indexes requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::indexes requires enum type.");
[[maybe_unused]] index_t<E> i = 0; [[maybe_unused]] auto i = index_t<E>{0};
return std::array<index_t<E>, sizeof...(I)>{{(is_valid<E, I + min_v<E>>() ? i++ : invalid_index_v<E>)...}}; return std::array<index_t<E>, sizeof...(I)>{{(is_valid<E, I + min_v<E>>() ? i++ : invalid_index_v<E>)...}};
} }
@ -410,6 +435,20 @@ inline constexpr auto entries_v = entries<E, IsFlags>(std::make_index_sequence<c
template <typename E, bool IsFlags = false, typename D = std::decay_t<E>> template <typename E, bool IsFlags = false, typename D = std::decay_t<E>>
using entries_t = decltype((entries_v<D, IsFlags>)); using entries_t = decltype((entries_v<D, IsFlags>));
template <typename E, bool IsFlags, 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.");
if constexpr (IsFlags) {
auto range_count = std::size_t{0};
for (auto i = max_v<E, true>; i != max_v<E, true>; i <<= static_cast<U>(1), ++range_count) {};
return range_count != count_v<E, true>;
} else {
return range_size_v<E, false> != count_v<E, false>;
}
}
template <typename E, bool IsFlags = false> template <typename E, bool IsFlags = false>
inline constexpr bool is_sparse_v = range_size_v<E, IsFlags> != count_v<E, IsFlags>; inline constexpr bool is_sparse_v = range_size_v<E, IsFlags> != count_v<E, IsFlags>;
@ -453,7 +492,7 @@ struct enable_if_enum<true, true, T, R> {
using type = R; using type = R;
using D = std::decay_t<T>; using D = std::decay_t<T>;
static_assert(supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); static_assert(supported<D>::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
static_assert(count_v<D, true> > 0, "magic_enum::flag requires enum flag implementation."); static_assert(count_v<D, true> > 0, "magic_enum::flag requires enum-flags implementation.");
}; };
template <typename T, typename R = void> template <typename T, typename R = void>
@ -543,11 +582,10 @@ template <typename E>
if constexpr (detail::is_sparse_v<D>) { if constexpr (detail::is_sparse_v<D>) {
return assert(index < detail::count_v<D>), detail::values_v<D>[index]; return assert(index < detail::count_v<D>), detail::values_v<D>[index];
} else { } else {
return assert(index < detail::count_v<D>), detail::value<D, false, detail::min_v<D>>(index); return assert(index < detail::count_v<D>), detail::value<D, detail::min_v<D>>(index);
} }
} }
// Obtains value enum sequence.
// Returns std::array with enum values, sorted by enum value. // Returns std::array with enum values, sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, detail::values_t<E>> { [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t<E, detail::values_t<E>> {
@ -556,7 +594,7 @@ template <typename E>
return detail::values_v<D>; return detail::values_v<D>;
} }
// Returns string enum name from static storage enum variable. // Returns string name from static storage enum variable.
// This version is much lighter on the compile times and is not restricted to the enum_range limitation. // This version is much lighter on the compile times and is not restricted to the enum_range limitation.
template <auto V> template <auto V>
[[nodiscard]] constexpr std::string_view enum_name() noexcept { [[nodiscard]] constexpr std::string_view enum_name() noexcept {
@ -568,7 +606,7 @@ template <auto V>
return name; return name;
} }
// Returns string enum name from enum value. // Returns string 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>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, std::string_view> { [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, std::string_view> {
@ -581,8 +619,7 @@ template <typename E>
return {}; // Value out of range. return {}; // Value out of range.
} }
// Obtains string enum name sequence. // Returns std::array with string names, sorted by enum value.
// Returns std::array with string enum names, sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, detail::names_t<E>> { [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t<E, detail::names_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -590,8 +627,7 @@ template <typename E>
return detail::names_v<D>; return detail::names_v<D>;
} }
// Obtains pair (value enum, string enum name) sequence. // Returns std::array with pairs (enum value, string name), sorted by enum value.
// Returns std::array with std::pair (value enum, string enum name), sorted by enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, detail::entries_t<E>> { [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t<E, detail::entries_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -599,7 +635,7 @@ template <typename E>
return detail::entries_v<D>; return detail::entries_v<D>;
} }
// Obtains enum value from enum string name. // Obtains enum value from string name.
// Returns std::optional with enum value. // Returns std::optional with enum value.
template <typename E, typename BinaryPredicate> template <typename E, typename BinaryPredicate>
[[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> {
@ -615,6 +651,8 @@ template <typename E, typename BinaryPredicate>
return std::nullopt; // Invalid value or out of range. return std::nullopt; // Invalid value or out of range.
} }
// Obtains enum value from string name.
// Returns std::optional with enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::decay_t<E>>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -647,7 +685,7 @@ template <typename E>
return static_cast<underlying_type_t<E>>(value); return static_cast<underlying_type_t<E>>(value);
} }
// Obtains index in enum value sequence from enum value. // Obtains index in enum values from enum value.
// Returns std::optional with index. // Returns std::optional with index.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> { [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> {
@ -660,7 +698,7 @@ template <typename E>
return std::nullopt; // Value out of range. return std::nullopt; // Value out of range.
} }
// Checks whether enum contains enumerator with such value. // Checks whether enum contains enumerator with such enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -676,7 +714,7 @@ template <typename E>
return detail::undex<D>(value) != -1; return detail::undex<D>(value) != -1;
} }
// Checks whether enum contains enumerator with such string enum name. // Checks whether enum contains enumerator with such string name.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -751,7 +789,7 @@ constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E,
namespace flag { namespace flag {
// Returns number of enum flag values. // Returns number of enum-flags values.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_flags_t<E, std::size_t> { [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_flags_t<E, std::size_t> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -759,8 +797,8 @@ template <typename E>
return detail::count_v<D, true>; return detail::count_v<D, true>;
} }
// Returns enum flag value at specified index. // Returns enum-flags value at specified index.
// No bounds checking is performed: the behavior is undefined if index >= number of enum values. // No bounds checking is performed: the behavior is undefined if index >= number of enum-flags values.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_flags_t<E, std::decay_t<E>> { [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_flags_t<E, std::decay_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -768,12 +806,13 @@ template <typename E>
if constexpr (detail::is_sparse_v<D>) { if constexpr (detail::is_sparse_v<D>) {
return assert((index < detail::count_v<D, true>)), detail::values_v<D, true>[index]; return assert((index < detail::count_v<D, true>)), detail::values_v<D, true>[index];
} else { } else {
return assert((index < detail::count_v<D, true>)), detail::value<D, true, 0>(index); constexpr auto min = detail::log2(detail::min_v<D, true>) - 1;
return assert((index < detail::count_v<D, true>)), detail::value<D, min, true>(index);
} }
} }
// Obtains value enum flag sequence. // Returns std::array with enum-flags values, sorted by enum-flags value.
// Returns std::array with enum flag values, sorted by enum flag value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_flags_t<E, detail::values_t<E, true>> { [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_flags_t<E, detail::values_t<E, true>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -781,8 +820,8 @@ template <typename E>
return detail::values_v<D, true>; return detail::values_v<D, true>;
} }
// Returns string enum flag name from enum value. // Returns string name from enum-flags value.
// If enum 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_name(E value) -> detail::enable_if_enum_flags_t<E, std::string> { [[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_flags_t<E, std::string> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -802,8 +841,7 @@ template <typename E>
return name; return name;
} }
// Obtains string enum flag name sequence. // Returns std::array with string names, sorted by enum-flags value.
// Returns std::array with string enum flag names, sorted by enum flag value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_flags_t<E, detail::names_t<E, true>> { [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_flags_t<E, detail::names_t<E, true>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -811,8 +849,7 @@ template <typename E>
return detail::names_v<D, true>; return detail::names_v<D, true>;
} }
// Obtains pair (value enum flag, string enum flag name) sequence. // Returns std::array with pairs (enum-flags value, string name), sorted by enum-flags value.
// Returns std::array with std::pair (value enum flag, string enum flag name), sorted by enum flag value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_flags_t<E, detail::entries_t<E, true>> { [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_flags_t<E, detail::entries_t<E, true>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -822,18 +859,14 @@ template <typename E>
// TODO: enum_cast // TODO: enum_cast
// Obtains enum flag value from integer value. // Obtains enum-flags value from integer value.
// Returns std::optional with enum flag value. // Returns std::optional with enum-flags value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
using U = std::underlying_type_t<D>; using U = std::underlying_type_t<D>;
if (value < detail::min_v<D, true> || value > detail::max_v<D, true>) { auto check_value = U{0};
return std::nullopt; // Out of range.
}
U check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) { for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {
if (const auto v = enum_value<D>(i); (static_cast<U>(value) & static_cast<U>(v)) != 0) { if (const auto v = enum_value<D>(i); (static_cast<U>(value) & static_cast<U>(v)) != 0) {
check_value |= static_cast<U>(v); check_value |= static_cast<U>(v);
@ -844,11 +877,11 @@ template <typename E>
return static_cast<D>(value); return static_cast<D>(value);
} }
return std::nullopt; // Invalid value. return std::nullopt; // Invalid value or out of range.
} }
// Obtains enum flag value from enum flag string name. // Obtains enum-flags value from string name.
// Returns std::optional with enum flag value. // Returns std::optional with enum-flags value.
template <typename E, typename BinaryPredicate> template <typename E, typename BinaryPredicate>
[[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> {
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::flag::enum_cast requires bool(char, char) invocable predicate."); static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::flag::enum_cast requires bool(char, char) invocable predicate.");
@ -856,29 +889,38 @@ template <typename E, typename BinaryPredicate>
return {}; return {};
} }
// Obtains enum flag value from enum flag string name. // Obtains enum-flags value from string name.
// Returns std::optional with enum flag value. // Returns std::optional with enum-flags value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> { [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_flags_t<E, std::optional<std::decay_t<E>>> {
static_assert(sizeof(E) == 0, "not implemented"); static_assert(sizeof(E) == 0, "not implemented");
return {}; return {};
} }
// Returns integer value from enum flag value. // Returns integer value from enum-flags value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_flags_t<E, underlying_type_t<E>> { [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_flags_t<E, underlying_type_t<E>> {
return static_cast<underlying_type_t<E>>(value); return static_cast<underlying_type_t<E>>(value);
} }
// Obtains index in enum flag value sequence from enum flag value. // Obtains index in enum-flags values from enum-flags value.
// Returns std::optional with index. // Returns std::optional with index.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> { [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t<E, std::optional<std::size_t>> {
static_assert(sizeof(E) == 0, "not implemented"); using D = std::decay_t<E>;
return {};
if (detail::is_pow2<D>(value)) {
for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {
if (enum_value<D>(i) == value) {
return i;
}
}
}
return std::nullopt; // Value out of range.
} }
// Checks whether enum flag contains enumerator with such integer value. // Checks whether enum-flags contains enumerator with such integer value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_flags_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -886,7 +928,7 @@ template <typename E>
return enum_cast<D>(value).has_value(); return enum_cast<D>(value).has_value();
} }
// Checks whether enum flag contains enumerator with such value. // Checks whether enum-flags contains enumerator with such enum-flags value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
@ -895,7 +937,7 @@ template <typename E>
return enum_cast<D>(static_cast<U>(value)).has_value(); return enum_cast<D>(static_cast<U>(value)).has_value();
} }
// Checks whether enum flag contains enumerator with such string enum name. // Checks whether enum-flags contains enumerator with such string name.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t<E, bool> { [[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
static_assert(sizeof(E) == 0, "not implemented"); static_assert(sizeof(E) == 0, "not implemented");
@ -907,15 +949,15 @@ namespace ostream_operators {
// TODO: operator<< // TODO: operator<<
using namespace magic_enum::ostream_operators; using namespace magic_enum::ostream_operators;
} // namespace magic_enum::flag::ostream_operators } // namespace magic_enum::flags::ostream_operators
namespace bitwise_operators { namespace bitwise_operators {
using namespace magic_enum::bitwise_operators; using namespace magic_enum::bitwise_operators;
} // namespace magic_enum::flag::bitwise_operators } // namespace magic_enum::flags::bitwise_operators
} // namespace magic_enum::flag } // namespace magic_enum::flags
} // namespace magic_enum } // namespace magic_enum