diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 6421434..7e23c2d 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -44,9 +44,13 @@ #include #include #include + #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) #include #endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) +#include +#endif #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) #include #endif @@ -259,32 +263,21 @@ constexpr bool cmp_less(L lhs, R rhs) noexcept { } } -template -constexpr std::uint8_t log2(T value) noexcept { - if constexpr (std::is_enum_v) { - using U = std::underlying_type_t; +template +constexpr I log2(I value) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); - return log2(static_cast(value)); - } else { - static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); - auto ret = std::uint8_t{0}; - for (; value > T{1}; value >>= T{1}, ++ret) {}; + auto ret = I{0}; + for (; value > I{1}; value >>= I{1}, ++ret) {}; - return ret; - } + return ret; } -template -constexpr bool is_pow2(T x) noexcept { - if constexpr (std::is_enum_v) { - using U = std::underlying_type_t; +template +constexpr bool is_pow2(I x) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::is_pow2 requires integral type."); - return is_pow2(static_cast(x)); - } else { - static_assert(std::is_integral_v, "magic_enum::detail::is_pow2 requires integral type."); - - return x != 0 && (x & (x - 1)) == 0; - } + return x != 0 && (x & (x - 1)) == 0; } template @@ -359,7 +352,7 @@ constexpr int reflected_max() noexcept { static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); if constexpr (IsFlags) { - return (std::numeric_limits::max)(); + return std::numeric_limits::digits - 1; } else { constexpr auto lhs = enum_range::max; static_assert(lhs < (std::numeric_limits::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX."); @@ -390,8 +383,8 @@ constexpr E value(std::size_t i) noexcept { } } -template -constexpr auto values(std::integer_sequence) noexcept { +template +constexpr auto values(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); constexpr std::array valid{{is_valid(I)>()...}}; constexpr std::size_t count = ((valid[I] ? std::size_t{1} : std::size_t{0}) + ...); @@ -409,15 +402,11 @@ constexpr auto values(std::integer_sequence) noexcept { template > constexpr auto values() noexcept { static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); + constexpr auto range_size = reflected_max_v - reflected_min_v + 1; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - if constexpr (IsFlags) { - return values(std::make_integer_sequence::digits>{}); - } else { - constexpr auto range_size = reflected_max_v - reflected_min_v + 1; - static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); - static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - return values>(std::make_integer_sequence{}); - } + return values>(std::make_index_sequence{}); } template @@ -438,36 +427,35 @@ inline constexpr auto max_v = static_cast(values_v.back()); template > constexpr std::size_t range_size() noexcept { static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); + constexpr auto max = IsFlags ? log2(max_v) : max_v; + constexpr auto min = IsFlags ? log2(min_v) : min_v; + constexpr auto range_size = max - min + U{1}; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - if constexpr (IsFlags) { - return std::numeric_limits::digits; - } else { - constexpr auto range_size = max_v - min_v + U{1}; - static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); - static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - return static_cast(range_size); - } + return static_cast(range_size); } template inline constexpr auto range_size_v = range_size(); -template -using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; +template +using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; -template -inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); +template +inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); -template -constexpr auto indexes(std::integer_sequence) noexcept { +template +constexpr auto indexes(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::indexes requires enum type."); - [[maybe_unused]] auto i = index_t{0}; + constexpr auto min = IsFlags ? log2(min_v) : min_v; + [[maybe_unused]] auto i = index_t{0}; - return std::array, sizeof...(I)>{{(is_valid>() ? i++ : invalid_index_v)...}}; + return std::array{{(is_valid(I)>() ? i++ : invalid_index_v)...}}; } -template -inline constexpr auto indexes_v = indexes(std::make_integer_sequence>{}); +template +inline constexpr auto indexes_v = indexes(std::make_index_sequence>{}); template constexpr auto names(std::index_sequence) noexcept { @@ -499,14 +487,7 @@ template > constexpr bool is_sparse() noexcept { static_assert(is_enum_v, "magic_enum::detail::is_sparse requires enum type."); - if constexpr (IsFlags) { - auto range_count = std::size_t{1}; - for (auto i = min_v; i != max_v; i <<= U{1}, ++range_count) {}; - - return range_count != count_v; - } else { - return range_size_v != count_v; - } + return range_size_v != count_v; } template @@ -628,9 +609,8 @@ using underlying_type_t = typename underlying_type::type; // Returns string name of enum type. template -[[nodiscard]] constexpr string_view enum_type_name() noexcept { +[[nodiscard]] constexpr auto enum_type_name() noexcept -> std::enable_if_t>, string_view> { using D = std::decay_t; - static_assert(std::is_enum_v, "Requires enum type."); constexpr string_view name = detail::type_name_v; static_assert(name.size() > 0, "Enum type does not have a name."); @@ -669,9 +649,8 @@ template // Returns string name from static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. template -[[nodiscard]] constexpr string_view enum_name() noexcept { +[[nodiscard]] constexpr auto enum_name() noexcept -> std::enable_if_t>, string_view> { using D = std::decay_t; - static_assert(std::is_enum_v, "Requires enum type."); constexpr string_view name = detail::enum_name_v; static_assert(name.size() > 0, "Enum value does not have a name."); @@ -747,7 +726,7 @@ template // Returns integer value from enum value. template -[[nodiscard]] constexpr underlying_type_t enum_integer(E value) noexcept { +[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> std::enable_if_t>, underlying_type_t> { return static_cast>(value); } @@ -804,25 +783,19 @@ std::basic_ostream& operator<<(std::basic_ostream& o using D = std::decay_t; using U = underlying_type_t; #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED - using namespace magic_enum; - - if (const auto name = enum_name(value); !name.empty()) { + if (const auto name = magic_enum::enum_name(value); !name.empty()) { for (const auto c : name) { os.put(c); } return os; } #endif - return os << static_cast(value); + return (os << static_cast(value)); } template , int> = 0> std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { - if (value.has_value()) { - os << value.value(); - } - - return os; + return value.has_value() ? (os << value.value()) : os; } } // namespace magic_enum::ostream_operators @@ -851,17 +824,17 @@ constexpr E operator^(E lhs, E rhs) noexcept { template , int> = 0> constexpr E& operator|=(E& lhs, E rhs) noexcept { - return lhs = lhs | rhs; + return lhs = (lhs | rhs); } template , int> = 0> constexpr E& operator&=(E& lhs, E rhs) noexcept { - return lhs = lhs & rhs; + return lhs = (lhs & rhs); } template , int> = 0> constexpr E& operator^=(E& lhs, E rhs) noexcept { - return lhs = lhs ^ rhs; + return lhs = (lhs ^ rhs); } } // namespace magic_enum::bitwise_operators @@ -912,8 +885,8 @@ template string name; auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { - if (const auto v = enum_value(i); (static_cast(value) & static_cast(v)) != 0) { - check_value |= static_cast(v); + if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { + check_value |= v; const auto n = detail::names_v[i]; if (!name.empty()) { name.append(1, '|'); @@ -922,7 +895,7 @@ template } } - if (check_value == static_cast(value)) { + if (check_value != 0 && check_value == static_cast(value)) { return name; } @@ -997,8 +970,6 @@ template } if (f == U{0}) { return {}; // Invalid value or out of range. - } else { - result |= f; } value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); } @@ -1027,8 +998,9 @@ using magic_enum::enum_integer; template [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_flags_t> { using D = std::decay_t; + using U = underlying_type_t; - if (detail::is_pow2(value)) { + if (detail::is_pow2(static_cast(value))) { for (std::size_t i = 0; i < detail::count_v; ++i) { if (enum_value(i) == value) { return i; @@ -1082,24 +1054,19 @@ std::basic_ostream& operator<<(std::basic_ostream& o using D = std::decay_t; using U = underlying_type_t; #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED - using namespace magic_enum::flags; - if (const auto name = enum_name(value); !name.empty()) { + if (const auto name = magic_enum::flags::enum_name(value); !name.empty()) { for (const auto c : name) { os.put(c); } return os; } #endif - return os << static_cast(value); + return (os << static_cast(value)); } template = 0> std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { - if (value.has_value()) { - os << value.value(); - } - - return os; + return value.has_value() ? (os << value.value()) : os; } } // namespace magic_enum::flags::ostream_operators