1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-10 23:44:29 +00:00
This commit is contained in:
neargye 2022-03-11 16:54:12 +02:00
parent c1568c5b26
commit 718d2601b2

View file

@ -630,19 +630,19 @@ struct constexpr_hash_t;
template <typename Value>
struct constexpr_hash_t<Value, std::enable_if_t<is_enum_v<Value>>> {
constexpr auto operator()(const Value& val) const noexcept {
using type = typename underlying_type<Value>::type;
if constexpr (std::is_same_v<type, bool>) {
return static_cast<std::size_t>(static_cast<bool>(val));
constexpr auto operator()(Value value) const noexcept {
using U = typename underlying_type<Value>::type;
if constexpr (std::is_same_v<U, bool>) {
return static_cast<std::size_t>(static_cast<bool>(value));
} else {
return static_cast<typename underlying_type<Value>::type>(val);
return static_cast<U>(value);
}
}
using secondary_hash = constexpr_hash_t;
};
template <typename Value>
struct constexpr_hash_t<Value, std::enable_if_t<std::is_same_v<Value, std::string_view>>> {
struct constexpr_hash_t<Value, std::enable_if_t<std::is_same_v<Value, string_view>>> {
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<Value, std::enable_if_t<std::is_same_v<Value, std::strin
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
constexpr std::uint32_t operator()(std::string_view val) const noexcept {
std::uint32_t crc = 0xffffffffL;
for (auto c : val)
constexpr std::uint32_t operator()(string_view val) const noexcept {
auto crc = static_cast<std::uint32_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<std::uint64_t>(2166136261ULL)};
for (char v : val) {
constexpr std::uint32_t operator()(string_view val) const noexcept {
auto acc = static_cast<std::uint64_t>(2166136261ULL);
for (const auto v : val) {
acc = ((acc ^ static_cast<std::uint64_t>(v)) * static_cast<std::uint64_t>(16777619ULL)) & std::numeric_limits<std::uint32_t>::max();
}
return static_cast<std::uint32_t>(acc);
@ -709,22 +710,25 @@ constexpr auto calculate_cases(std::size_t page) {
std::array<SwitchType, 256> 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<Hash>(*first++);
}
// dead cases, try to avoid case collisions
for (SwitchType last_value = result[values_to-1];
fill != result.end() && last_value != (std::numeric_limits<SwitchType>::max)(); *fill++ = ++last_value);
for (SwitchType last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits<SwitchType>::max)(); *fill++ = ++last_value) {
}
auto it = result.begin();
for (auto last_value = (std::numeric_limits<SwitchType>::min)(); fill != result.end(); *fill++ = last_value)
while (last_value == *it)
for (auto last_value = (std::numeric_limits<SwitchType>::min)(); fill != result.end(); *fill++ = last_value) {
while (last_value == *it) {
++last_value, ++it;
}
}
return result;
}
template< class R, class F, class... Args >
template <typename R, typename F, typename... Args >
constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
if constexpr (std::is_void_v<R>) {
std::forward<F>(f)(std::forward<Args>(args)...);
@ -739,6 +743,7 @@ enum class case_call_t {
template <typename DefaultResultType = void>
constexpr auto default_result_type_lambda = [] { return DefaultResultType{}; };
template <>
constexpr auto default_result_type_lambda<void> = [] {};
@ -747,17 +752,19 @@ constexpr bool no_duplicate() {
using value_t = std::decay_t<decltype((*Arr)[0])>;
using hash_value_t = std::invoke_result_t<Hash, value_t>;
std::array<hash_value_t, Arr->size()> hashes{};
std::size_t size{};
std::size_t size = 0;
for (auto elem : *Arr) {
hashes[size] = hash_v<Hash>(elem);
for (auto i = size++; i > 0; --i) {
if (hashes[i] < hashes[i - 1]) {
hash_value_t tmp = hashes[i];
auto tmp = hashes[i];
hashes[i] = hashes[i - 1];
hashes[i - 1] = tmp;
} else if (hashes[i] == hashes[i-1])
} else if (hashes[i] == hashes[i - 1]) {
return false;
else break;
} else {
break;
}
}
}
return true;
@ -777,26 +784,24 @@ constexpr bool no_duplicate() {
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<result_t, Lambda, std::integral_constant<std::size_t, val + page>>) \
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), \
std::integral_constant<std::size_t, val + page>{}); \
else if constexpr (call_v == case_call_t::value && \
std::is_invocable_r_v<result_t, Lambda, std::integral_constant<value_t, values[val + page]>>) \
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), \
std::integral_constant<value_t, values[val + page]>{}); \
if constexpr (call_v == case_call_t::index && std::is_invocable_r_v<result_t, Lambda, std::integral_constant<std::size_t, val + page>>) \
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + page>{}); \
else if constexpr (call_v == case_call_t::value && std::is_invocable_r_v<result_t, Lambda, std::integral_constant<value_t, values[val + page]>>) \
return detail::invoke_r<result_t>(std::forward<Lambda>(lambda), std::integral_constant<value_t, values[val + page]>{}); \
break; \
} else [[fallthrough]];
template<auto* globValues, case_call_t call_v, std::size_t page = 0,
template <auto* globValues,
case_call_t call_v,
std::size_t page = 0,
typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*globValues)>::value_type>,
typename Lambda, typename ResultGetterType = decltype(default_result_type_lambda<>),
typename BinaryPredicate = std::equal_to<>>
static constexpr auto constexpr_switch(Lambda&& lambda,
constexpr std::invoke_result_t<ResultGetterType> constexpr_switch(
Lambda&& lambda,
typename std::decay_t<decltype(*globValues)>::value_type searched,
ResultGetterType&& def = default_result_type_lambda<>,
BinaryPredicate&& pred = {})
-> std::invoke_result_t<ResultGetterType> {
BinaryPredicate&& pred = {}) {
using result_t = std::invoke_result_t<ResultGetterType>;
using value_t = typename std::decay_t<decltype(*globValues)>::value_type;
using hash_t = std::conditional_t<no_duplicate<globValues, Hash>(), 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<globValues, call_v, page + 256, Hash>(std::forward<Lambda>(lambda),
searched, std::forward<ResultGetterType>(def));
return constexpr_switch<globValues, call_v, page + 256, Hash>(std::forward<Lambda>(lambda), searched, std::forward<ResultGetterType>(def));
}
break;
}
@ -913,7 +917,8 @@ template <typename E>
if constexpr (detail::is_sparse_v<D> || detail::is_flags_v<D>) {
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::index>(
[](std::size_t index) { return optional<std::size_t>{index}; },
value, detail::default_result_type_lambda<optional<std::size_t>>);
value,
detail::default_result_type_lambda<optional<std::size_t>>);
} else {
const auto v = static_cast<U>(value);
if (v >= detail::min_v<D> && v <= detail::max_v<D>) {
@ -938,8 +943,9 @@ template <auto V>
template <typename E>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, string_view> {
using D = std::decay_t<E>;
if (auto index = enum_index(value))
if (const auto index = enum_index(value); index.has_value()) {
return detail::names_v<D>[*index];
}
return {};
}
@ -989,7 +995,7 @@ template <typename E>
// Obtains enum value from integer value.
// Returns optional with enum value.
template <typename E>
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<std::decay_t<E>> value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
@ -1009,7 +1015,9 @@ template <typename E>
return {}; // Invalid value or out of range.
} else {
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
[](D value) { return optional<D>{value}; }, static_cast<D>(value), detail::default_result_type_lambda<optional<D>>);
[](D value) { return optional<D>{value}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
}
} else {
constexpr auto min = detail::min_v<D>;
@ -1063,9 +1071,9 @@ template <typename E, typename BinaryPredicate = std::equal_to<char>>
if constexpr (default_predicate) {
return detail::constexpr_switch<&detail::names_v<D>, detail::case_call_t::index>(
[](std::size_t index) { return optional<D>{detail::values_v<D>[index]}; },
value, detail::default_result_type_lambda<optional<D>>, [&p](std::string_view lhs, std::string_view rhs) {
return detail::cmp_equal(lhs, rhs, p);
});
value,
detail::default_result_type_lambda<optional<D>>,
[&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<D>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D>[i], p)) {