From d525acae66237298bf8fb87f3fcf70ffcba8fab9 Mon Sep 17 00:00:00 2001 From: neargye Date: Sat, 15 Aug 2020 22:47:20 +0500 Subject: [PATCH] wip --- example/enum_flag_example.cpp | 22 ++-- example/example.cpp | 20 ++- include/magic_enum.hpp | 239 ++++++++++++++++------------------ 3 files changed, 131 insertions(+), 150 deletions(-) diff --git a/example/enum_flag_example.cpp b/example/enum_flag_example.cpp index d2eaf79..812a3fb 100644 --- a/example/enum_flag_example.cpp +++ b/example/enum_flag_example.cpp @@ -34,21 +34,17 @@ int main() { std::cout << f1_name << std::endl; // Endangered // String enum name sequence. - constexpr auto names = magic_enum::flags::enum_names(); + constexpr auto& names = magic_enum::flags::enum_names(); std::cout << "AnimalFlags names:"; - for (auto n : names) { + for (const auto& n : names) { std::cout << " " << n; } std::cout << std::endl; // AnimalFlags names: HasClaws CanFly EatsFish Endangered -#if 0 // String name to enum value. auto f2 = magic_enum::flags::enum_cast("EatsFish|CanFly"); -#else -auto f2 = magic_enum::flags::enum_cast(1074790400); -#endif - if (f2.has_value() && f2.value() == AnimalFlags::EatsFish) { + if (f2.has_value()) { std::cout << "EatsFish = " << magic_enum::flags::enum_integer(f2.value()) << std::endl; // CanFly|EatsFish = 1074790400 } @@ -60,9 +56,7 @@ auto f2 = magic_enum::flags::enum_cast(1074790400); // Enum value to integer value. auto f4_integer = magic_enum::flags::enum_integer(AnimalFlags::HasClaws); - if (f4_integer == static_cast>(AnimalFlags::HasClaws)) { - std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 1024 - } + std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 1024 using namespace magic_enum::flags::ostream_operators; // out-of-the-box ostream operator for all enums. // ostream operator for enum. @@ -75,9 +69,9 @@ auto f2 = magic_enum::flags::enum_cast(1074790400); std::cout << "AnimalFlags[0] = " << magic_enum::flags::enum_value(0) << std::endl; // AnimalFlags[0] = HasClaws // Enum value sequence. - constexpr auto values = magic_enum::flags::enum_values(); + constexpr auto& values = magic_enum::flags::enum_values(); std::cout << "AnimalFlags values:"; - for (AnimalFlags f : values) { + for (const auto& f : values) { std::cout << " " << f; // ostream operator for enum. } std::cout << std::endl; @@ -89,9 +83,9 @@ auto f2 = magic_enum::flags::enum_cast(1074790400); std::cout << flag << std::endl; // HasClaws|CanFly // Enum pair (value enum, string enum name) sequence. - constexpr auto entries = magic_enum::flags::enum_entries(); + constexpr auto& entries = magic_enum::flags::enum_entries(); std::cout << "AnimalFlags entries:"; - for (auto e : entries) { + for (const auto& e : entries) { std::cout << " " << e.second << " = " << magic_enum::flags::enum_integer(e.first); } std::cout << std::endl; diff --git a/example/example.cpp b/example/example.cpp index c321ca1..bc41d26 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -39,9 +39,9 @@ int main() { std::cout << c1_name << std::endl; // RED // String enum name sequence. - constexpr auto names = magic_enum::enum_names(); + constexpr auto& names = magic_enum::enum_names(); std::cout << "Color names:"; - for (auto n : names) { + for (const auto& n : names) { std::cout << " " << n; } std::cout << std::endl; @@ -49,21 +49,19 @@ int main() { // String name to enum value. auto c2 = magic_enum::enum_cast("BLUE"); - if (c2.has_value() && c2.value() == Color::BLUE) { + if (c2.has_value()) { std::cout << "BLUE = " << to_integer(c2.value()) << std::endl; // BLUE = 0 } // Integer value to enum value. auto c3 = magic_enum::enum_cast(10); - if (c3.has_value() && c3.value() == Color::GREEN) { + if (c3.has_value()) { std::cout << "GREEN = " << magic_enum::enum_integer(c3.value()) << std::endl; // GREEN = 10 } // Enum value to integer value. auto c4_integer = magic_enum::enum_integer(Color::RED); - if (c4_integer == static_cast>(Color::RED)) { - std::cout << "RED = " << c4_integer << std::endl; // RED = -10 - } + std::cout << "RED = " << c4_integer << std::endl; // RED = -10 using namespace magic_enum::ostream_operators; // out-of-the-box ostream operator for all enums. // ostream operator for enum. @@ -76,9 +74,9 @@ int main() { std::cout << "Color[0] = " << magic_enum::enum_value(0) << std::endl; // Color[0] = RED // Enum value sequence. - constexpr auto values = magic_enum::enum_values(); + constexpr auto& values = magic_enum::enum_values(); std::cout << "Colors values:"; - for (Color c : values) { + for (const auto& c : values) { std::cout << " " << c; // ostream operator for enum. } std::cout << std::endl; @@ -103,9 +101,9 @@ int main() { static_assert(magic_enum::is_scoped_enum_v); // Enum pair (value enum, string enum name) sequence. - constexpr auto entries = magic_enum::enum_entries(); + constexpr auto& entries = magic_enum::enum_entries(); std::cout << "Colors entries:"; - for (auto e : entries) { + for (const auto& e : entries) { std::cout << " " << e.second << " = " << static_cast(e.first); } std::cout << std::endl; diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 2e36ce7..ea0fb9a 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -665,6 +665,19 @@ template return detail::entries_v; } +// Obtains enum value from integer value. +// Returns std::optional with enum value. +template +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + if (detail::undex(value) != detail::invalid_index_v) { + return static_cast(value); + } + + return std::nullopt; // Invalid value or out of range. +} + // Obtains enum value from string name. // Returns std::optional with enum value. template @@ -690,19 +703,6 @@ template return enum_cast(value, detail::char_equal_to{}); } -// Obtains enum value from integer value. -// Returns std::optional with enum value. -template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - if (detail::undex(value) != detail::invalid_index_v) { - return static_cast(value); - } - - return std::nullopt; // Invalid value or out of range. -} - // Returns integer value from enum value. template [[nodiscard]] constexpr underlying_type_t enum_integer(E value) noexcept { @@ -744,7 +744,7 @@ template using D = std::decay_t; static_assert(std::is_invocable_r_v, "magic_enum::enum_contains requires bool(char, char) invocable predicate."); - return enum_cast(value, std::move(p)).has_value(); + return enum_cast(value, std::move_if_noexcept(p)).has_value(); } // Checks whether enum contains enumerator with such string name. @@ -826,6 +826,9 @@ constexpr E& operator^=(E& lhs, E rhs) noexcept { namespace flags { +// Returns string name of enum type. +using magic_enum::enum_type_name; + // Returns number of enum-flags values. template [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_flags_t { @@ -908,100 +911,91 @@ template return detail::entries_v; } -// Checks whether enum-flags contains enumerator with such integer value. -template -[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t { - using D = std::decay_t; - - if constexpr(Strict) { - if constexpr (detail::is_sparse_v) { - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (value == enum_value(i)) { - return true; - } - } - - return false; - } - } else { - if constexpr (detail::is_sparse_v) { - using U = underlying_type_t; - auto check_value = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { - check_value |= v; - } - } - - return check_value == value; - } else { - constexpr auto min = detail::min_v; - constexpr auto max = detail::value_ors(); - - return value >= min && value <= max; - } - } -} - -// Checks whether enum-flags contains enumerator with such enum-flags value. -template -[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t { - using D = std::decay_t; - using U = underlying_type_t; - - return enum_contains(static_cast(value)); -} - -// Checks whether enum-flags contains enumerator with such string name. -template -[[nodiscard]] constexpr auto enum_contains(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t { - using D = std::decay_t; - static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate."); - // TODO: impl - static_assert(sizeof(decltype(value)) == sizeof(E) * 0, "not implemented"); - return {}; -} - -// Checks whether enum-flags contains enumerator with such string name. -template -[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t { - // TODO: impl - static_assert(sizeof(decltype(value)) == sizeof(E) * 0, "not implemented"); - return {}; -} - // Obtains enum-flags value from integer value. // Returns std::optional with enum-flags value. template [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t>> { using D = std::decay_t; + using U = underlying_type_t; - if (enum_contains(value)) { - return static_cast(value); + if constexpr(Strict) { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast(enum_value(i))) { + return static_cast(value); + } + } + } else { + if constexpr (detail::is_sparse_v) { + auto check_value = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { + check_value |= v; + } + } + + if (check_value == value) { + return static_cast(value); + } + } else { + constexpr auto min = detail::min_v; + constexpr auto max = detail::value_ors(); + + if (value >= min && value <= max) { + return static_cast(value); + } + } } - return std::nullopt; // Invalid value or out of range. + return std::nullopt; } // Obtains enum-flags value from string name. // Returns std::optional with enum-flags value. -template +template [[nodiscard]] constexpr auto enum_cast(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t>> { static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_cast requires bool(char, char) invocable predicate."); - // TODO: impl - static_assert(sizeof(decltype(value)) + sizeof(decltype(p)) == sizeof(E) * 0, "not implemented"); - return {}; + using D = std::decay_t; + using U = underlying_type_t; + + auto result = U{0}; + while (!value.empty()) { + const auto d = value.find_first_of('|'); + const auto s = (d == std::string_view::npos) ? value : value.substr(0, d); + auto f = U{0}; + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(s, detail::names_v[i], p)) { + f = static_cast(enum_value(i)); + result |= f; + break; + } + } + if (f == 0) { + return std::nullopt; + } else { + result |= f; + } + value.remove_prefix((d == std::string_view::npos) ? value.size() : d + 1); + } + + if (result == 0) { + return std::nullopt; + } else { + return static_cast(result); + } } // Obtains enum-flags value from string name. // Returns std::optional with enum-flags value. -template +template [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_flags_t>> { - // TODO: impl - static_assert(sizeof(decltype(value)) == sizeof(E) * 0, "not implemented"); - return {}; + using D = std::decay_t; + + return enum_cast(value, detail::char_equal_to{}); } +// Returns integer value from enum value. +using magic_enum::enum_integer; + // Obtains index in enum-flags values from enum-flags value. // Returns std::optional with index. template @@ -1019,11 +1013,39 @@ template return std::nullopt; // Value out of range. } -// Returns string name of enum type. -using magic_enum::enum_type_name; +// Checks whether enum-flags contains enumerator with such enum-flags value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_flags_t { + using D = std::decay_t; + using U = underlying_type_t; -// Returns integer value from enum value. -using magic_enum::enum_integer; + return enum_cast(static_cast(value)); +} + +// Checks whether enum-flags contains enumerator with such integer value. +template +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_flags_t { + using D = std::decay_t; + + return enum_cast(value).has_value(); +} + +// Checks whether enum-flags contains enumerator with such string name. +template +[[nodiscard]] constexpr auto enum_contains(std::string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_flags_t { + using D = std::decay_t; + static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate."); + + return enum_cast(value, std::move_if_noexcept(p)).has_value(); +} + +// Checks whether enum-flags contains enumerator with such string name. +template +[[nodiscard]] constexpr auto enum_contains(std::string_view value) noexcept -> detail::enable_if_enum_flags_t { + using D = std::decay_t; + + return enum_cast(value).has_value(); +} namespace ostream_operators { @@ -1056,40 +1078,7 @@ std::basic_ostream& operator<<(std::basic_ostream& o namespace bitwise_operators { -template = 0> -constexpr E operator~(E rhs) noexcept { - return static_cast(~static_cast>(rhs)); -} - -template = 0> -constexpr E operator|(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) | static_cast>(rhs)); -} - -template = 0> -constexpr E operator&(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) & static_cast>(rhs)); -} - -template = 0> -constexpr E operator^(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); -} - -template = 0> -constexpr E& operator|=(E& lhs, E rhs) noexcept { - return lhs = lhs | rhs; -} - -template = 0> -constexpr E& operator&=(E& lhs, E rhs) noexcept { - return lhs = lhs & rhs; -} - -template = 0> -constexpr E& operator^=(E& lhs, E rhs) noexcept { - return lhs = lhs ^ rhs; -} +using namespace magic_enum::bitwise_operators; } // namespace magic_enum::flags::bitwise_operators