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>
|
#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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue