diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 377a82c..7dd6526 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -625,24 +625,24 @@ struct underlying_type {}; template struct underlying_type : std::underlying_type> {}; -template +template struct constexpr_hash_t; -template +template struct constexpr_hash_t>> { - constexpr auto operator()(const Value& val) const noexcept { - using type = typename underlying_type::type; - if constexpr (std::is_same_v) { - return static_cast(static_cast(val)); + constexpr auto operator()(Value value) const noexcept { + using U = typename underlying_type::type; + if constexpr (std::is_same_v) { + return static_cast(static_cast(value)); } else { - return static_cast::type>(val); + return static_cast(value); } } using secondary_hash = constexpr_hash_t; }; -template -struct constexpr_hash_t>> { +template +struct constexpr_hash_t>> { static constexpr std::uint32_t crc_table[256] { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, @@ -677,17 +677,18 @@ struct constexpr_hash_t(0xffffffffL); + for (const auto c : val) { crc = (crc >> 8) ^ crc_table[(crc ^ c) & 0xff]; + } return crc ^ 0xffffffffL; } struct secondary_hash { - constexpr std::uint32_t operator()(std::string_view val) const noexcept { - auto acc {static_cast(2166136261ULL)}; - for (char v : val) { + constexpr std::uint32_t operator()(string_view val) const noexcept { + auto acc = static_cast(2166136261ULL); + for (const auto v : val) { acc = ((acc ^ static_cast(v)) * static_cast(16777619ULL)) & std::numeric_limits::max(); } return static_cast(acc); @@ -695,7 +696,7 @@ struct constexpr_hash_t +template constexpr static Hash hash_v{}; template @@ -709,23 +710,26 @@ constexpr auto calculate_cases(std::size_t page) { std::array result{}; auto fill = result.begin(); - for (auto first = values.begin() + page, last = values.begin() + page + values_to; first != last; ) + for (auto first = values.begin() + page, last = values.begin() + page + values_to; first != last; ) { *fill++ = hash_v(*first++); + } // dead cases, try to avoid case collisions - for (SwitchType last_value = result[values_to-1]; - fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value); + for (SwitchType last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value) { + } auto it = result.begin(); - for (auto last_value = (std::numeric_limits::min)(); fill != result.end(); *fill++ = last_value) - while (last_value == *it) + for (auto last_value = (std::numeric_limits::min)(); fill != result.end(); *fill++ = last_value) { + while (last_value == *it) { ++last_value, ++it; + } + } return result; } -template< class R, class F, class... Args > -constexpr R invoke_r( F&& f, Args&&... args ) noexcept(std::is_nothrow_invocable_r_v) { +template +constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { if constexpr (std::is_void_v) { std::forward(f)(std::forward(args)...); } else { @@ -737,27 +741,30 @@ enum class case_call_t { index, value }; -template +template constexpr auto default_result_type_lambda = [] { return DefaultResultType{}; }; -template<> + +template <> constexpr auto default_result_type_lambda = [] {}; -template +template constexpr bool no_duplicate() { using value_t = std::decay_t; using hash_value_t = std::invoke_result_t; std::arraysize()> hashes{}; - std::size_t size{}; + std::size_t size = 0; for (auto elem : *Arr) { hashes[size] = hash_v(elem); for (auto i = size++; i > 0; --i) { - if (hashes[i] < hashes[i-1]) { - hash_value_t tmp = hashes[i]; - hashes[i] = hashes[i-1]; - hashes[i-1] = tmp; - } else if (hashes[i] == hashes[i-1]) - return false; - else break; + if (hashes[i] < hashes[i - 1]) { + auto tmp = hashes[i]; + hashes[i] = hashes[i - 1]; + hashes[i - 1] = tmp; + } else if (hashes[i] == hashes[i - 1]) { + return false; + } else { + break; + } } } return true; @@ -772,31 +779,29 @@ constexpr bool no_duplicate() { T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \ T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255) -#define MAGIC_ENUM_CASE(val) \ - case cases[val]: \ - if constexpr ((val) + page < size) { \ - if (!pred(values[val + page], searched)) \ - break; \ - if constexpr (call_v == case_call_t::index && \ - std::is_invocable_r_v>) \ - return detail::invoke_r(std::forward(lambda), \ - std::integral_constant{}); \ - else if constexpr (call_v == case_call_t::value && \ - std::is_invocable_r_v>) \ - return detail::invoke_r(std::forward(lambda), \ - std::integral_constant{}); \ - break; \ +#define MAGIC_ENUM_CASE(val) \ + case cases[val]: \ + if constexpr ((val) + page < size) { \ + if (!pred(values[val + page], searched)) \ + break; \ + if constexpr (call_v == case_call_t::index && std::is_invocable_r_v>) \ + return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ + else if constexpr (call_v == case_call_t::value && std::is_invocable_r_v>) \ + return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ + break; \ } else [[fallthrough]]; -template::value_type>, - typename Lambda, typename ResultGetterType = decltype(default_result_type_lambda<>), - typename BinaryPredicate = std::equal_to<>> -static constexpr auto constexpr_switch(Lambda&& lambda, - typename std::decay_t::value_type searched, - ResultGetterType&& def = default_result_type_lambda<>, - BinaryPredicate&& pred = {}) - -> std::invoke_result_t { +template ::value_type>, + typename Lambda, typename ResultGetterType = decltype(default_result_type_lambda<>), + typename BinaryPredicate = std::equal_to<>> +constexpr std::invoke_result_t constexpr_switch( + Lambda&& lambda, + typename std::decay_t::value_type searched, + ResultGetterType&& def = default_result_type_lambda<>, + BinaryPredicate&& pred = {}) { using result_t = std::invoke_result_t; using value_t = typename std::decay_t::value_type; using hash_t = std::conditional_t(), Hash, typename Hash::secondary_hash>; @@ -808,8 +813,7 @@ static constexpr auto constexpr_switch(Lambda&& lambda, MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE) default: if constexpr (size > 256 + page) { - return constexpr_switch(std::forward(lambda), - searched, std::forward(def)); + return constexpr_switch(std::forward(lambda), searched, std::forward(def)); } break; } @@ -912,8 +916,9 @@ template if constexpr (detail::is_sparse_v || detail::is_flags_v) { return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( - [](std::size_t index) { return optional{index}; }, - value, detail::default_result_type_lambda>); + [](std::size_t index) { return optional{index}; }, + value, + detail::default_result_type_lambda>); } else { const auto v = static_cast(value); if (v >= detail::min_v && v <= detail::max_v) { @@ -938,8 +943,9 @@ template template [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { using D = std::decay_t; - if (auto index = enum_index(value)) + if (const auto index = enum_index(value); index.has_value()) { return detail::names_v[*index]; + } return {}; } @@ -989,7 +995,7 @@ template // Obtains enum value from integer value. // Returns optional with enum value. template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t> value) noexcept -> detail::enable_if_enum_t>> { +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { using D = std::decay_t; using U = underlying_type_t; @@ -1009,7 +1015,9 @@ template return {}; // Invalid value or out of range. } else { return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( - [](D value) { return optional{value}; }, static_cast(value), detail::default_result_type_lambda>); + [](D value) { return optional{value}; }, + static_cast(value), + detail::default_result_type_lambda>); } } else { constexpr auto min = detail::min_v; @@ -1062,10 +1070,10 @@ template > std::is_same_v, std::equal_to<>>; if constexpr (default_predicate) { return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( - [](std::size_t index) { return optional{detail::values_v[index]}; }, - value, detail::default_result_type_lambda>, [&p](std::string_view lhs, std::string_view rhs) { - return detail::cmp_equal(lhs, rhs, p); - }); + [](std::size_t index) { return optional{detail::values_v[index]}; }, + value, + detail::default_result_type_lambda>, + [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); } else { for (std::size_t i = 0; i < detail::count_v; ++i) { if (detail::cmp_equal(value, detail::names_v[i], p)) {