mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-08 23:24:20 +00:00
add support big range (#268)
* add support big range * remove string_view from n() * fix containers
This commit is contained in:
parent
4c54c094ea
commit
629f7b09af
10 changed files with 601 additions and 784 deletions
|
|
@ -1,27 +0,0 @@
|
|||
load("@rules_cc//cc:defs.bzl", "cc_binary")
|
||||
load("@magic_enum//bazel:copts.bzl", "COPTS")
|
||||
|
||||
_EXAMPLES = [
|
||||
"enum_flag_example",
|
||||
"example",
|
||||
#"example_containers_array", TODO
|
||||
#"example_containers_bitset", TODO
|
||||
#"example_containers_set", TODO
|
||||
"example_custom_name",
|
||||
"example_switch",
|
||||
]
|
||||
|
||||
[cc_binary(
|
||||
name = example,
|
||||
srcs = ["{}.cpp".format(example)],
|
||||
deps = ["@magic_enum"],
|
||||
copts = COPTS,
|
||||
) for example in _EXAMPLES]
|
||||
|
||||
cc_binary(
|
||||
name = "example_nonascii_name",
|
||||
srcs = ["example_nonascii_name.cpp"],
|
||||
deps = ["@magic_enum"],
|
||||
copts = COPTS,
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
|
@ -20,9 +20,9 @@ endfunction()
|
|||
|
||||
make_example(example)
|
||||
make_example(enum_flag_example)
|
||||
#make_example(example_containers_array) TODO
|
||||
#make_example(example_containers_bitset) TODO
|
||||
#make_example(example_containers_set) TODO
|
||||
make_example(example_containers_array)
|
||||
make_example(example_containers_bitset)
|
||||
make_example(example_containers_set)
|
||||
make_example(example_custom_name)
|
||||
make_example(example_switch)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
#include <magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
struct RGB {
|
||||
|
||||
|
|
@ -37,7 +41,6 @@ struct RGB {
|
|||
[[nodiscard]] constexpr bool operator==(RGB rgb) const noexcept { return std::equal_to{}(r, rgb.r) && std::equal_to{}(g, rgb.g) && std::equal_to{}(b, rgb.b); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& ostream, RGB rgb) {
|
||||
|
||||
ostream << "R=" << static_cast<std::uint32_t>(rgb.r) << " G=" << static_cast<std::uint32_t>(rgb.g) << " B=" << static_cast<std::uint32_t>(rgb.b);
|
||||
return ostream;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@
|
|||
#include <magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@
|
|||
#include <magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 26495) // Variable 'static_string<N>::chars_' is uninitialized.
|
||||
# pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
|
||||
# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value.
|
||||
# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
|
||||
# pragma warning(disable : 4514) // Unreferenced inline function has been removed.
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128.
|
||||
// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX.
|
||||
#if !defined(MAGIC_ENUM_RANGE_MAX)
|
||||
# define MAGIC_ENUM_RANGE_MAX 128
|
||||
# define MAGIC_ENUM_RANGE_MAX 127
|
||||
#endif
|
||||
|
||||
// Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations.
|
||||
|
|
@ -224,10 +224,23 @@ struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
|
|||
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 str_view {
|
||||
const char* str_ = nullptr;
|
||||
std::size_t size_ = 0;
|
||||
|
||||
constexpr const char* data() const noexcept { return str_; }
|
||||
|
||||
constexpr std::size_t size() const noexcept { return size_; }
|
||||
};
|
||||
|
||||
template <std::uint16_t N>
|
||||
class static_string {
|
||||
class static_str {
|
||||
public:
|
||||
constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_integer_sequence<std::uint16_t, N>{}} {
|
||||
constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence<std::uint16_t, N>{}} {
|
||||
assert(str.size() == N);
|
||||
}
|
||||
|
||||
constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence<std::uint16_t, N>{}} {
|
||||
assert(str.size() == N);
|
||||
}
|
||||
|
||||
|
|
@ -239,17 +252,19 @@ class static_string {
|
|||
|
||||
private:
|
||||
template <std::uint16_t... I>
|
||||
constexpr static_string(string_view 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_{str[I]..., '\0'} {}
|
||||
|
||||
char chars_[static_cast<std::size_t>(N) + 1];
|
||||
};
|
||||
|
||||
template <>
|
||||
class static_string<0> {
|
||||
class static_str<0> {
|
||||
public:
|
||||
constexpr explicit static_string() = default;
|
||||
constexpr explicit static_str() = default;
|
||||
|
||||
constexpr explicit static_string(string_view) noexcept {}
|
||||
constexpr explicit static_str(str_view) noexcept {}
|
||||
|
||||
constexpr explicit static_str(string_view) noexcept {}
|
||||
|
||||
constexpr const char* data() const noexcept { return nullptr; }
|
||||
|
||||
|
|
@ -386,44 +401,42 @@ constexpr auto n() noexcept {
|
|||
if constexpr (supported<E>::value) {
|
||||
#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN)
|
||||
constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
|
||||
constexpr auto name = name_ptr ? string_view{name_ptr} : string_view{};
|
||||
constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
|
||||
#elif defined(__clang__)
|
||||
auto name = string_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
#elif defined(__GNUC__)
|
||||
auto name = string_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name[name.size() - 1] == ']') {
|
||||
name.remove_suffix(1);
|
||||
name.remove_prefix(49);
|
||||
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name.str_[name.size_ - 1] == ']') {
|
||||
name.size_ -= 50;
|
||||
name.str_ += 49;
|
||||
} else {
|
||||
name.remove_suffix(3);
|
||||
name.remove_prefix(37);
|
||||
name.size_ -= 40;
|
||||
name.str_ += 37;
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
auto name = string_view{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57};
|
||||
auto name = str_view{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57};
|
||||
#else
|
||||
auto name = string_view{};
|
||||
auto name = str_view{};
|
||||
#endif
|
||||
return name;
|
||||
} else {
|
||||
return string_view{}; // Unsupported compiler or Invalid customize.
|
||||
return str_view{}; // Unsupported compiler or Invalid customize.
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr auto type_name() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::type_name requires enum type.");
|
||||
|
||||
[[maybe_unused]] constexpr auto custom = customize::enum_type_name<E>();
|
||||
static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
|
||||
if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
|
||||
constexpr auto name = custom.second;
|
||||
static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
|
||||
return static_string<name.size()>{name};
|
||||
return static_str<name.size()>{name};
|
||||
} else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
|
||||
return static_string<0>{};
|
||||
return static_str<0>{};
|
||||
} else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
|
||||
constexpr auto name = n<E>();
|
||||
return static_string<name.size()>{name};
|
||||
return static_str<name.size()>{name};
|
||||
} else {
|
||||
static_assert(always_false_v<E>, "magic_enum::customize invalid.");
|
||||
}
|
||||
|
|
@ -439,65 +452,66 @@ constexpr auto n() noexcept {
|
|||
if constexpr (supported<decltype(V)>::value) {
|
||||
#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
|
||||
constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
|
||||
constexpr auto name = name_ptr ? string_view{name_ptr} : string_view{};
|
||||
constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
|
||||
#elif defined(__clang__)
|
||||
auto name = string_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
if (name[0] == '(' || name[0] == '-' || (name[0] >= '0' && name[0] <= '9')) {
|
||||
name = string_view{};
|
||||
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
|
||||
name = str_view{};;
|
||||
}
|
||||
constexpr auto prefix = n<decltype(V)>().size();
|
||||
if (name.size() > prefix && name[prefix] == ':') {
|
||||
name.remove_prefix(prefix + 2);
|
||||
if (name.size_ > prefix && name.str_[prefix] == ':') {
|
||||
name.size_ -= (prefix + 2);
|
||||
name.str_ += (prefix + 2);
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
auto name = string_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name[name.size() - 1] == ']') {
|
||||
name.remove_suffix(1);
|
||||
name.remove_prefix(54);
|
||||
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name.str_[name.size_ - 1] == ']') {
|
||||
name.size_ -= 55;
|
||||
name.str_ += 54;
|
||||
} else {
|
||||
name.remove_suffix(3);
|
||||
name.remove_prefix(37);
|
||||
name.size_ -= 40;
|
||||
name.str_ += 37;
|
||||
}
|
||||
if (name[0] == '(') {
|
||||
name = string_view{};
|
||||
if (name.str_[0] == '(') {
|
||||
name = str_view{};
|
||||
}
|
||||
constexpr auto prefix = n<decltype(V)>().size();
|
||||
if (name.size() > prefix && name[prefix] == ':') {
|
||||
name.remove_prefix(prefix + 2);
|
||||
if (name.size_ > prefix && name.str_[prefix] == ':') {
|
||||
name.size_ -= (prefix + 2);
|
||||
name.str_ += (prefix + 2);
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
string_view name;
|
||||
str_view name;
|
||||
if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) {
|
||||
name = string_view{__FUNCSIG__ + 35, sizeof(__FUNCSIG__) - 52};
|
||||
name = str_view{__FUNCSIG__ + 35, sizeof(__FUNCSIG__) - 52};
|
||||
constexpr auto prefix = n<decltype(V)>().size();
|
||||
if (name.size() > prefix && name[prefix] == ':') {
|
||||
name.remove_prefix(prefix + 2);
|
||||
if (name.size_ > prefix && name.str_[prefix] == ':') {
|
||||
name.size_ -= (prefix + 2);
|
||||
name.str_ += (prefix + 2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
auto name = string_view{};
|
||||
auto name = str_view{};
|
||||
#endif
|
||||
return name;
|
||||
} else {
|
||||
return string_view{}; // Unsupported compiler or Invalid customize.
|
||||
return str_view{}; // Unsupported compiler or Invalid customize.
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, E V>
|
||||
constexpr auto enum_name() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::enum_name requires enum type.");
|
||||
|
||||
[[maybe_unused]] constexpr auto custom = customize::enum_name<E>(V);
|
||||
static_assert(std::is_same_v<std::decay_t<decltype(custom)>, customize::customize_t>, "magic_enum::customize requires customize_t type.");
|
||||
if constexpr (custom.first == customize::detail::customize_tag::custom_tag) {
|
||||
constexpr auto name = custom.second;
|
||||
static_assert(!name.empty(), "magic_enum::customize requires not empty string.");
|
||||
return static_string<name.size()>{name};
|
||||
return static_str<name.size()>{name};
|
||||
} else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) {
|
||||
return static_string<0>{};
|
||||
return static_str<0>{};
|
||||
} else if constexpr (custom.first == customize::detail::customize_tag::default_tag) {
|
||||
constexpr auto name = n<V>();
|
||||
return static_string<name.size()>{name};
|
||||
return static_str<name.size()>{name};
|
||||
} else {
|
||||
static_assert(always_false_v<E>, "magic_enum::customize invalid.");
|
||||
}
|
||||
|
|
@ -508,8 +522,6 @@ inline constexpr auto enum_name_v = enum_name<E, V>();
|
|||
|
||||
template <typename E, auto V>
|
||||
constexpr bool is_valid() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::is_valid requires enum type.");
|
||||
|
||||
#if defined(__clang__) && __clang_major__ >= 16 && 0
|
||||
// https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307
|
||||
constexpr E v = __builtin_bit_cast(E, V);
|
||||
|
|
@ -536,8 +548,6 @@ enum class enum_subtype {
|
|||
|
||||
template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr U ualue(std::size_t i) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::ualue requires enum type.");
|
||||
|
||||
if constexpr (std::is_same_v<U, bool>) { // bool special case
|
||||
static_assert(O == 0, "magic_enum::detail::ualue requires valid offset.");
|
||||
|
||||
|
|
@ -551,15 +561,11 @@ constexpr U ualue(std::size_t i) noexcept {
|
|||
|
||||
template <typename E, int O, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr E value(std::size_t i) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::value requires enum type.");
|
||||
|
||||
return static_cast<E>(ualue<E, O, S>(i));
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr int reflected_min() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::reflected_min requires enum type.");
|
||||
|
||||
if constexpr (S == enum_subtype::flags) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -576,8 +582,6 @@ constexpr int reflected_min() noexcept {
|
|||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr int reflected_max() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::reflected_max requires enum type.");
|
||||
|
||||
if constexpr (S == enum_subtype::flags) {
|
||||
return std::numeric_limits<U>::digits - 1;
|
||||
} else {
|
||||
|
|
@ -592,39 +596,66 @@ constexpr int reflected_max() noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr std::size_t values_count(const bool (&valid)[N]) noexcept {
|
||||
auto count = std::size_t{0};
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if (valid[i]) {
|
||||
++count;
|
||||
}
|
||||
#define MAGIC_ENUM_FOR_EACH_256(T) \
|
||||
T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \
|
||||
T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \
|
||||
T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \
|
||||
T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \
|
||||
T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \
|
||||
T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \
|
||||
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)
|
||||
|
||||
template <typename E, enum_subtype S, std::size_t Size, int Min, std::size_t I>
|
||||
constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
|
||||
#define MAGIC_ENUM_V(O) \
|
||||
if constexpr ((I + O) < Size) { \
|
||||
if constexpr (is_valid<E, ualue<E, Min, S>(I + O)>()) { \
|
||||
valid[I + O] = true; \
|
||||
++count; \
|
||||
} \
|
||||
}
|
||||
|
||||
return count;
|
||||
MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V);
|
||||
|
||||
if constexpr ((I + 256) < Size) {
|
||||
valid_count<E, S, Size, Min, I + 256>(valid, count);
|
||||
}
|
||||
#undef MAGIC_ENUM_V
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, int Min, std::size_t... I>
|
||||
constexpr auto values(std::index_sequence<I...>) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");
|
||||
constexpr bool valid[sizeof...(I)] = {is_valid<E, ualue<E, Min, S>(I)>()...};
|
||||
constexpr std::size_t count = values_count(valid);
|
||||
template <std::size_t N>
|
||||
struct valid_count_t {
|
||||
std::size_t count = 0;
|
||||
bool valid[N] = {};
|
||||
};
|
||||
|
||||
if constexpr (count > 0) {
|
||||
template <typename E, enum_subtype S, std::size_t Size, int Min>
|
||||
constexpr auto valid_count() noexcept {
|
||||
valid_count_t<Size> vc;
|
||||
valid_count<E, S, Size, Min, 0>(vc.valid, vc.count);
|
||||
return vc;
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, std::size_t Size, int Min>
|
||||
constexpr auto values() noexcept {
|
||||
constexpr auto vc = valid_count<E, S, Size, Min>();
|
||||
|
||||
if constexpr (vc.count > 0) {
|
||||
#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
|
||||
std::array<E, count> values = {};
|
||||
std::array<E, vc.count> values = {};
|
||||
#else
|
||||
E values[count] = {};
|
||||
E values[vc.count] = {};
|
||||
#endif
|
||||
for (std::size_t i = 0, v = 0; v < count; ++i) {
|
||||
if (valid[i]) {
|
||||
for (std::size_t i = 0, v = 0; v < vc.count; ++i) {
|
||||
if (vc.valid[i]) {
|
||||
values[v++] = value<E, Min, S>(i);
|
||||
}
|
||||
}
|
||||
#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR)
|
||||
return values;
|
||||
#else
|
||||
return to_array(values, std::make_index_sequence<count>{});
|
||||
return to_array(values, std::make_index_sequence<vc.count>{});
|
||||
#endif
|
||||
} else {
|
||||
return std::array<E, 0>{};
|
||||
|
|
@ -633,20 +664,17 @@ constexpr auto values(std::index_sequence<I...>) noexcept {
|
|||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr auto values() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::values requires enum type.");
|
||||
constexpr auto min = reflected_min<E, S>();
|
||||
constexpr auto max = reflected_max<E, S>();
|
||||
constexpr auto range_size = max - min + 1;
|
||||
static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
|
||||
static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");
|
||||
|
||||
return values<E, S, min>(std::make_index_sequence<range_size>{});
|
||||
return values<E, S, range_size, min>();
|
||||
}
|
||||
|
||||
template <typename E, typename U = std::underlying_type_t<E>>
|
||||
constexpr enum_subtype subtype() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::subtype requires enum type.");
|
||||
|
||||
constexpr enum_subtype subtype(std::true_type) noexcept {
|
||||
if constexpr (std::is_same_v<U, bool>) { // bool special case
|
||||
return enum_subtype::common;
|
||||
} else if constexpr (has_is_flags<E>::value) {
|
||||
|
|
@ -671,8 +699,14 @@ constexpr enum_subtype subtype() noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline constexpr auto subtype_v = subtype<E>();
|
||||
template <typename T>
|
||||
constexpr enum_subtype subtype(std::false_type) noexcept {
|
||||
// For non-enum type return default common subtype.
|
||||
return enum_subtype::common;
|
||||
}
|
||||
|
||||
template <typename E, typename D = std::decay_t<E>>
|
||||
inline constexpr auto subtype_v = subtype<D>(std::is_enum<D>{});
|
||||
|
||||
template <typename E, enum_subtype S>
|
||||
inline constexpr auto values_v = values<E, S>();
|
||||
|
|
@ -691,8 +725,6 @@ inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S
|
|||
|
||||
template <typename E, enum_subtype S, std::size_t... I>
|
||||
constexpr auto names(std::index_sequence<I...>) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::names requires enum type.");
|
||||
|
||||
return std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
|
||||
}
|
||||
|
||||
|
|
@ -704,8 +736,6 @@ using names_t = decltype((names_v<D, S>));
|
|||
|
||||
template <typename E, enum_subtype S, std::size_t... I>
|
||||
constexpr auto entries(std::index_sequence<I...>) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::entries requires enum type.");
|
||||
|
||||
return std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
|
||||
}
|
||||
|
||||
|
|
@ -717,8 +747,6 @@ using entries_t = decltype((entries_v<D, S>));
|
|||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr bool is_sparse() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::is_sparse requires enum type.");
|
||||
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return false;
|
||||
} else if constexpr (std::is_same_v<U, bool>) { // bool special case
|
||||
|
|
@ -737,7 +765,6 @@ inline constexpr bool is_sparse_v = is_sparse<E, S>();
|
|||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr U values_ors() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::values_ors requires enum type.");
|
||||
static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype.");
|
||||
|
||||
auto ors = U{0};
|
||||
|
|
@ -939,15 +966,6 @@ constexpr bool has_duplicate() noexcept {
|
|||
return true;
|
||||
}
|
||||
|
||||
#define MAGIC_ENUM_FOR_EACH_256(T) T(0)T(1)T(2)T(3)T(4)T(5)T(6)T(7)T(8)T(9)T(10)T(11)T(12)T(13)T(14)T(15)T(16)T(17)T(18)T(19)T(20)T(21)T(22)T(23)T(24)T(25)T(26)T(27)T(28)T(29)T(30)T(31) \
|
||||
T(32)T(33)T(34)T(35)T(36)T(37)T(38)T(39)T(40)T(41)T(42)T(43)T(44)T(45)T(46)T(47)T(48)T(49)T(50)T(51)T(52)T(53)T(54)T(55)T(56)T(57)T(58)T(59)T(60)T(61)T(62)T(63) \
|
||||
T(64)T(65)T(66)T(67)T(68)T(69)T(70)T(71)T(72)T(73)T(74)T(75)T(76)T(77)T(78)T(79)T(80)T(81)T(82)T(83)T(84)T(85)T(86)T(87)T(88)T(89)T(90)T(91)T(92)T(93)T(94)T(95) \
|
||||
T(96)T(97)T(98)T(99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \
|
||||
T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \
|
||||
T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \
|
||||
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) { \
|
||||
|
|
@ -1000,7 +1018,6 @@ constexpr decltype(auto) constexpr_switch(
|
|||
return def();
|
||||
}
|
||||
|
||||
#undef MAGIC_ENUM_FOR_EACH_256
|
||||
#undef MAGIC_ENUM_CASE
|
||||
|
||||
#else
|
||||
|
|
@ -1010,7 +1027,6 @@ inline constexpr bool has_hash = false;
|
|||
|
||||
template <typename E, enum_subtype S, typename F, std::size_t... I>
|
||||
constexpr auto for_each(F&& f, std::index_sequence<I...>) {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::for_each requires enum type.");
|
||||
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> || ...);
|
||||
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[0]>>, std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> && ...);
|
||||
|
||||
|
|
@ -1025,8 +1041,6 @@ constexpr auto for_each(F&& f, std::index_sequence<I...>) {
|
|||
|
||||
template <typename E, enum_subtype S, typename F,std::size_t... I>
|
||||
constexpr bool all_invocable(std::index_sequence<I...>) {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::all_invocable requires enum type.");
|
||||
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -1079,14 +1093,14 @@ template <typename E>
|
|||
}
|
||||
|
||||
// Returns number of enum values.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t<E, std::size_t> {
|
||||
return detail::count_v<std::decay_t<E>, S>;
|
||||
}
|
||||
|
||||
// Returns enum value at specified index.
|
||||
// No bounds checking is performed: the behavior is undefined if index >= number of enum values.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1100,7 +1114,7 @@ template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
|||
}
|
||||
|
||||
// Returns enum value at specified index.
|
||||
template <typename E, std::size_t I, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, std::size_t I, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");
|
||||
|
|
@ -1109,7 +1123,7 @@ template <typename E, std::size_t I, auto S = detail::subtype_v<std::decay_t<E>>
|
|||
}
|
||||
|
||||
// Returns std::array with enum values, sorted by enum value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
|
||||
return detail::values_v<std::decay_t<E>, S>;
|
||||
}
|
||||
|
|
@ -1128,7 +1142,7 @@ template <typename E>
|
|||
|
||||
// Obtains index in enum values from enum value.
|
||||
// Returns optional with index.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
|
|
@ -1189,7 +1203,7 @@ template <auto V>
|
|||
|
||||
// Returns name from enum value.
|
||||
// If enum value does not have name or value out of range, returns empty string.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1236,13 +1250,13 @@ template <typename E>
|
|||
}
|
||||
|
||||
// Returns std::array with names, sorted by enum value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
|
||||
return detail::names_v<std::decay_t<E>, S>;
|
||||
}
|
||||
|
||||
// Returns std::array with pairs (value, name), sorted by enum value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
|
||||
return detail::entries_v<std::decay_t<E>, S>;
|
||||
}
|
||||
|
|
@ -1252,7 +1266,7 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{};
|
|||
|
||||
// Obtains enum value from integer value.
|
||||
// Returns optional with enum value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1320,7 +1334,7 @@ template <typename E>
|
|||
|
||||
// Obtains enum value from name.
|
||||
// Returns optional with enum value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename BinaryPredicate = std::equal_to<>>
|
||||
template <typename E, auto S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
|
||||
[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1387,7 +1401,7 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
|
|||
}
|
||||
|
||||
// Checks whether enum contains value with such value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
|
|
@ -1414,7 +1428,7 @@ template <typename E>
|
|||
}
|
||||
|
||||
// Checks whether enum contains value with such integer value.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>>
|
||||
template <typename E, auto S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1430,7 +1444,7 @@ template <typename E>
|
|||
}
|
||||
|
||||
// Checks whether enum contains enumerator with such name.
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename BinaryPredicate = std::equal_to<>>
|
||||
template <typename E, auto S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
|
||||
[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
|
|
@ -1445,7 +1459,7 @@ template <typename E, typename BinaryPredicate = std::equal_to<>>
|
|||
return static_cast<bool>(enum_flags_cast<D>(value, std::move(p)));
|
||||
}
|
||||
|
||||
template <typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename F, detail::enable_if_t<E, int> = 0>
|
||||
template <typename E, auto S = detail::subtype_v<E>, typename F, detail::enable_if_t<E, int> = 0>
|
||||
constexpr auto enum_for_each(F&& f) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
|
||||
|
|
@ -1517,6 +1531,5 @@ constexpr E& operator^=(E& lhs, E rhs) noexcept {
|
|||
#undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN
|
||||
#undef MAGIC_ENUM_ARRAY_CONSTEXPR
|
||||
#undef MAGIC_ENUM_FOR_EACH_256
|
||||
#undef MAGIC_ENUM_CASE
|
||||
|
||||
#endif // NEARGYE_MAGIC_ENUM_HPP
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -142,7 +142,7 @@ constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) {
|
|||
|
||||
} // namespace magic_enum::detail
|
||||
|
||||
template <typename Result = detail::default_result_type, typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
template <typename Result = detail::default_result_type, typename E, auto S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
|
|
@ -165,7 +165,7 @@ constexpr decltype(auto) enum_switch(F&& f, E value) {
|
|||
return enum_switch<Result, E, S>(std::forward<F>(f), value);
|
||||
}
|
||||
|
||||
template <typename Result, typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
template <typename Result, typename E, auto S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ endfunction()
|
|||
make_test(test.cpp test-cpp17 c++17)
|
||||
make_test(test_flags.cpp test_flags-cpp17 c++17)
|
||||
make_test(test_aliases.cpp test_aliases-cpp17 c++17)
|
||||
#make_test(test_containers.cpp test_containers-cpp17 c++17) TODO
|
||||
make_test(test_containers.cpp test_containers-cpp17 c++17)
|
||||
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp17 c++17)
|
||||
|
|
@ -47,7 +47,7 @@ if(HAS_CPP20_FLAG)
|
|||
make_test(test.cpp test-cpp20 c++20)
|
||||
make_test(test_flags.cpp test_flags-cpp20 c++20)
|
||||
make_test(test_aliases.cpp test_aliases-cpp20 c++20)
|
||||
#make_test(test_containers.cpp test_containers-cpp20 c++20) TODO
|
||||
make_test(test_containers.cpp test_containers-cpp20 c++20)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp20 c++20)
|
||||
endif()
|
||||
|
|
@ -57,7 +57,7 @@ if(HAS_CPP23_FLAG)
|
|||
make_test(test.cpp test-cpp23 c++23)
|
||||
make_test(test_flags.cpp test_flags-cpp23 c++23)
|
||||
make_test(test_aliases.cpp test_aliases-cpp23 c++23)
|
||||
#make_test(test_containers.cpp test_containers-cpp23 c++23) TODO
|
||||
make_test(test_containers.cpp test_containers-cpp23 c++23)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp23 c++23)
|
||||
endif()
|
||||
|
|
@ -67,7 +67,7 @@ if(HAS_CPPLATEST_FLAG)
|
|||
make_test(test.cpp test-cpplatest c++latest)
|
||||
make_test(test_flags.cpp test_flags-cpplatest c++latest)
|
||||
make_test(test_aliases.cpp test_aliases-cpplatest c++latest)
|
||||
#make_test(test_containers.cpp test_containers-cpplatest c++latest) TODO
|
||||
make_test(test_containers.cpp test_containers-cpplatest c++latest)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpplatest c++latest)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -37,10 +37,15 @@
|
|||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <magic_enum_containers.hpp>
|
||||
#include <magic_enum_iostream.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum class Empty {};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue