1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-10 23:44:29 +00:00

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).
This commit is contained in:
Alexander Karatarakis 2019-10-14 00:44:42 -07:00 committed by Daniil Goncharov
parent 0f36cd5b0f
commit db4c55c36a

View file

@ -228,29 +228,49 @@ constexpr std::size_t reflected_size() {
return static_cast<std::size_t>(size);
}
template <typename E>
inline constexpr std::size_t reflected_size_v = reflected_size<E>();
template <typename E, int... I>
constexpr int range_min(std::integer_sequence<int, I...>) noexcept {
constexpr std::array<bool, reflected_size_v<E>> reflected_set_v_helper(std::integer_sequence<int, I...>) {
return {{(n<E, static_cast<E>(I + reflected_min_v<E>)>().size() != 0)...}};
}
template<typename E>
inline constexpr std::array<bool, reflected_size_v<E>> reflected_set_v = reflected_set_v_helper<E>(std::make_integer_sequence<int, reflected_size_v<E>>{});
template <typename E>
constexpr int range_min() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::range_min requires enum type.");
int r = 0;
(void)(((n<E, static_cast<E>(I + reflected_min_v<E>)>().size() != 0) ? (r = I + reflected_min_v<E>, false) : true) && ...);
return r;
// Find leftmost value.
for (int i = 0; i < static_cast<int>(reflected_size_v<E>); ++i) {
if (reflected_set_v<E>[i]) {
return i + reflected_min_v<E>;
}
}
return reflected_max_v<E>;
}
template <typename E, int... I>
constexpr int range_max(std::integer_sequence<int, I...>) noexcept {
template <typename E>
constexpr int range_max() noexcept {
static_assert(is_enum_v<E>, "magic_enum::detail::range_max requires enum type.");
int r = 0;
(void)(((n<E, static_cast<E>(reflected_max_v<E> - I)>().size() != 0) ? (r = reflected_max_v<E> - I, false) : true) && ...);
return r;
// Find rightmost value
for (int i = static_cast<int>(reflected_size_v<E>) - 1; i >= 0; --i) {
if (reflected_set_v<E>[i]) {
return i + reflected_min_v<E>;
}
}
return reflected_min_v<E>;
}
template <typename E>
inline constexpr int min_v = range_min<E>(std::make_integer_sequence<int, reflected_size<E>()>{});
inline constexpr int min_v = range_min<E>();
template <typename E>
inline constexpr int max_v = range_max<E>(std::make_integer_sequence<int, reflected_size<E>()>{});
inline constexpr int max_v = range_max<E>();
template <typename E>
constexpr std::size_t range_size() noexcept {