1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-09 23:34:23 +00:00
This commit is contained in:
neargye 2020-07-05 15:12:05 +05:00
parent 604054df5a
commit 8e343c47b8
3 changed files with 150 additions and 102 deletions

View file

@ -24,16 +24,16 @@
#include <magic_enum.hpp> #include <magic_enum.hpp>
enum class AnimalFlags : std::uint64_t { HasClaws = 1 << 1, CanFly = 1 << 2, EatsFish = 1 << 20, Endangered = std::uint64_t{1} << 40 }; enum class AnimalFlags : std::uint64_t { HasClaws = 1 << 10, CanFly = 1 << 20, EatsFish = 1 << 30, Endangered = std::uint64_t{1} << 40 };
int main() { int main() {
// Enum variable to string name. // Enum variable to string name.
AnimalFlags f1 = AnimalFlags::CanFly; AnimalFlags f1 = AnimalFlags::Endangered;
auto f1_name = magic_enum::flag::enum_name(f1); auto f1_name = magic_enum::flags::enum_name(f1);
std::cout << f1_name << std::endl; // CanFly std::cout << f1_name << std::endl; // Endangered
// String enum name sequence. // String enum name sequence.
constexpr auto names = magic_enum::flag::enum_names<AnimalFlags>(); constexpr auto names = magic_enum::flags::enum_names<AnimalFlags>();
std::cout << "AnimalFlags names:"; std::cout << "AnimalFlags names:";
for (auto n : names) { for (auto n : names) {
std::cout << " " << n; std::cout << " " << n;
@ -43,38 +43,38 @@ int main() {
#if 0 #if 0
// String name to enum value. // String name to enum value.
auto f2 = magic_enum::flag::enum_cast<AnimalFlags>("EatsFish"); auto f2 = magic_enum::flags::enum_cast<AnimalFlags>("EatsFish|CanFly");
#else
auto f2 = magic_enum::flags::enum_cast<AnimalFlags>(1074790400);
#endif
if (f2.has_value() && f2.value() == AnimalFlags::EatsFish) { if (f2.has_value() && f2.value() == AnimalFlags::EatsFish) {
std::cout << "EatsFish = " << magic_enum::flag::enum_integer(f2.value()) << std::endl; // EatsFish = 4 std::cout << "EatsFish = " << magic_enum::flags::enum_integer(f2.value()) << std::endl; // CanFly|EatsFish = 1074790400
} }
// Integer value to enum value. // Integer value to enum value.
auto f3 = magic_enum::flag::enum_cast<AnimalFlags>(8); auto f3 = magic_enum::flags::enum_cast<AnimalFlags>(1073742848);
if (f3.has_value() && f3.value() == AnimalFlags::Endangered) { if (f3.has_value()) {
std::cout << "Endangered = " << magic_enum::flag::enum_integer(f3.value()) << std::endl; // Endangered = 8 std::cout << magic_enum::flags::enum_name(f3.value()) << " = " << magic_enum::flags::enum_integer(f3.value()) << std::endl; // HasClaws|EatsFish = 1073742848
} }
#endif
// Enum value to integer value. // Enum value to integer value.
auto f4_integer = magic_enum::flag::enum_integer(AnimalFlags::HasClaws); auto f4_integer = magic_enum::flags::enum_integer(AnimalFlags::HasClaws);
if (f4_integer == static_cast<std::underlying_type_t<AnimalFlags>>(AnimalFlags::HasClaws)) { if (f4_integer == static_cast<std::underlying_type_t<AnimalFlags>>(AnimalFlags::HasClaws)) {
std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 2 std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 1024
} }
using namespace magic_enum::flag::ostream_operators; // out-of-the-box ostream operator for all enums. using namespace magic_enum::flags::ostream_operators; // out-of-the-box ostream operator for all enums.
#if 0
// ostream operator for enum. // ostream operator for enum.
std::cout << f1 << " " << f2 << " " << f3 << std::endl; // CanFly EatsFish Endangered std::cout << f1 << " " << f2 << " " << f3 << std::endl; // Endangered CanFly|EatsFish HasClaws|EatsFish
#endif
// Number of enum values. // Number of enum values.
std::cout << "AnimalFlags enum size: " << magic_enum::flag::enum_count<AnimalFlags>() << std::endl; // AnimalFlags enum size: 4 std::cout << "AnimalFlags enum size: " << magic_enum::flags::enum_count<AnimalFlags>() << std::endl; // AnimalFlags enum size: 4
// Indexed access to enum value. // Indexed access to enum value.
std::cout << "AnimalFlags[0] = " << magic_enum::flag::enum_value<AnimalFlags>(0) << std::endl; // AnimalFlags[0] = HasClaws std::cout << "AnimalFlags[0] = " << magic_enum::flags::enum_value<AnimalFlags>(0) << std::endl; // AnimalFlags[0] = HasClaws
// Enum value sequence. // Enum value sequence.
constexpr auto values = magic_enum::flag::enum_values<AnimalFlags>(); constexpr auto values = magic_enum::flags::enum_values<AnimalFlags>();
std::cout << "AnimalFlags values:"; std::cout << "AnimalFlags values:";
for (AnimalFlags f : values) { for (AnimalFlags f : values) {
std::cout << " " << f; // ostream operator for enum. std::cout << " " << f; // ostream operator for enum.
@ -82,19 +82,19 @@ int main() {
std::cout << std::endl; std::cout << std::endl;
// AnimalFlags sequence: HasClaws CanFly EatsFish Endangered // AnimalFlags sequence: HasClaws CanFly EatsFish Endangered
using namespace magic_enum::flag::bitwise_operators; // out-of-the-box bitwise operators for all enums. using namespace magic_enum::flags::bitwise_operators; // out-of-the-box bitwise operators for all enums.
// Support operators: ~, |, &, ^, |=, &=, ^=. // Support operators: ~, |, &, ^, |=, &=, ^=.
AnimalFlags flag = AnimalFlags::HasClaws | AnimalFlags::CanFly; AnimalFlags flag = AnimalFlags::HasClaws | AnimalFlags::CanFly;
std::cout << flag << std::endl; // HasClaws | CanFly std::cout << flag << std::endl; // HasClaws|CanFly
// Enum pair (value enum, string enum name) sequence. // Enum pair (value enum, string enum name) sequence.
constexpr auto entries = magic_enum::flag::enum_entries<AnimalFlags>(); constexpr auto entries = magic_enum::flags::enum_entries<AnimalFlags>();
std::cout << "AnimalFlags entries:"; std::cout << "AnimalFlags entries:";
for (auto e : entries) { for (auto e : entries) {
std::cout << " " << e.second << " = " << magic_enum::flag::enum_integer(e.first); std::cout << " " << e.second << " = " << magic_enum::flags::enum_integer(e.first);
} }
std::cout << std::endl; std::cout << std::endl;
// AnimalFlags entries: AnimalFlags entries: HasClaws = 2 CanFly = 4 EatsFish = 1048576 Endangered = 1099511627776 // AnimalFlags entries: AnimalFlags entries: HasClaws = 1024 CanFly = 1048576 EatsFish = 1073741824 Endangered = 1099511627776
return 0; return 0;
} }

View file

@ -70,7 +70,7 @@ int main() {
std::cout << "Color: " << c1 << " " << c2 << " " << c3 << std::endl; // Color: RED BLUE GREEN std::cout << "Color: " << c1 << " " << c2 << " " << c3 << std::endl; // Color: RED BLUE GREEN
// Number of enum values. // Number of enum values.
std::cout << "Color enum size: " << magic_enum::enum_count<Color>() << std::endl; // Color enum size: 3 std::cout << "Color enum size: " << magic_enum::enum_count<Color>() << std::endl; // Color size: 3
// Indexed access to enum value. // Indexed access to enum value.
std::cout << "Color[0] = " << magic_enum::enum_value<Color>(0) << std::endl; // Color[0] = RED std::cout << "Color[0] = " << magic_enum::enum_value<Color>(0) << std::endl; // Color[0] = RED
@ -88,7 +88,7 @@ int main() {
using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums. using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums.
// Support operators: ~, |, &, ^, |=, &=, ^=. // Support operators: ~, |, &, ^, |=, &=, ^=.
Flags flag = Flags::A | Flags::C; Flags flag = Flags::A | Flags::C;
std::cout << flag << std::endl; std::cout << flag << std::endl; // 5
enum color { red, green, blue }; enum color { red, green, blue };

View file

@ -282,7 +282,7 @@ constexpr bool is_valid() noexcept {
} }
template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>> template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>
constexpr auto reflected_min() noexcept { constexpr int reflected_min() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::reflected_min requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::reflected_min requires enum type.");
if constexpr (IsFlags) { if constexpr (IsFlags) {
@ -298,7 +298,7 @@ constexpr auto reflected_min() noexcept {
} }
template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>> template <typename E, bool IsFlags, typename U = std::underlying_type_t<E>>
constexpr auto reflected_max() noexcept { constexpr int reflected_max() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::reflected_max requires enum type."); static_assert(is_enum_v<E>, "magic_enum::detail::reflected_max requires enum type.");
if constexpr (IsFlags) { if constexpr (IsFlags) {
@ -450,7 +450,7 @@ constexpr bool is_sparse() noexcept {
} }
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 = is_sparse<E, IsFlags>();
template <typename E, typename U = std::underlying_type_t<E>> template <typename E, typename U = std::underlying_type_t<E>>
constexpr int undex(U value) noexcept { constexpr int undex(U value) noexcept {
@ -476,6 +476,18 @@ constexpr int endex(E value) noexcept {
return undex<E>(static_cast<U>(value)); return undex<E>(static_cast<U>(value));
} }
template <typename E, typename U = std::underlying_type_t<E>>
constexpr U value_ors() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::endex requires enum type.");
auto value = U{0};
for (std::size_t i = 0; i < count_v<E, true>; ++i) {
value |= static_cast<U>(values_v<E, true>[i]);
}
return value;
}
template <bool, bool, typename T, typename R> template <bool, bool, typename T, typename R>
struct enable_if_enum {}; struct enable_if_enum {};
@ -492,13 +504,13 @@ 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-flags implementation."); static_assert(count_v<D, true> > 0, "magic_enum::flags requires enum-flags implementation.");
}; };
template <typename T, typename R = void> template <typename T, typename R = void>
using enable_if_enum_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, false, T, R>::type; using enable_if_enum_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, false, T, R>::type;
template <typename T, typename R> template <typename T, typename R = void>
using enable_if_enum_flags_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, true, T, R>::type; using enable_if_enum_flags_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, true, T, R>::type;
template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>> template <typename T, typename Enable = std::enable_if_t<std::is_enum_v<std::decay_t<T>>>>
@ -578,11 +590,12 @@ template <typename E>
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> { [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t<E, std::decay_t<E>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
constexpr auto count = detail::count_v<D>;
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 < count), detail::values_v<D>[index];
} else { } else {
return assert(index < detail::count_v<D>), detail::value<D, detail::min_v<D>>(index); return assert(index < count), detail::value<D, detail::min_v<D>>(index);
} }
} }
@ -681,7 +694,7 @@ template <typename E>
// Returns integer value from enum value. // Returns integer value from enum value.
template <typename E> template <typename E>
[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t<E, underlying_type_t<E>> { [[nodiscard]] constexpr underlying_type_t<E> enum_integer(E value) noexcept {
return static_cast<underlying_type_t<E>>(value); return static_cast<underlying_type_t<E>>(value);
} }
@ -724,21 +737,26 @@ template <typename E>
namespace ostream_operators { namespace ostream_operators {
template <typename Char, typename Traits, typename E> template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_t<E>>
auto operator<<(std::basic_ostream<Char, Traits>& os, E value) -> detail::enable_if_enum_t<E, std::basic_ostream<Char, Traits>&> { auto& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
if (const auto name = enum_name(value); !name.empty()) { using namespace magic_enum;
using D = std::decay_t<E>;
if (const auto name = enum_name<D>(value); !name.empty()) {
for (const auto c : name) { for (const auto c : name) {
os.put(c); os.put(c);
} }
} else { } else {
os << enum_integer(value); os << enum_integer<D>(value);
} }
return os; return os;
} }
template <typename Char, typename Traits, typename E> template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_t<E>>
auto operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) -> detail::enable_if_enum_t<E, std::basic_ostream<Char, Traits>&> { auto& operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) {
using namespace magic_enum;
if (value.has_value()) { if (value.has_value()) {
os << value.value(); os << value.value();
} }
@ -750,44 +768,44 @@ auto operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) ->
namespace bitwise_operators { namespace bitwise_operators {
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator~(E rhs) noexcept -> detail::enable_if_enum_t<E, E> { constexpr E operator~(E rhs) noexcept {
return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs)); return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator|(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> { constexpr E operator|(E lhs, E rhs) noexcept {
return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs)); return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator&(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> { constexpr E operator&(E lhs, E rhs) noexcept {
return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs)); return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator^(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> { constexpr E operator^(E lhs, E rhs) noexcept {
return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs)); return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator|=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> { constexpr E& operator|=(E& lhs, E rhs) noexcept {
return lhs = lhs | rhs; return lhs = lhs | rhs;
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator&=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> { constexpr E& operator&=(E& lhs, E rhs) noexcept {
return lhs = lhs & rhs; return lhs = lhs & rhs;
} }
template <typename E> template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> { constexpr E& operator^=(E& lhs, E rhs) noexcept {
return lhs = lhs ^ rhs; return lhs = lhs ^ rhs;
} }
} // namespace magic_enum::bitwise_operators } // namespace magic_enum::bitwise_operators
namespace flag { namespace flags {
// Returns number of enum-flags values. // Returns number of enum-flags values.
template <typename E> template <typename E>
@ -802,13 +820,14 @@ template <typename E>
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>;
constexpr auto count = detail::count_v<D, true>;
if constexpr (detail::is_sparse_v<D>) { if constexpr (detail::is_sparse_v<D, true>) {
return assert((index < detail::count_v<D, true>)), detail::values_v<D, true>[index]; return assert(index < count), detail::values_v<D, true>[index];
} else { } else {
constexpr auto min = detail::log2(detail::min_v<D, true>) - 1; 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); return assert(index < count), detail::value<D, min, true>(index);
} }
} }
@ -857,23 +876,53 @@ template <typename E>
return detail::entries_v<D, true>; return detail::entries_v<D, true>;
} }
// TODO: enum_cast // Checks whether enum-flags contains enumerator with such integer value.
template <typename E>
[[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 U = std::underlying_type_t<D>;
if constexpr (detail::is_sparse_v<D, true>) {
constexpr auto min = detail::min_v<D, true>;
constexpr auto max = detail::value_ors<D>();
return value >= min && value <= max;
} else {
auto check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, true>; ++i) {
if (const auto v = static_cast<U>(enum_value<D>(i)); (static_cast<U>(value) & v) != 0) {
check_value |= v;
}
}
return check_value == value;
}
}
// Checks whether enum-flags contains enumerator with such enum-flags value.
template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
using D = std::decay_t<E>;
using U = std::underlying_type_t<D>;
return enum_contains<D>(static_cast<U>(value));
}
// Checks whether enum-flags contains enumerator with such string name.
template <typename E>
[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
// TODO: impl
static_assert(sizeof(E) == 0, "not implemented");
return {};
}
// Obtains enum-flags value from integer value. // Obtains enum-flags value from integer value.
// Returns std::optional with enum-flags 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>;
auto check_value = U{0}; if (enum_contains<D>(value)) {
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) {
check_value |= static_cast<U>(v);
}
}
if (check_value == value) {
return static_cast<D>(value); return static_cast<D>(value);
} }
@ -884,7 +933,8 @@ template <typename E>
// Returns std::optional with enum-flags 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::flags::enum_cast requires bool(char, char) invocable predicate.");
// TODO: impl
static_assert(sizeof(E) == 0, "not implemented"); static_assert(sizeof(E) == 0, "not implemented");
return {}; return {};
} }
@ -893,20 +943,15 @@ template <typename E, typename BinaryPredicate>
// Returns std::optional with enum-flags 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>>> {
// TODO: impl
static_assert(sizeof(E) == 0, "not implemented"); static_assert(sizeof(E) == 0, "not implemented");
return {}; return {};
} }
// Returns integer value from enum-flags value.
template <typename 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);
}
// Obtains index in enum-flags values from enum-flags 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_flags_t<E, std::optional<std::size_t>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
if (detail::is_pow2<D>(value)) { if (detail::is_pow2<D>(value)) {
@ -920,34 +965,37 @@ template <typename E>
return std::nullopt; // Value out of range. return std::nullopt; // Value out of range.
} }
// Checks whether enum-flags contains enumerator with such integer value. using magic_enum::enum_type_name; // TODO: impl
template <typename E> using magic_enum::enum_integer; // TODO: impl
[[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>;
return enum_cast<D>(value).has_value();
}
// Checks whether enum-flags contains enumerator with such enum-flags value.
template <typename E>
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t<E, bool> {
using D = std::decay_t<E>;
using U = std::underlying_type_t<D>;
return enum_cast<D>(static_cast<U>(value)).has_value();
}
// Checks whether enum-flags contains enumerator with such string name.
template <typename E>
[[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");
return {};
}
namespace ostream_operators { namespace ostream_operators {
// TODO: operator<< template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_flags_t<E>>
using namespace magic_enum::ostream_operators; auto& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
using namespace magic_enum::flags;
using D = std::decay_t<E>;
if (const auto name = enum_name<D>(value); !name.empty()) {
for (const auto c : name) {
os.put(c);
}
} else {
os << enum_integer<D>(value);
}
return os;
}
template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_flags_t<E>>
auto& operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) {
using namespace magic_enum::flags;
if (value.has_value()) {
os << value.value();
}
return os;
}
} // namespace magic_enum::flags::ostream_operators } // namespace magic_enum::flags::ostream_operators