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

add support big range (#268)

* add support big range

* remove string_view from n()

* fix containers
This commit is contained in:
Daniil Goncharov 2023-05-22 19:44:28 +04:00 committed by GitHub
parent 4c54c094ea
commit 629f7b09af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 601 additions and 784 deletions

View file

@ -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"],
)

View file

@ -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)

View file

@ -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;
}

View file

@ -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() {

View file

@ -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() {

View file

@ -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 {
}
}
#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; \
} \
}
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 <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;
}
struct valid_count_t {
std::size_t count = 0;
bool valid[N] = {};
};
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;
}
return count;
}
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>();
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);
if constexpr (count > 0) {
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

View file

@ -71,8 +71,12 @@ namespace detail {
// copied from std::lexicographical_compare
for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) {
if (cmp(*first1, *first2)) { return true; }
if (cmp(*first2, *first1)) { return false; }
if (cmp(*first1, *first2)) {
return true;
}
if (cmp(*first2, *first1)) {
return false;
}
}
return (first1 == last1) && (first2 != last2);
}
@ -97,8 +101,7 @@ namespace detail {
if (comp(*it, e)) {
first = ++it;
count -= step + 1;
}
else {
} else {
count = step;
}
}
@ -162,12 +165,9 @@ namespace detail {
};
template <typename E, typename Less>
struct indexing<E, Less, std::enable_if_t<std::is_enum_v<std::decay_t<E>> &&
(std::is_same_v<Less, std::less<E>> || std::is_same_v<Less, std::less<>>)>> {
struct indexing<E, Less, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && (std::is_same_v<Less, std::less<E>> || std::is_same_v<Less, std::less<>>)>> {
constexpr static inline const std::array<E, enum_count<E>()> *values_v = &enum_values<E>();
[[nodiscard]] constexpr inline optional<std::size_t> operator()(E val) const noexcept {
return enum_index(val);
}
[[nodiscard]] constexpr inline optional<std::size_t> operator()(E val) const noexcept { return enum_index(val); }
};
template <typename Less>
@ -180,13 +180,9 @@ namespace detail {
}
};
template <typename E = void,
typename OP = std::less<>,
typename = void>
template <typename E = void, typename OP = std::less<>, typename = void>
struct name_sort_impl {
[[nodiscard]] constexpr inline bool operator()(E e1, E e2) const noexcept {
return OP{}(enum_name(e1), enum_name(e2));
}
[[nodiscard]] constexpr inline bool operator()(E e1, E e2) const noexcept { return OP{}(enum_name(e1), enum_name(e2)); }
};
template <typename OP>
@ -196,11 +192,8 @@ namespace detail {
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>>> {
[[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept {
return lexicographical_compare<S>(s1, s2);
}
struct FullCmp<S, std::enable_if_t<!std::is_invocable_v<S, string_view, string_view> && std::is_invocable_v<S, char, char>>> {
[[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare<S>(s1, s2); }
};
template <typename E1, typename E2>
@ -210,9 +203,10 @@ namespace detail {
// if both is enum, only accept if the same enum
(!std::is_enum_v<std::decay_t<E1>> || !std::is_enum_v<std::decay_t<E2>> || std::is_same_v<E1, E2>)&&
// is invocable with comparator
(std::is_invocable_r_v<bool, FullCmp<>,
std::conditional_t<std::is_enum_v<std::decay_t<E1>>, string_view, E1>,
std::conditional_t<std::is_enum_v<std::decay_t<E2>>, string_view, E2>>), bool> operator()(E1 e1, E2 e2) const noexcept {
(std::is_invocable_r_v<bool, FullCmp<>, std::conditional_t<std::is_enum_v<std::decay_t<E1>>, string_view, E1>,
std::conditional_t<std::is_enum_v<std::decay_t<E2>>, string_view, E2>>),
bool>
operator()(E1 e1, E2 e2) const noexcept {
using D1 = std::decay_t<E1>;
using D2 = std::decay_t<E2>;
constexpr FullCmp<> cmp{};
@ -250,38 +244,23 @@ namespace detail {
constexpr FilteredIterator(FilteredIterator &&) noexcept = default;
constexpr FilteredIterator &operator=(FilteredIterator &&) noexcept = default;
template <typename OtherParent, typename OtherIterator, typename = std::enable_if_t<std::is_convertible_v<OtherParent, Parent> && std::is_convertible_v<OtherIterator, Iterator>>*>
template <typename OtherParent, typename OtherIterator,
typename = std::enable_if_t<std::is_convertible_v<OtherParent, Parent> && std::is_convertible_v<OtherIterator, Iterator>> *>
constexpr explicit FilteredIterator(const FilteredIterator<OtherParent, OtherIterator, Getter, Predicate> &other)
: parent(other.parent)
, first(other.first)
, last(other.last)
, current(other.current)
, getter(other.getter)
, predicate(other.predicate)
{}
: parent(other.parent), first(other.first), last(other.last), current(other.current), getter(other.getter), predicate(other.predicate) {}
~FilteredIterator() = default;
constexpr FilteredIterator(Parent p, Iterator begin, Iterator end, Iterator curr, Getter getter = {}, Predicate pred = {})
: parent(p)
, first(std::move(begin))
, last(std::move(end))
, current(std::move(curr))
, getter{std::move(getter)}
, predicate{std::move(pred)}
{
: parent(p), first(std::move(begin)), last(std::move(end)), current(std::move(curr)), getter{std::move(getter)}, predicate{std::move(pred)} {
if (current == first && !predicate(parent, current)) {
++*this;
}
}
[[nodiscard]] constexpr reference operator*() const {
return getter(parent, current);
}
[[nodiscard]] constexpr reference operator*() const { return getter(parent, current); }
[[nodiscard]] constexpr pointer operator->() const {
return std::addressof(**this);
}
[[nodiscard]] constexpr pointer operator->() const { return std::addressof(**this); }
constexpr FilteredIterator &operator++() {
do {
@ -309,15 +288,12 @@ namespace detail {
return cp;
}
[[nodiscard]] friend constexpr bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) {
return lhs.current == rhs.current;
}
[[nodiscard]] friend constexpr bool operator==(const FilteredIterator &lhs, const FilteredIterator &rhs) { return lhs.current == rhs.current; }
[[nodiscard]] friend constexpr bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) {
return lhs.current != rhs.current;
}
[[nodiscard]] friend constexpr bool operator!=(const FilteredIterator &lhs, const FilteredIterator &rhs) { return lhs.current != rhs.current; }
};
} // detail
} // namespace detail
template <typename E = void>
using name_less [[maybe_unused]] = detail::name_sort_impl<E>;
@ -333,7 +309,6 @@ using default_indexing = detail::indexing<E>;
template <typename Cmp = std::less<>>
using comparator_indexing [[maybe_unused]] = detail::indexing<void, Cmp>;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ARRAY //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -372,97 +347,51 @@ struct array {
throw std::out_of_range("enum array::at: unrecognized position");
}
[[nodiscard]] constexpr reference operator[](E pos) noexcept {
return a[*index_type{}(pos)];
}
[[nodiscard]] constexpr reference operator[](E pos) noexcept { return a[*index_type{}(pos)]; }
[[nodiscard]] constexpr const_reference operator[](E pos) const noexcept {
return a[*index_type{}(pos)];
}
[[nodiscard]] constexpr const_reference operator[](E pos) const noexcept { return a[*index_type{}(pos)]; }
[[nodiscard]] constexpr reference front() noexcept {
return a.front();
}
[[nodiscard]] constexpr reference front() noexcept { return a.front(); }
[[nodiscard]] constexpr const_reference front() const noexcept {
return a.front();
}
[[nodiscard]] constexpr const_reference front() const noexcept { return a.front(); }
[[nodiscard]] constexpr reference back() noexcept {
return a.back();
}
[[nodiscard]] constexpr reference back() noexcept { return a.back(); }
[[nodiscard]] constexpr const_reference back() const noexcept {
return a.back();
}
[[nodiscard]] constexpr const_reference back() const noexcept { return a.back(); }
[[nodiscard]] constexpr pointer data() noexcept {
return a.data();
}
[[nodiscard]] constexpr pointer data() noexcept { return a.data(); }
[[nodiscard]] constexpr const_pointer data() const noexcept {
return a.data();
}
[[nodiscard]] constexpr const_pointer data() const noexcept { return a.data(); }
[[nodiscard]] constexpr iterator begin() noexcept {
return a.begin();
}
[[nodiscard]] constexpr iterator begin() noexcept { return a.begin(); }
[[nodiscard]] constexpr const_iterator begin() const noexcept {
return a.begin();
}
[[nodiscard]] constexpr const_iterator begin() const noexcept { return a.begin(); }
[[nodiscard]] constexpr const_iterator cbegin() const noexcept {
return a.cbegin();
}
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return a.cbegin(); }
[[nodiscard]] constexpr iterator end() noexcept {
return a.end();
}
[[nodiscard]] constexpr iterator end() noexcept { return a.end(); }
[[nodiscard]] constexpr const_iterator end() const noexcept {
return a.end();
}
[[nodiscard]] constexpr const_iterator end() const noexcept { return a.end(); }
[[nodiscard]] constexpr const_iterator cend() const noexcept {
return a.cend();
}
[[nodiscard]] constexpr const_iterator cend() const noexcept { return a.cend(); }
[[nodiscard]] constexpr iterator rbegin() noexcept {
return a.rbegin();
}
[[nodiscard]] constexpr iterator rbegin() noexcept { return a.rbegin(); }
[[nodiscard]] constexpr const_iterator rbegin() const noexcept {
return a.rbegin();
}
[[nodiscard]] constexpr const_iterator rbegin() const noexcept { return a.rbegin(); }
[[nodiscard]] constexpr const_iterator crbegin() const noexcept {
return a.crbegin();
}
[[nodiscard]] constexpr const_iterator crbegin() const noexcept { return a.crbegin(); }
[[nodiscard]] constexpr iterator rend() noexcept {
return a.rend();
}
[[nodiscard]] constexpr iterator rend() noexcept { return a.rend(); }
[[nodiscard]] constexpr const_iterator rend() const noexcept {
return a.rend();
}
[[nodiscard]] constexpr const_iterator rend() const noexcept { return a.rend(); }
[[nodiscard]] constexpr const_iterator crend() const noexcept {
return a.crend();
}
[[nodiscard]] constexpr const_iterator crend() const noexcept { return a.crend(); }
[[nodiscard]] constexpr bool empty() const noexcept {
return a.empty();
}
[[nodiscard]] constexpr bool empty() const noexcept { return a.empty(); }
[[nodiscard]] constexpr size_type size() const noexcept {
return a.size();
}
[[nodiscard]] constexpr size_type size() const noexcept { return a.size(); }
[[nodiscard]] constexpr size_type max_size() const noexcept {
return a.max_size();
}
[[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); }
constexpr void fill(const V &value) {
for (auto &v : a) {
@ -478,29 +407,17 @@ struct array {
}
}
[[nodiscard]] friend constexpr bool operator==(const array& a1, const array& a2) {
return detail::equal(a1, a2);
}
[[nodiscard]] friend constexpr bool operator==(const array &a1, const array &a2) { return detail::equal(a1, a2); }
[[nodiscard]] friend constexpr bool operator!=(const array& a1, const array& a2) {
return !detail::equal(a1, a2);
}
[[nodiscard]] friend constexpr bool operator!=(const array &a1, const array &a2) { return !detail::equal(a1, a2); }
[[nodiscard]] friend constexpr bool operator<(const array& a1, const array& a2) {
return detail::lexicographical_compare(a1, a2);
}
[[nodiscard]] friend constexpr bool operator<(const array &a1, const array &a2) { return detail::lexicographical_compare(a1, a2); }
[[nodiscard]] friend constexpr bool operator<=(const array& a1, const array& a2) {
return !detail::lexicographical_compare(a2, a1);
}
[[nodiscard]] friend constexpr bool operator<=(const array &a1, const array &a2) { return !detail::lexicographical_compare(a2, a1); }
[[nodiscard]] friend constexpr bool operator>(const array& a1, const array& a2) {
return detail::lexicographical_compare(a2, a1);
}
[[nodiscard]] friend constexpr bool operator>(const array &a1, const array &a2) { return detail::lexicographical_compare(a2, a1); }
[[nodiscard]] friend constexpr bool operator>=(const array& a1, const array& a2) {
return !detail::lexicographical_compare(a1, a2);
}
[[nodiscard]] friend constexpr bool operator>=(const array &a1, const array &a2) { return !detail::lexicographical_compare(a1, a2); }
container_type a;
};
@ -516,7 +433,8 @@ namespace detail {
constexpr array<E, std::remove_cv_t<T>> to_array_impl(T(&&a)[N], std::index_sequence<I...>) {
return {{std::move(a[I])...}};
}
}
} // namespace detail
template <typename E, typename T, std::size_t N>
constexpr std::enable_if_t<(enum_count<E>() == N), array<E, std::remove_cv_t<T>>> to_array(T (&a)[N]) {
@ -535,7 +453,6 @@ constexpr std::enable_if_t<(enum_count<E>() == sizeof...(Ts)), array<E, std::rem
inline constexpr detail::raw_access_t raw_access{};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BITSET //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -549,6 +466,7 @@ class bitset {
std::conditional_t<enum_count<E>() <= 16, std::uint_least16_t,
std::conditional_t<enum_count<E>() <= 32, std::uint_least32_t,
std::uint_least64_t>>>;
constexpr static std::size_t bits_per_base = sizeof(base_type) * 8;
constexpr static std::size_t base_type_count = (enum_count<E>() > 0 ? (enum_count<E>() - 1) / bits_per_base + 1 : 0);
constexpr static std::size_t not_interested = base_type_count * bits_per_base - enum_count<E>();
@ -563,14 +481,10 @@ class bitset {
base_type bit_index;
constexpr reference_impl(parent_t parent, std::size_t ix) noexcept
: reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)})
{}
: reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)}) {}
constexpr reference_impl(parent_t parent, std::pair<std::size_t, base_type> ix) noexcept
: parent(parent)
, num_index(std::get<0>(ix))
, bit_index(std::get<1>(ix))
{}
: parent(parent), num_index(std::get<0>(ix)), bit_index(std::get<1>(ix)) {}
public:
constexpr reference_impl &operator=(bool v) noexcept {
@ -590,13 +504,9 @@ class bitset {
return *this;
}
[[nodiscard]] constexpr explicit operator bool() const noexcept {
return (parent->a[num_index] & bit_index) > 0;
}
[[nodiscard]] constexpr explicit operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; }
[[nodiscard]] constexpr bool operator~() const noexcept {
return !static_cast<bool>(*this);
}
[[nodiscard]] constexpr bool operator~() const noexcept { return !static_cast<bool>(*this); }
constexpr reference_impl &flip() noexcept {
*this = ~*this;
@ -618,6 +528,7 @@ class bitset {
}
return res;
}
public:
using index_type = Index;
using container_type = std::array<base_type, base_type_count>;
@ -639,12 +550,8 @@ public:
}
}
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') : a{{}} {
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')
: a{{}} {
std::size_t i{};
for (auto c : sv.substr(pos, n)) {
if (c == one) {
@ -659,17 +566,11 @@ public:
}
}
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 *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 bitset(std::initializer_list<E> starters) : a{{}} {
if constexpr (magic_enum::detail::is_flags_v<E>) {
if constexpr (magic_enum::detail::subtype_v<E> == magic_enum::detail::enum_subtype::flags) {
for (auto &f : starters) {
*this |= bitset(f);
}
@ -681,7 +582,7 @@ public:
}
template <typename V = E>
constexpr explicit bitset(std::enable_if_t<magic_enum::detail::is_flags_v<V>, E> starter) : a{{}} {
constexpr explicit bitset(std::enable_if_t<magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, E> starter) : a{{}} {
auto u = enum_underlying(starter);
for (E v : enum_values<E>()) {
if (auto ul = enum_underlying(v); (ul & u) != 0) {
@ -695,9 +596,7 @@ public:
}
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 sep = '|') {
for (std::size_t to{}; (to = magic_enum::detail::find(sv, sep)) != string_view::npos; sv.remove_prefix(to + 1)) {
if (auto v = magic_enum::enum_cast<E>(sv.substr(0, to), cmp)) {
set(v);
@ -714,21 +613,13 @@ public:
}
}
[[nodiscard]] friend constexpr bool operator==( const bitset& lhs, const bitset& rhs ) noexcept {
return detail::equal(lhs.a, rhs.a);
}
[[nodiscard]] friend constexpr bool operator==(const bitset &lhs, const bitset &rhs) noexcept { return detail::equal(lhs.a, rhs.a); }
[[nodiscard]] friend constexpr bool operator!=( const bitset& lhs, const bitset& rhs ) noexcept {
return !detail::equal(lhs.a, rhs.a);
}
[[nodiscard]] friend constexpr bool operator!=(const bitset &lhs, const bitset &rhs) noexcept { return !detail::equal(lhs.a, rhs.a); }
[[nodiscard]] constexpr bool operator[](E pos) const noexcept {
return static_cast<bool>(const_reference(this, *index_type{}(pos)));
}
[[nodiscard]] constexpr bool operator[](E pos) const noexcept { return static_cast<bool>(const_reference(this, *index_type{}(pos))); }
[[nodiscard]] constexpr reference operator[](E pos) noexcept {
return reference{this, *index_type{}(pos)};
}
[[nodiscard]] constexpr reference operator[](E pos) noexcept { return reference{this, *index_type{}(pos)}; }
constexpr bool test(E pos) const {
if (auto ix = index_type{}(pos)) {
@ -763,9 +654,7 @@ public:
return false;
}
[[nodiscard]] constexpr bool none() const noexcept {
return !any();
}
[[nodiscard]] constexpr bool none() const noexcept { return !any(); }
[[nodiscard]] constexpr std::size_t count() const noexcept {
std::size_t c{};
@ -775,13 +664,9 @@ public:
return c;
}
[[nodiscard]] constexpr std::size_t size() const noexcept {
return enum_count<E>();
}
[[nodiscard]] constexpr std::size_t size() const noexcept { return enum_count<E>(); }
[[nodiscard]] constexpr std::size_t max_size() const noexcept {
return enum_count<E>();
}
[[nodiscard]] constexpr std::size_t max_size() const noexcept { return enum_count<E>(); }
constexpr bitset &operator&=(const bitset &other) noexcept {
for (std::size_t i{}; i < base_type_count; ++i) {
@ -835,9 +720,7 @@ public:
throw std::out_of_range("enum bitset::set: unrecognized position");
}
constexpr bitset& reset() noexcept {
return *this = bitset{};
}
constexpr bitset &reset() noexcept { return *this = bitset{}; }
constexpr bitset &reset(E pos) {
if (auto ix = index_type{}(pos)) {
@ -847,9 +730,7 @@ public:
throw std::out_of_range("enum bitset::reset: unrecognized position");
}
constexpr bitset& flip() noexcept {
return *this = ~*this;
}
constexpr bitset &flip() noexcept { return *this = ~*this; }
[[nodiscard]] friend constexpr bitset operator&(const bitset &lhs, const bitset &rhs) noexcept {
bitset cp = lhs;
@ -870,7 +751,7 @@ public:
}
template <typename V = E>
[[nodiscard]] constexpr explicit operator std::enable_if_t<magic_enum::detail::is_flags_v<V>, E>() const {
[[nodiscard]]constexpr explicit operator std::enable_if_t<magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, E>() const {
E res{};
for (auto &e : enum_values<E>()) {
if (test(e)) {
@ -881,9 +762,6 @@ public:
}
[[nodiscard]] string to_string(char sep = '|') const {
// if constexpr (magic_enum::detail::is_flags_v<E>) {
// return enum_flags_name(static_cast<E>(*this), sep);
// } else {
string name;
for (auto &e : enum_values<E>()) {
@ -896,12 +774,9 @@ public:
}
}
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 zero = '0', char one = '1') const {
string name;
name.reserve(size());
for (std::size_t i{}; i < size(); ++i) {
@ -910,17 +785,11 @@ public:
return name;
}
[[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const {
return to_<unsigned long long>(raw);
}
[[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { return to_<unsigned long long>(raw); }
[[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const {
return to_<unsigned long>(raw);
}
[[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { return to_<unsigned long>(raw); }
friend std::ostream& operator<<(std::ostream& o, const bitset& bs) {
return o << bs.to_string();
}
friend std::ostream &operator<<(std::ostream &o, const bitset &bs) { return o << bs.to_string(); }
friend std::istream &operator>>(std::istream &i, bitset &bs) {
string s;
@ -934,7 +803,6 @@ private:
container_type a;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SET //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -942,17 +810,13 @@ template <typename E, typename CExprLess = std::less<E>>
class set {
using index_type = detail::indexing<E, CExprLess>;
struct Getter {
constexpr const E& operator()(const set*, const E* p) const noexcept {
return *p;
}
constexpr const E &operator()(const set *, const E *p) const noexcept { return *p; }
};
struct Predicate {
constexpr bool operator()(const set* h, const E* e) const noexcept {
return h->a[*e];
}
constexpr bool operator()(const set *h, const E *e) const noexcept { return h->a[*e]; }
};
public:
public:
using container_type = bitset<E, index_type>;
using key_type = E;
using value_type = E;
@ -985,7 +849,7 @@ public:
}
template <typename V = E>
constexpr explicit set(std::enable_if_t<magic_enum::detail::is_flags_v<V>, E> starter) {
constexpr explicit set(std::enable_if_t<magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, E> starter) {
auto u = enum_underlying(starter);
for (E v : enum_values<E>()) {
if ((enum_underlying(v) & u) != 0) {
@ -1006,52 +870,30 @@ public:
}
constexpr const_iterator begin() const noexcept {
return const_iterator{this, &(*index_type::values_v->begin()),
&(*index_type::values_v->end()),
&(*index_type::values_v->begin())};
return const_iterator{this, &(*index_type::values_v->begin()), &(*index_type::values_v->end()), &(*index_type::values_v->begin())};
}
constexpr const_iterator end() const noexcept {
return const_iterator{this, &(*index_type::values_v->begin()),
&(*index_type::values_v->end()),
&(*index_type::values_v->end())};
return const_iterator{this, &(*index_type::values_v->begin()), &(*index_type::values_v->end()), &(*index_type::values_v->end())};
}
constexpr const_iterator cbegin() const noexcept {
return begin();
}
constexpr const_iterator cbegin() const noexcept { return begin(); }
constexpr const_iterator cend() const noexcept {
return end();
}
constexpr const_iterator cend() const noexcept { return end(); }
constexpr const_reverse_iterator rbegin() const noexcept {
return {end()};
}
constexpr const_reverse_iterator rbegin() const noexcept { return {end()}; }
constexpr const_reverse_iterator rend() const noexcept {
return {begin()};
}
constexpr const_reverse_iterator rend() const noexcept { return {begin()}; }
constexpr const_reverse_iterator crbegin() const noexcept {
return rbegin();
}
constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
constexpr const_reverse_iterator crend() const noexcept {
return rend();
}
constexpr const_reverse_iterator crend() const noexcept { return rend(); }
[[nodiscard]] constexpr bool empty() const noexcept {
return s == 0;
}
[[nodiscard]] constexpr bool empty() const noexcept { return s == 0; }
[[nodiscard]] constexpr size_type size() const noexcept {
return s;
}
[[nodiscard]] constexpr size_type size() const noexcept { return s; }
[[nodiscard]] constexpr size_type max_size() const noexcept {
return a.max_size();
}
[[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); }
constexpr void clear() noexcept {
a.reset();
@ -1067,24 +909,16 @@ public:
++s;
}
return {iterator{this, &(*index_type::values_v->begin()),
&(*index_type::values_v->end()),
&(*index_type::values_v)[*i]}, r};
return {iterator{this, &(*index_type::values_v->begin()), &(*index_type::values_v->end()), &(*index_type::values_v)[*i]}, r};
}
return {end(), false};
}
constexpr std::pair<iterator,bool> insert(value_type&& value) noexcept {
return insert(value);
}
constexpr std::pair<iterator, bool> insert(value_type &&value) noexcept { return insert(value); }
constexpr iterator insert(const_iterator, const value_type& value) noexcept {
return insert(value).first;
}
constexpr iterator insert(const_iterator, const value_type &value) noexcept { return insert(value).first; }
constexpr iterator insert(const_iterator hint, value_type&& value) noexcept {
return insert(hint, value);
}
constexpr iterator insert(const_iterator hint, value_type &&value) noexcept { return insert(hint, value); }
template <typename InputIt>
constexpr void insert(InputIt first, InputIt last) noexcept {
@ -1100,14 +934,10 @@ public:
}
template <typename... Args>
constexpr std::pair<iterator,bool> emplace(Args&&... args) noexcept {
return insert({std::forward<Args>(args)...});
}
constexpr std::pair<iterator, bool> emplace(Args &&... args) noexcept { return insert({std::forward<Args>(args)...}); }
template <typename... Args>
constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept {
return emplace(std::forward<Args>(args)...).first;
}
constexpr iterator emplace_hint(const_iterator, Args &&... args) noexcept { return emplace(std::forward<Args>(args)...).first; }
constexpr iterator erase(const_iterator pos) noexcept {
erase(*pos++);
@ -1115,7 +945,9 @@ public:
}
constexpr iterator erase(const_iterator first, const_iterator last) noexcept {
while((first = erase(first)) != last) { ; }
while ((first = erase(first)) != last) {
;
}
return first;
}
@ -1132,8 +964,7 @@ public:
template <typename K, typename KC = key_compare>
constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> erase(K &&x) noexcept {
size_type c{};
for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{});
first != last; ) {
for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); first != last;) {
c += erase(*first++);
}
return c;
@ -1145,9 +976,7 @@ public:
other = cp;
}
[[nodiscard]] constexpr size_type count(const key_type& key) const noexcept {
return index_type{}(key) && a[key];
}
[[nodiscard]] constexpr size_type count(const key_type &key) const noexcept { return index_type{}(key) && a[key]; }
template <typename K, typename KC = key_compare>
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> count(const K &x) const {
@ -1160,9 +989,7 @@ public:
[[nodiscard]] constexpr const_iterator find(const key_type &key) const noexcept {
if (auto i = index_type{}(key); i && a.test(key))
return const_iterator{this, index_type::values_v->begin(),
index_type::values_v->end(),
&(*index_type::values_v)[*i]};
return const_iterator{this, index_type::values_v->begin(), index_type::values_v->end(), &(*index_type::values_v)[*i]};
return end();
}
@ -1176,9 +1003,7 @@ public:
return end();
}
[[nodiscard]] constexpr bool contains(const key_type& key) const noexcept {
return count(key);
}
[[nodiscard]] constexpr bool contains(const key_type &key) const noexcept { return count(key); }
template <typename K, typename KC = key_compare>
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, bool> contains(const K &x) const noexcept {
@ -1196,9 +1021,7 @@ public:
[[nodiscard]] constexpr const_iterator lower_bound(const key_type &key) const noexcept {
if (auto i = index_type{}(key)) {
auto it = const_iterator{this, index_type::values_v->begin(),
index_type::values_v->end(),
&(*index_type::values_v)[*i]};
auto it = const_iterator{this, index_type::values_v->begin(), index_type::values_v->end(), &(*index_type::values_v)[*i]};
return a.test(key) ? it : std::next(it);
}
return end();
@ -1212,9 +1035,7 @@ public:
[[nodiscard]] constexpr const_iterator upper_bound(const key_type &key) const noexcept {
if (auto i = index_type{}(key)) {
return std::next(const_iterator{this, index_type::values_v->begin(),
index_type::values_v->end(),
&(*index_type::values_v)[*i]});
return std::next(const_iterator{this, index_type::values_v->begin(), index_type::values_v->end(), &(*index_type::values_v)[*i]});
}
return end();
}
@ -1225,25 +1046,21 @@ public:
return first != last ? upper_bound(*std::prev(last)) : end();
}
[[nodiscard]] constexpr key_compare key_comp() const {
return {};
}
[[nodiscard]] constexpr key_compare key_comp() const { return {}; }
[[nodiscard]] constexpr value_compare value_comp() const {
return {};
}
[[nodiscard]] constexpr value_compare value_comp() const { return {}; }
[[nodiscard]] constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept {
return lhs.a == rhs.a;
}
[[nodiscard]] constexpr friend bool operator==(const set &lhs, const set &rhs) noexcept { return lhs.a == rhs.a; }
[[nodiscard]] constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept {
return lhs.a != rhs.a;
}
[[nodiscard]] constexpr friend bool operator!=(const set &lhs, const set &rhs) noexcept { return lhs.a != rhs.a; }
[[nodiscard]] constexpr friend bool operator<(const set &lhs, const set &rhs) noexcept {
if (lhs.s < rhs.s) { return true; }
if (rhs.s < lhs.s) { return false; }
if (lhs.s < rhs.s) {
return true;
}
if (rhs.s < lhs.s) {
return false;
}
for (auto &e : *index_type::values_v) {
if (auto c = rhs.contains(e); c != lhs.contains(e)) {
@ -1253,17 +1070,11 @@ public:
return false;
}
[[nodiscard]] constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept {
return !(rhs < lhs);
}
[[nodiscard]] constexpr friend bool operator<=(const set &lhs, const set &rhs) noexcept { return !(rhs < lhs); }
[[nodiscard]] constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept {
return rhs < lhs;
}
[[nodiscard]] constexpr friend bool operator>(const set &lhs, const set &rhs) noexcept { return rhs < lhs; }
[[nodiscard]] constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept {
return !(lhs < rhs);
}
[[nodiscard]] constexpr friend bool operator>=(const set &lhs, const set &rhs) noexcept { return !(lhs < rhs); }
template <typename Pred>
size_type erase_if(Pred pred) {
@ -1284,54 +1095,58 @@ private:
std::size_t s{};
};
} // namespace magic_enum::containers
namespace std {
template <auto I, typename E, typename V, typename Index>
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
I < magic_enum::enum_count<E>()), V&> get( magic_enum::containers::array<E, V, Index>& a ) noexcept {
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> && I < magic_enum::enum_count<E>()), V &>
get(magic_enum::containers::array<E, V, Index> &a) noexcept {
return a.a[I];
}
template <auto I, typename E, typename V, typename Index>
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
I < magic_enum::enum_count<E>()), V&&> get( magic_enum::containers::array<E, V, Index>&& a ) noexcept {
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> && I < magic_enum::enum_count<E>()), V &&>
get(magic_enum::containers::array<E, V, Index> &&a) noexcept {
return std::move(a.a[I]);
}
template <auto I, typename E, typename V, typename Index>
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
I < magic_enum::enum_count<E>()), const V&> get( const magic_enum::containers::array<E, V, Index>& a ) noexcept {
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> && I < magic_enum::enum_count<E>()), const V &>
get(const magic_enum::containers::array<E, V, Index> &a) noexcept {
return a.a[I];
}
template <auto I, typename E, typename V, typename Index>
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
I < magic_enum::enum_count<E>()), const V&&> get( const magic_enum::containers::array<E, V, Index>&& a ) noexcept {
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> && I < magic_enum::enum_count<E>()), const V &&>
get(const magic_enum::containers::array<E, V, Index> &&a) noexcept {
return std::move(a.a[I]);
}
template <auto Enum, typename E, typename V, typename Index>
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
magic_enum::enum_contains(Enum), V&> get( magic_enum::containers::array<E, V, Index>& a ) noexcept {
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> && magic_enum::enum_contains(Enum), V &>
get(magic_enum::containers::array<E, V, Index> &a) noexcept {
return a[Enum];
}
template <auto Enum, typename E, typename V, typename Index>
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
magic_enum::enum_contains(Enum), V&&> get( magic_enum::containers::array<E, V, Index>&& a ) noexcept {
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> && magic_enum::enum_contains(Enum), V &&>
get(magic_enum::containers::array<E, V, Index> &&a) noexcept {
return std::move(a[Enum]);
}
template <auto Enum, typename E, typename V, typename Index>
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
magic_enum::enum_contains(Enum), const V&> get( const magic_enum::containers::array<E, V, Index>& a ) noexcept {
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> && magic_enum::enum_contains(Enum), const V &>
get(const magic_enum::containers::array<E, V, Index> &a) noexcept {
return a[Enum];
}
template <auto Enum, typename E, typename V, typename Index>
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
magic_enum::enum_contains(Enum), const V&&> get( const magic_enum::containers::array<E, V, Index>&& a ) noexcept {
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> && magic_enum::enum_contains(Enum), const V &&>
get(const magic_enum::containers::array<E, V, Index> &&a) noexcept {
return std::move(a[Enum]);
}
}
} // namespace std
#endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP

View file

@ -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.");

View file

@ -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()

View file

@ -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 {};