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

Enable wchar_t as string_view value_type (#272)

This commit is contained in:
Daniil Goncharov 2023-05-24 19:05:20 +04:00 committed by GitHub
parent fba99305d2
commit 8f6c9905fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 190 additions and 22 deletions

View file

@ -134,6 +134,23 @@ MAGIC_ENUM_USING_ALIAS_STRING
using std::string;
#endif
using char_type = string_view::value_type;
static_assert(std::is_same_v<string_view::value_type, string::value_type>, "magic_enum::customize requires same string_view::value_type and string::value_type");
static_assert([] {
if constexpr (std::is_same_v<char_type, wchar_t>) {
constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t.");
for (std::size_t i = 0; i < std::size(c); ++i) {
if (c[i] != wc[i]) {
return false;
}
}
}
return true;
} (), "magic_enum::customize wchar_t is not compatible with ASCII.");
namespace customize {
// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.
@ -163,7 +180,7 @@ enum class customize_tag {
class customize_t : public std::pair<detail::customize_tag, string_view> {
public:
constexpr customize_t(string_view srt) : std::pair<detail::customize_tag, string_view>{detail::customize_tag::custom_tag, srt} {}
constexpr customize_t(const char* srt) : customize_t{string_view{srt}} {}
constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {}
constexpr customize_t(detail::customize_tag tag) : std::pair<detail::customize_tag, string_view>{tag, string_view{}} {
assert(tag != detail::customize_tag::custom_tag);
}
@ -186,8 +203,6 @@ constexpr customize_t enum_type_name() noexcept {
return default_tag;
}
static_assert(std::is_same_v<string_view::value_type, string::value_type>, "magic_enum::customize requires same string_view::value_type and string::value_type");
} // namespace magic_enum::customize
namespace detail {
@ -244,7 +259,7 @@ class static_str {
assert(str.size() == N);
}
constexpr const char* data() const noexcept { return chars_; }
constexpr const char_type* data() const noexcept { return chars_; }
constexpr std::uint16_t size() const noexcept { return N; }
@ -252,9 +267,12 @@ class static_str {
private:
template <std::uint16_t... I>
constexpr static_str(const char* str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{str[I]..., '\0'} {}
constexpr static_str(const char* str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{static_cast<char_type>(str[I])..., '\0'} {}
char chars_[static_cast<std::size_t>(N) + 1];
template <std::uint16_t... I>
constexpr static_str(string_view str, std::integer_sequence<std::uint16_t, I...>) noexcept : chars_{str[I]..., '\0'} {}
char_type chars_[static_cast<std::size_t>(N) + 1];
};
template <>
@ -266,7 +284,7 @@ class static_str<0> {
constexpr explicit static_str(string_view) noexcept {}
constexpr const char* data() const noexcept { return nullptr; }
constexpr const char_type* data() const noexcept { return nullptr; }
constexpr std::uint16_t size() const noexcept { return 0; }
@ -275,18 +293,18 @@ class static_str<0> {
template <typename Op = std::equal_to<>>
class case_insensitive {
static constexpr char to_lower(char c) noexcept {
return (c >= 'A' && c <= 'Z') ? static_cast<char>(c + ('a' - 'A')) : c;
static constexpr char_type to_lower(char_type c) noexcept {
return (c >= 'A' && c <= 'Z') ? static_cast<char_type>(c + ('a' - 'A')) : c;
}
public:
template <typename L, typename R>
constexpr auto operator()(L lhs,R rhs) const noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<L>, char> && std::is_same_v<std::decay_t<R>, char>, bool> {
constexpr auto operator()(L lhs,R rhs) const noexcept -> std::enable_if_t<std::is_same_v<std::decay_t<L>, char_type> && std::is_same_v<std::decay_t<R>, char_type>, bool> {
return Op{}(to_lower(lhs), to_lower(rhs));
}
};
constexpr std::size_t find(string_view str, char c) noexcept {
constexpr std::size_t find(string_view str, char_type c) noexcept {
#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://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
@ -317,7 +335,7 @@ constexpr bool is_default_predicate() noexcept {
template <typename BinaryPredicate>
constexpr bool is_nothrow_invocable() {
return is_default_predicate<BinaryPredicate>() ||
std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char, char>;
std::is_nothrow_invocable_r_v<bool, BinaryPredicate, char_type, char_type>;
}
template <typename BinaryPredicate>
@ -785,7 +803,7 @@ struct enable_if_enum<true, R> {
};
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>, typename D = std::decay_t<T>>
using enable_if_t = typename enable_if_enum<std::is_enum_v<D> && std::is_invocable_r_v<bool, BinaryPredicate, char, char>, R>::type;
using enable_if_t = typename enable_if_enum<std::is_enum_v<D> && std::is_invocable_r_v<bool, BinaryPredicate, char_type, char_type>, R>::type;
template <typename T, std::enable_if_t<std::is_enum_v<std::decay_t<T>>, int> = 0>
using enum_concept = T;
@ -1225,7 +1243,7 @@ template <detail::enum_subtype S, typename E>
// Returns name from enum-flags value.
// If enum-flags value does not have name or value out of range, returns empty string.
template <typename E>
[[nodiscard]] auto enum_flags_name(E value, char sep = '|') -> detail::enable_if_t<E, string> {
[[nodiscard]] auto enum_flags_name(E value, char_type sep = '|') -> detail::enable_if_t<E, string> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;

View file

@ -190,7 +190,7 @@ struct name_sort_impl<void, OP> {
struct FullCmp : S {};
template <typename S>
struct FullCmp<S, std::enable_if_t<!std::is_invocable_v<S, string_view, string_view> && std::is_invocable_v<S, char, char>>> {
struct FullCmp<S, std::enable_if_t<!std::is_invocable_v<S, string_view, string_view> && std::is_invocable_v<S, char_type, char_type>>> {
[[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare<S>(s1, s2); }
};
@ -546,7 +546,7 @@ class bitset {
}
}
constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char zero = '0', char one = '1')
constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char_type zero = '0', char_type one = '1')
: a{{}} {
std::size_t i{};
for (auto c : sv.substr(pos, n)) {
@ -562,8 +562,8 @@ class bitset {
}
}
constexpr explicit bitset(detail::raw_access_t, const char* str, std::size_t n = ~std::size_t{}, char zero = '0', char one = '1')
: bitset(std::string_view{str, (std::min)(std::char_traits<char>::length(str), n)}, 0, n, zero, one) {}
constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{}, char_type zero = '0', char_type one = '1')
: bitset(std::string_view{str, (std::min)(std::char_traits<char_type>::length(str), n)}, 0, n, zero, one) {}
constexpr bitset(std::initializer_list<E> starters) : a{{}} {
if constexpr (magic_enum::detail::subtype_v<E> == magic_enum::detail::enum_subtype::flags) {
@ -591,7 +591,7 @@ class bitset {
}
template <typename Cmp = std::equal_to<>>
constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char sep = '|') {
constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char_type sep = '|') {
for (std::size_t to{}; (to = magic_enum::detail::find(sv, sep)) != string_view::npos; sv.remove_prefix(to + 1)) {
if (auto v = enum_cast<E>(sv.substr(0, to), cmp)) {
set(v);
@ -756,7 +756,7 @@ class bitset {
return res;
}
[[nodiscard]] string to_string(char sep = '|') const {
[[nodiscard]] string to_string(char_type sep = '|') const {
string name;
for (auto& e : enum_values<E>()) {
@ -771,7 +771,7 @@ class bitset {
return name;
}
[[nodiscard]] string to_string(detail::raw_access_t, char zero = '0', char one = '1') const {
[[nodiscard]] string to_string(detail::raw_access_t, char_type zero = '0', char_type one = '1') const {
string name;
name.reserve(size());
for (std::size_t i{}; i < size(); ++i) {