mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-09 23:34:23 +00:00
parent
07181c5a11
commit
9268bb3042
2 changed files with 41 additions and 29 deletions
|
|
@ -172,12 +172,6 @@ struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};
|
struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};
|
||||||
|
|
||||||
struct char_equal_to {
|
|
||||||
constexpr bool operator()(char lhs, char rhs) const noexcept {
|
|
||||||
return lhs == rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
class static_string {
|
class static_string {
|
||||||
public:
|
public:
|
||||||
|
|
@ -236,6 +230,16 @@ constexpr string_view pretty_name(string_view name) noexcept {
|
||||||
return {}; // Invalid name.
|
return {}; // Invalid name.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename CharType>
|
||||||
|
constexpr auto to_lower([[maybe_unused]] CharType ch) noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<CharType>, char>, char> {
|
||||||
|
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||||
|
static_assert(!std::is_same_v<CharType, CharType>, "magic_enum::detail::to_lower not supported Non-ASCII feature.");
|
||||||
|
return {};
|
||||||
|
#else
|
||||||
|
return 'A' <= ch && ch <= 'Z' ? ch - 'A' + 'a' : ch;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
constexpr std::size_t find(string_view str, char c) noexcept {
|
constexpr std::size_t find(string_view str, char c) noexcept {
|
||||||
#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
|
#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
|
||||||
// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc
|
// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc
|
||||||
|
|
@ -264,7 +268,7 @@ constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N], std::index_sequ
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BinaryPredicate>
|
template <typename BinaryPredicate>
|
||||||
constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) {
|
constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) {
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
|
#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
|
||||||
// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
|
// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
|
||||||
// https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
|
// https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
|
||||||
|
|
@ -272,7 +276,9 @@ constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p)
|
||||||
#else
|
#else
|
||||||
constexpr bool workaround = false;
|
constexpr bool workaround = false;
|
||||||
#endif
|
#endif
|
||||||
constexpr bool custom_predicate = std::negation_v<std::is_same<std::decay_t<BinaryPredicate>, char_equal_to>>;
|
constexpr bool custom_predicate =
|
||||||
|
!std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<char>> &&
|
||||||
|
!std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
|
||||||
|
|
||||||
if constexpr (custom_predicate || workaround) {
|
if constexpr (custom_predicate || workaround) {
|
||||||
if (lhs.size() != rhs.size()) {
|
if (lhs.size() != rhs.size()) {
|
||||||
|
|
@ -288,8 +294,6 @@ constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
static_cast<void>(p);
|
|
||||||
|
|
||||||
return lhs == rhs;
|
return lhs == rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -803,10 +807,21 @@ template <typename E>
|
||||||
return {}; // Invalid value or out of range.
|
return {}; // Invalid value or out of range.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
|
||||||
|
inline constexpr auto case_insensitive = [](auto lhs, auto rhs) noexcept
|
||||||
|
-> std::enable_if_t<std::is_same_v<std::decay_t<decltype(lhs)>, char> && std::is_same_v<std::decay_t<decltype(rhs)>, char>, bool> {
|
||||||
|
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||||
|
static_assert(!std::is_same_v<decltype(lhs), decltype(lhs)>, "magic_enum::case_insensitive not supported Non-ASCII feature.");
|
||||||
|
return {};
|
||||||
|
#else
|
||||||
|
return detail::to_lower(lhs) == detail::to_lower(rhs);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// Obtains enum value from name.
|
// Obtains enum value from name.
|
||||||
// Returns optional with enum value.
|
// Returns optional with enum value.
|
||||||
template <typename E, typename BinaryPredicate>
|
template <typename E, typename BinaryPredicate = std::equal_to<char>>
|
||||||
[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {
|
[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p = {}) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {
|
||||||
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");
|
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_cast requires bool(char, char) invocable predicate.");
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = underlying_type_t<D>;
|
using U = underlying_type_t<D>;
|
||||||
|
|
@ -844,15 +859,6 @@ template <typename E, typename BinaryPredicate>
|
||||||
return {}; // Invalid value or out of range.
|
return {}; // Invalid value or out of range.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtains enum value from name.
|
|
||||||
// Returns optional with enum value.
|
|
||||||
template <typename E>
|
|
||||||
[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t<E, optional<std::decay_t<E>>> {
|
|
||||||
using D = std::decay_t<E>;
|
|
||||||
|
|
||||||
return enum_cast<D>(value, detail::char_equal_to{});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns integer value from enum value.
|
// Returns integer value from enum value.
|
||||||
template <typename E>
|
template <typename E>
|
||||||
[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t<E, underlying_type_t<E>> {
|
[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t<E, underlying_type_t<E>> {
|
||||||
|
|
@ -898,19 +904,13 @@ template <typename E>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether enum contains enumerator with such name.
|
// Checks whether enum contains enumerator with such name.
|
||||||
template <typename E, typename BinaryPredicate>
|
template <typename E, typename BinaryPredicate = std::equal_to<char>>
|
||||||
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> {
|
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>) -> detail::enable_if_enum_t<E, bool> {
|
||||||
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");
|
static_assert(std::is_invocable_r_v<bool, BinaryPredicate, char, char>, "magic_enum::enum_contains requires bool(char, char) invocable predicate.");
|
||||||
|
|
||||||
return enum_cast<std::decay_t<E>>(value, std::move_if_noexcept(p)).has_value();
|
return enum_cast<std::decay_t<E>>(value, std::move_if_noexcept(p)).has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether enum contains enumerator with such name.
|
|
||||||
template <typename E>
|
|
||||||
[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t<E, bool> {
|
|
||||||
return enum_cast<std::decay_t<E>>(value).has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace fusion_detail {
|
namespace fusion_detail {
|
||||||
|
|
||||||
template <typename E>
|
template <typename E>
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,12 @@ TEST_CASE("enum_cast") {
|
||||||
REQUIRE(lang.value() == Language::日本語);
|
REQUIRE(lang.value() == Language::日本語);
|
||||||
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
|
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
|
||||||
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
|
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
|
||||||
|
#else // !defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||||
|
constexpr auto dr2 = enum_cast<Directions>("RIGHT", case_insensitive);
|
||||||
|
REQUIRE(dr2.value() == Directions::Right);
|
||||||
|
REQUIRE(enum_cast<Directions&>("up", case_insensitive).value() == Directions::Up);
|
||||||
|
REQUIRE(enum_cast<const Directions>("dOwN", case_insensitive).value() == Directions::Down);
|
||||||
|
REQUIRE_FALSE(enum_cast<Directions>("Left-", case_insensitive).has_value());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr auto nt = enum_cast<number>("three");
|
constexpr auto nt = enum_cast<number>("three");
|
||||||
|
|
@ -372,6 +378,12 @@ TEST_CASE("enum_contains") {
|
||||||
REQUIRE(enum_contains<const Language>(lang));
|
REQUIRE(enum_contains<const Language>(lang));
|
||||||
REQUIRE(enum_contains<Language>("😃"));
|
REQUIRE(enum_contains<Language>("😃"));
|
||||||
REQUIRE_FALSE(enum_contains<Language>("None"));
|
REQUIRE_FALSE(enum_contains<Language>("None"));
|
||||||
|
#else
|
||||||
|
auto dr2 = std::string{"RIGHT"};
|
||||||
|
REQUIRE(enum_contains<const Directions>(dr2, case_insensitive));
|
||||||
|
REQUIRE(enum_contains<Directions&>("up", case_insensitive));
|
||||||
|
REQUIRE(enum_contains<Directions>("dOwN", case_insensitive));
|
||||||
|
REQUIRE_FALSE(enum_contains<Directions>("Left-", case_insensitive));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr auto nt = enum_contains<number>("three");
|
constexpr auto nt = enum_contains<number>("three");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue