mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-09 23:34:23 +00:00
wip
This commit is contained in:
parent
604054df5a
commit
8e343c47b8
3 changed files with 150 additions and 102 deletions
|
|
@ -24,16 +24,16 @@
|
|||
|
||||
#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() {
|
||||
// Enum variable to string name.
|
||||
AnimalFlags f1 = AnimalFlags::CanFly;
|
||||
auto f1_name = magic_enum::flag::enum_name(f1);
|
||||
std::cout << f1_name << std::endl; // CanFly
|
||||
AnimalFlags f1 = AnimalFlags::Endangered;
|
||||
auto f1_name = magic_enum::flags::enum_name(f1);
|
||||
std::cout << f1_name << std::endl; // Endangered
|
||||
|
||||
// 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:";
|
||||
for (auto n : names) {
|
||||
std::cout << " " << n;
|
||||
|
|
@ -43,38 +43,38 @@ int main() {
|
|||
|
||||
#if 0
|
||||
// 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) {
|
||||
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.
|
||||
auto f3 = magic_enum::flag::enum_cast<AnimalFlags>(8);
|
||||
if (f3.has_value() && f3.value() == AnimalFlags::Endangered) {
|
||||
std::cout << "Endangered = " << magic_enum::flag::enum_integer(f3.value()) << std::endl; // Endangered = 8
|
||||
auto f3 = magic_enum::flags::enum_cast<AnimalFlags>(1073742848);
|
||||
if (f3.has_value()) {
|
||||
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.
|
||||
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)) {
|
||||
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.
|
||||
#if 0
|
||||
using namespace magic_enum::flags::ostream_operators; // out-of-the-box ostream operator for all enums.
|
||||
// ostream operator for enum.
|
||||
std::cout << f1 << " " << f2 << " " << f3 << std::endl; // CanFly EatsFish Endangered
|
||||
#endif
|
||||
std::cout << f1 << " " << f2 << " " << f3 << std::endl; // Endangered CanFly|EatsFish HasClaws|EatsFish
|
||||
|
||||
// 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.
|
||||
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.
|
||||
constexpr auto values = magic_enum::flag::enum_values<AnimalFlags>();
|
||||
constexpr auto values = magic_enum::flags::enum_values<AnimalFlags>();
|
||||
std::cout << "AnimalFlags values:";
|
||||
for (AnimalFlags f : values) {
|
||||
std::cout << " " << f; // ostream operator for enum.
|
||||
|
|
@ -82,19 +82,19 @@ int main() {
|
|||
std::cout << std::endl;
|
||||
// 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: ~, |, &, ^, |=, &=, ^=.
|
||||
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.
|
||||
constexpr auto entries = magic_enum::flag::enum_entries<AnimalFlags>();
|
||||
constexpr auto entries = magic_enum::flags::enum_entries<AnimalFlags>();
|
||||
std::cout << "AnimalFlags 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;
|
||||
// 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ int main() {
|
|||
std::cout << "Color: " << c1 << " " << c2 << " " << c3 << std::endl; // Color: RED BLUE GREEN
|
||||
|
||||
// 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.
|
||||
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.
|
||||
// Support operators: ~, |, &, ^, |=, &=, ^=.
|
||||
Flags flag = Flags::A | Flags::C;
|
||||
std::cout << flag << std::endl;
|
||||
std::cout << flag << std::endl; // 5
|
||||
|
||||
enum color { red, green, blue };
|
||||
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ constexpr bool is_valid() noexcept {
|
|||
}
|
||||
|
||||
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.");
|
||||
|
||||
if constexpr (IsFlags) {
|
||||
|
|
@ -298,7 +298,7 @@ constexpr auto reflected_min() noexcept {
|
|||
}
|
||||
|
||||
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.");
|
||||
|
||||
if constexpr (IsFlags) {
|
||||
|
|
@ -450,7 +450,7 @@ constexpr bool is_sparse() noexcept {
|
|||
}
|
||||
|
||||
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>>
|
||||
constexpr int undex(U value) noexcept {
|
||||
|
|
@ -476,6 +476,18 @@ constexpr int endex(E value) noexcept {
|
|||
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>
|
||||
struct enable_if_enum {};
|
||||
|
||||
|
|
@ -492,13 +504,13 @@ struct enable_if_enum<true, true, T, R> {
|
|||
using type = R;
|
||||
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(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>
|
||||
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;
|
||||
|
||||
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>
|
||||
[[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>;
|
||||
constexpr auto count = detail::count_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 {
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -724,21 +737,26 @@ template <typename E>
|
|||
|
||||
namespace ostream_operators {
|
||||
|
||||
template <typename Char, typename Traits, typename E>
|
||||
auto operator<<(std::basic_ostream<Char, Traits>& os, E value) -> detail::enable_if_enum_t<E, std::basic_ostream<Char, Traits>&> {
|
||||
if (const auto name = enum_name(value); !name.empty()) {
|
||||
template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_t<E>>
|
||||
auto& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
|
||||
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) {
|
||||
os.put(c);
|
||||
}
|
||||
} else {
|
||||
os << enum_integer(value);
|
||||
os << enum_integer<D>(value);
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename Char, typename Traits, typename E>
|
||||
auto operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) -> detail::enable_if_enum_t<E, std::basic_ostream<Char, Traits>&> {
|
||||
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) {
|
||||
using namespace magic_enum;
|
||||
|
||||
if (value.has_value()) {
|
||||
os << value.value();
|
||||
}
|
||||
|
|
@ -750,44 +768,44 @@ auto operator<<(std::basic_ostream<Char, Traits>& os, std::optional<E> value) ->
|
|||
|
||||
namespace bitwise_operators {
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator~(E rhs) noexcept -> detail::enable_if_enum_t<E, E> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
constexpr E operator~(E rhs) noexcept {
|
||||
return static_cast<E>(~static_cast<underlying_type_t<E>>(rhs));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator|(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
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));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator&(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
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));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator^(E lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
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));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator|=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
constexpr E& operator|=(E& lhs, E rhs) noexcept {
|
||||
return lhs = lhs | rhs;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator&=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
constexpr E& operator&=(E& lhs, E rhs) noexcept {
|
||||
return lhs = lhs & rhs;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t<E, E&> {
|
||||
template <typename E, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
constexpr E& operator^=(E& lhs, E rhs) noexcept {
|
||||
return lhs = lhs ^ rhs;
|
||||
}
|
||||
|
||||
} // namespace magic_enum::bitwise_operators
|
||||
|
||||
namespace flag {
|
||||
namespace flags {
|
||||
|
||||
// Returns number of enum-flags values.
|
||||
template <typename E>
|
||||
|
|
@ -802,13 +820,14 @@ 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>> {
|
||||
using D = std::decay_t<E>;
|
||||
constexpr auto count = detail::count_v<D, true>;
|
||||
|
||||
if constexpr (detail::is_sparse_v<D>) {
|
||||
return assert((index < detail::count_v<D, true>)), detail::values_v<D, true>[index];
|
||||
if constexpr (detail::is_sparse_v<D, true>) {
|
||||
return assert(index < count), detail::values_v<D, true>[index];
|
||||
} else {
|
||||
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>;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Returns std::optional with enum-flags value.
|
||||
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>>> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = std::underlying_type_t<D>;
|
||||
|
||||
auto check_value = U{0};
|
||||
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) {
|
||||
if (enum_contains<D>(value)) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
|
||||
|
|
@ -884,7 +933,8 @@ template <typename E>
|
|||
// Returns std::optional with enum-flags value.
|
||||
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>>> {
|
||||
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");
|
||||
return {};
|
||||
}
|
||||
|
|
@ -893,20 +943,15 @@ template <typename E, typename BinaryPredicate>
|
|||
// Returns std::optional with enum-flags value.
|
||||
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>>> {
|
||||
// TODO: impl
|
||||
static_assert(sizeof(E) == 0, "not implemented");
|
||||
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.
|
||||
// Returns std::optional with index.
|
||||
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>;
|
||||
|
||||
if (detail::is_pow2<D>(value)) {
|
||||
|
|
@ -920,34 +965,37 @@ template <typename E>
|
|||
return std::nullopt; // Value out of range.
|
||||
}
|
||||
|
||||
// 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>;
|
||||
|
||||
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 {};
|
||||
}
|
||||
using magic_enum::enum_type_name; // TODO: impl
|
||||
using magic_enum::enum_integer; // TODO: impl
|
||||
|
||||
namespace ostream_operators {
|
||||
|
||||
// TODO: operator<<
|
||||
using namespace magic_enum::ostream_operators;
|
||||
template <typename Char, typename Traits, typename E, typename = detail::enable_if_enum_flags_t<E>>
|
||||
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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue