From 25912781ee84cb2e6d1f7d26a6600b9b43781f5f Mon Sep 17 00:00:00 2001 From: neargye Date: Sat, 4 Jul 2020 15:38:50 +0500 Subject: [PATCH] wip --- include/magic_enum.hpp | 172 +++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 58 deletions(-) diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 983f54f..852d531 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -107,6 +107,18 @@ struct supported : std::false_type {}; #endif +template +struct has_min : std::false_type {}; + +template +struct has_min::min)>> : std::true_type {}; + +template +struct has_max : std::false_type {}; + +template +struct has_max::max)>> : std::true_type {}; + template inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; @@ -244,75 +256,116 @@ constexpr bool is_valid() noexcept { return n(V)>().size() != 0; } -template -constexpr std::size_t range_size() noexcept { - static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); - constexpr auto size = Max - Min + 1; - static_assert(size > 0, "magic_enum::enum_range requires valid size."); - static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - - return static_cast(size); -} - -template -constexpr int reflected_min() noexcept { +template > +constexpr auto reflected_min() noexcept { static_assert(is_enum_v, "magic_enum::detail::reflected_min requires enum type."); - constexpr auto lhs = enum_range::min; - static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); - constexpr auto rhs = (std::numeric_limits>::min)(); - return cmp_less(lhs, rhs) ? rhs : lhs; + if constexpr (IsFlags) { + return 0; + } else { + static_assert(has_min::value, "magic_enum::enum_range requires min."); + constexpr auto lhs = enum_range::min; + static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); + constexpr auto rhs = (std::numeric_limits::min)(); + + return cmp_less(lhs, rhs) ? rhs : lhs; + } } -template -constexpr int reflected_max() noexcept { +template > +constexpr auto reflected_max() noexcept { static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); - 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."); - constexpr auto rhs = (std::numeric_limits>::max)(); - return cmp_less(lhs, rhs) ? lhs : rhs; + if constexpr (IsFlags) { + return (std::numeric_limits>::max)(); + } else { + static_assert(has_max::value, "magic_enum::enum_range requires max."); + 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."); + constexpr auto rhs = (std::numeric_limits::max)(); + + return cmp_less(lhs, rhs) ? lhs : rhs; + } } -template -inline constexpr int reflected_min_v = reflected_min(); +template +inline constexpr auto reflected_min_v = reflected_min(); -template -inline constexpr int reflected_max_v = reflected_max(); +template +inline constexpr auto reflected_max_v = reflected_max(); -template +template > +constexpr auto value(std::size_t i) noexcept { + static_assert(is_enum_v, "magic_enum::detail::value requires enum type."); + + if constexpr (IsFlags) { + return static_cast(static_cast(0x1) << static_cast(i)); + } else { + return static_cast(static_cast(i) + O); + } +} + +template constexpr auto values(std::integer_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); - constexpr std::array valid{{is_valid>()...}}; - constexpr int count = ((valid[I] ? 1 : 0) + ...); + constexpr std::array valid{{is_valid(I)>()...}}; + constexpr std::size_t count = ((valid[I] ? 1 : 0) + ...); std::array values{}; - for (int i = 0, v = 0; v < count; ++i) { + for (std::size_t i = 0, v = 0; v < count; ++i) { if (valid[i]) { - values[v++] = static_cast(i + reflected_min_v); + values[v++] = value(i); } } return values; } -template -inline constexpr auto values_v = values(std::make_integer_sequence, reflected_max_v>()>{}); +template > +constexpr auto values() noexcept { + static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); -template > -using values_t = decltype((values_v)); + 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{}); + } +} -template -inline constexpr std::size_t count_v = values_v.size(); +template +inline constexpr auto values_v = values(); -template -inline constexpr int min_v = static_cast(values_v.front()); +template > +using values_t = decltype((values_v)); -template -inline constexpr int max_v = static_cast(values_v.back()); +template +inline constexpr auto count_v = values_v.size(); -template -inline constexpr std::size_t range_size_v = range_size, max_v>(); +template > +inline constexpr auto min_v = static_cast(values_v.front()); + +template > +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."); + + if constexpr (IsFlags) { + return std::numeric_limits::digits; + } else { + constexpr int range_size = max_v - 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 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>; @@ -331,40 +384,40 @@ constexpr auto indexes(std::integer_sequence) noexcept { template inline constexpr auto indexes_v = indexes(std::make_integer_sequence>{}); -template +template constexpr auto names(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); - return std::array{{enum_name_v[I]>...}}; + return std::array{{enum_name_v[I]>...}}; } -template -inline constexpr auto names_v = names(std::make_index_sequence>{}); +template +inline constexpr auto names_v = names(std::make_index_sequence>{}); -template > -using names_t = decltype((names_v)); +template > +using names_t = decltype((names_v)); -template +template constexpr auto entries(std::index_sequence) noexcept { static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); - return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; } -template -inline constexpr auto entries_v = entries(std::make_index_sequence>{}); +template +inline constexpr auto entries_v = entries(std::make_index_sequence>{}); -template > -using entries_t = decltype((entries_v)); +template > +using entries_t = decltype((entries_v)); -template -inline constexpr bool is_sparse_v = range_size_v != count_v; +template +inline constexpr bool is_sparse_v = range_size_v != count_v; template > constexpr int undex(U value) noexcept { static_assert(is_enum_v, "magic_enum::detail::undex requires enum type."); - if (const auto i = static_cast(value) - min_v; value >= static_cast(min_v) && value <= static_cast(max_v)) { + if (const auto i = static_cast(value) - static_cast(min_v); value >= min_v && value <= max_v) { if constexpr (is_sparse_v) { if (const auto idx = indexes_v[i]; idx != invalid_index_v) { return idx; @@ -685,6 +738,9 @@ constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t