From db4c55c36ac21e202d252d99d29f731c45666d1e Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Mon, 14 Oct 2019 00:44:42 -0700 Subject: [PATCH] Change the way range_min()/max() is calculated (#19) This was previously done via parameter expansion. The expanded form looks like this: A(128) && A(127) && ... && A(X) && ... && A(0) where A(X) is the actual range_max which is crafted to return 'false'. Static analysis detects that expressions after A(X) are dead code due to short-circuiting. The new implementation uses a simple loop to find the extrema, similarly to the loop in detail::values(). Furthermore, it uses only one parameter expansion (for reflected_set_v), as opposed to two (one for range_min and one for range_max). --- include/magic_enum.hpp | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 61f639a..59387f8 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -228,29 +228,49 @@ constexpr std::size_t reflected_size() { return static_cast(size); } +template +inline constexpr std::size_t reflected_size_v = reflected_size(); + template -constexpr int range_min(std::integer_sequence) noexcept { +constexpr std::array> reflected_set_v_helper(std::integer_sequence) { + return {{(n(I + reflected_min_v)>().size() != 0)...}}; +} +template +inline constexpr std::array> reflected_set_v = reflected_set_v_helper(std::make_integer_sequence>{}); + +template +constexpr int range_min() noexcept { static_assert(is_enum_v, "magic_enum::detail::range_min requires enum type."); - int r = 0; - (void)(((n(I + reflected_min_v)>().size() != 0) ? (r = I + reflected_min_v, false) : true) && ...); - return r; + // Find leftmost value. + for (int i = 0; i < static_cast(reflected_size_v); ++i) { + if (reflected_set_v[i]) { + return i + reflected_min_v; + } + } + + return reflected_max_v; } -template -constexpr int range_max(std::integer_sequence) noexcept { +template +constexpr int range_max() noexcept { static_assert(is_enum_v, "magic_enum::detail::range_max requires enum type."); - int r = 0; - (void)(((n(reflected_max_v - I)>().size() != 0) ? (r = reflected_max_v - I, false) : true) && ...); - return r; + // Find rightmost value + for (int i = static_cast(reflected_size_v) - 1; i >= 0; --i) { + if (reflected_set_v[i]) { + return i + reflected_min_v; + } + } + + return reflected_min_v; } template -inline constexpr int min_v = range_min(std::make_integer_sequence()>{}); +inline constexpr int min_v = range_min(); template -inline constexpr int max_v = range_max(std::make_integer_sequence()>{}); +inline constexpr int max_v = range_max(); template constexpr std::size_t range_size() noexcept {