From d3027d904f47d9bc9497114900694cd0f4bc0696 Mon Sep 17 00:00:00 2001 From: neargye Date: Mon, 29 Apr 2019 20:21:12 +0500 Subject: [PATCH] wip --- example/example.cpp | 12 ++----- include/magic_enum.hpp | 75 +++++++++++++++++------------------------- 2 files changed, 33 insertions(+), 54 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index d8ec7cc..4a888bf 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -54,15 +54,9 @@ int main() { } // Enum value to integer value. - auto color_underlying = magic_enum::integer_cast(Color::RED); - if (color_underlying.has_value() && color_underlying.value() == static_cast>(Color::RED)) { - std::cout << "RED = " << color_underlying.value() << std::endl; // RED = -10 - } - - // Enum value to specific type integer value. - auto color_int = magic_enum::integer_cast(Color::RED); - if (color_int.has_value() && color_int.value() == static_cast(Color::RED)) { - std::cout << "RED = " << color_int.value() << std::endl; // RED = -10 + auto color_integer_value = magic_enum::enum_integer_value(Color::RED); + if (color_integer_value == static_cast>(Color::RED)) { + std::cout << "RED = " << color_integer_value << std::endl; // RED = -10 } using namespace magic_enum::ops; // out-of-the-box stream operator for enums. diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index b488727..e9b5c0c 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -55,14 +55,15 @@ namespace magic_enum { -// Enum value must be in range [-MAGIC_ENUM_RANGE_MAX, MAGIC_ENUM_RANGE_MIN]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. -// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX and MAGIC_ENUM_RANGE_MIN. +// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. +// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. // If need another range for specific enum type, add specialization enum_range for necessary enum type. template struct enum_range final { static_assert(std::is_enum_v, "magic_enum::enum_range requires enum type."); static constexpr int min = std::is_signed_v> ? MAGIC_ENUM_RANGE_MIN : 0; static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::enum_range requires max > min."); }; static_assert(MAGIC_ENUM_RANGE_MAX > 0, @@ -86,7 +87,7 @@ template > } template > -[[nodiscard]] constexpr decltype(auto) range_impl() { +[[nodiscard]] constexpr auto range_impl() { static_assert(std::is_enum_v, "magic_enum::detail::range_impl requires enum type."); static_assert(enum_range::max > enum_range::min, "magic_enum::enum_range requires max > min."); constexpr int max = enum_range::max < (std::numeric_limits::max)() ? enum_range::max : (std::numeric_limits::max)(); @@ -99,31 +100,28 @@ template [[nodiscard]] constexpr std::string_view name_impl() noexcept { static_assert(std::is_enum_v, "magic_enum::detail::name_impl requires enum type."); #if defined(__clang__) - constexpr std::string_view name{__PRETTY_FUNCTION__}; - constexpr auto suffix = sizeof("]") - 1; + constexpr std::string_view name{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}; #elif defined(__GNUC__) && __GNUC__ >= 9 - constexpr std::string_view name{__PRETTY_FUNCTION__}; - constexpr auto suffix = sizeof("; std::string_view = std::basic_string_view]") - 1; + constexpr std::string_view name{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 51}; #elif defined(_MSC_VER) - constexpr std::string_view name{__FUNCSIG__}; - constexpr auto suffix = sizeof(">(void) noexcept") - 1; + constexpr std::string_view name{__FUNCSIG__, sizeof(__FUNCSIG__) - 17}; #else return {}; // Unsupported compiler. #endif #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER) - constexpr auto prefix = name.find_last_of(" :,-)", name.length() - suffix) + 1; + constexpr auto prefix = name.find_last_of(" :,-)") + 1; if constexpr (name[prefix] >= '0' && name[prefix] <= '9') { return {}; // Value does not have name. } else { - return name.substr(prefix, name.length() - prefix - suffix); + return name.substr(prefix, name.length() - prefix); } #endif } template -[[nodiscard]] constexpr decltype(auto) strings_impl(std::integer_sequence) noexcept { +[[nodiscard]] constexpr auto strings_impl(std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::detail::strings_impl requires enum type."); constexpr std::array names{{name_impl(I + min_impl())>()...}}; @@ -143,7 +141,7 @@ template } template -[[nodiscard]] constexpr decltype(auto) values_impl(std::integer_sequence) noexcept { +[[nodiscard]] constexpr auto values_impl(std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::detail::values_impl requires enum type."); constexpr int n = sizeof...(I); constexpr std::array valid{{!name_impl(I + min_impl())>().empty()...}}; @@ -160,7 +158,7 @@ template } template -[[nodiscard]] constexpr decltype(auto) names_impl(std::integer_sequence) noexcept { +[[nodiscard]] constexpr auto names_impl(std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::detail::names_impl requires enum type."); constexpr auto values = values_impl(range_impl()); constexpr std::array names{{name_impl()...}}; @@ -169,7 +167,7 @@ template } template -[[nodiscard]] constexpr decltype(auto) entries_impl(std::integer_sequence) noexcept { +[[nodiscard]] constexpr auto entries_impl(std::integer_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::detail::entries_impl requires enum type."); constexpr auto values = values_impl(range_impl()); constexpr std::array, sizeof...(I)> entries{{{values[I], name_impl()}...}}; @@ -178,7 +176,7 @@ template } template -using enable_if_enum_t = typename std::enable_if>::type; +using enable_if_enum_t = typename std::enable_if>>::type; template> struct is_scoped_enum_impl : std::false_type {}; @@ -239,29 +237,13 @@ template > } } -// Obtains integer value from enum value. -template , typename = detail::enable_if_enum_t> -[[nodiscard]] constexpr std::optional> integer_cast(E value) noexcept { - static_assert(std::is_enum_v, "magic_enum::integer_cast requires enum type."); +// Returns integer value from enum value. +template > +[[nodiscard]] constexpr auto enum_integer_value(E value) noexcept { + using D = std::decay_t; + static_assert(std::is_enum_v, "magic_enum::enum_integer_value requires enum type."); - if (detail::name_impl(static_cast(value)).empty()) { - return std::nullopt; // Invalid value or out of range. - } else { - return static_cast>(value); - } -} - -// Obtains specific type integer value from enum value. -template , typename = std::enable_if_t && std::is_arithmetic_v>> -[[nodiscard]] constexpr std::optional integer_cast(E value) noexcept { - static_assert(std::is_enum_v, "magic_enum::integer_cast requires enum type."); - static_assert(std::is_arithmetic_v, "magic_enum::integer_cast requires integer type."); - - if (detail::name_impl(static_cast(value)).empty() || static_cast(value) != static_cast>(value)) { - return std::nullopt; // Invalid value or out of range. - } else { - return static_cast(value); - } + return static_cast>(value); } // Returns enum value at specified index. @@ -276,7 +258,7 @@ template> // Obtains value enum sequence. template > -[[nodiscard]] constexpr decltype(auto) enum_values() noexcept { +[[nodiscard]] constexpr auto enum_values() noexcept { static_assert(std::is_enum_v, "magic_enum::enum_values requires enum type."); constexpr auto values = detail::values_impl(detail::range_impl()); @@ -293,8 +275,9 @@ template > } // Obtains string enum name from enum value. -template , typename = detail::enable_if_enum_t> +template > [[nodiscard]] constexpr std::string_view enum_name(E value) noexcept { + using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_name requires enum type."); return detail::name_impl(static_cast(value)); @@ -302,7 +285,7 @@ template , typename = detail::enable_if // Obtains string enum name sequence. template > -[[nodiscard]] constexpr decltype(auto) enum_names() noexcept { +[[nodiscard]] constexpr auto enum_names() noexcept { static_assert(std::is_enum_v, "magic_enum::enum_names requires enum type."); constexpr auto count = detail::values_impl(detail::range_impl()).size(); constexpr auto names = detail::names_impl(std::make_index_sequence{}); @@ -312,7 +295,7 @@ template > // Obtains pair (value enum, string enum name) sequence. template > -[[nodiscard]] constexpr decltype(auto) enum_entries() noexcept { +[[nodiscard]] constexpr auto enum_entries() noexcept { static_assert(std::is_enum_v, "magic_enum::enum_entries requires enum type."); constexpr auto count = detail::values_impl(detail::range_impl()).size(); constexpr auto entries = detail::entries_impl(std::make_index_sequence{}); @@ -322,8 +305,9 @@ template > namespace ops { -template , typename = detail::enable_if_enum_t> +template > std::basic_ostream& operator<<(std::basic_ostream& os, E value) { + using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::ops::operator<< requires enum type."); if (auto name = detail::name_impl(static_cast(value)); !name.empty()) { @@ -335,9 +319,10 @@ std::basic_ostream& operator<<(std::basic_ostream& o return os; } -template , typename = detail::enable_if_enum_t> +template > std::basic_ostream& operator<<(std::basic_ostream& os, std::optional value) { - static_assert(std::is_enum_v, "magic_enum::ops::operator<< requires enum type."); + using D = std::decay_t; + static_assert(std::is_enum_v, "magic_enum::ops::operator<< requires enum type."); if (value.has_value()) { if (auto name = detail::name_impl(static_cast(value.value())); !name.empty()) {