diff --git a/example/BUILD.bazel b/example/BUILD.bazel deleted file mode 100644 index d2bb746..0000000 --- a/example/BUILD.bazel +++ /dev/null @@ -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"], -) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index fd52853..e990d63 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -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) diff --git a/example/example_containers_array.cpp b/example/example_containers_array.cpp index c1cc13f..81fe9b8 100644 --- a/example/example_containers_array.cpp +++ b/example/example_containers_array.cpp @@ -25,6 +25,10 @@ #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; +template <> +struct magic_enum::customize::enum_range { + 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(rgb.r) << " G=" << static_cast(rgb.g) << " B=" << static_cast(rgb.b); return ostream; } diff --git a/example/example_containers_bitset.cpp b/example/example_containers_bitset.cpp index 29d1dd3..8bbab8e 100644 --- a/example/example_containers_bitset.cpp +++ b/example/example_containers_bitset.cpp @@ -30,6 +30,10 @@ #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; int main() { diff --git a/example/example_containers_set.cpp b/example/example_containers_set.cpp index bf6ff41..c1ef168 100644 --- a/example/example_containers_set.cpp +++ b/example/example_containers_set.cpp @@ -34,6 +34,10 @@ #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; int main() { diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 90d4c14..515515e 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -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::chars_' is uninitialized. +# pragma warning(disable : 26495) // Variable 'static_str::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 {}; template struct range_max::max)>> : std::integral_constant::max), customize::enum_range::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 -class static_string { +class static_str { public: - constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_integer_sequence{}} { + constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} { + assert(str.size() == N); + } + + constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} { assert(str.size() == N); } @@ -239,17 +252,19 @@ class static_string { private: template - constexpr static_string(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., '\0'} {} + constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{str[I]..., '\0'} {} char chars_[static_cast(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::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::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 constexpr auto type_name() noexcept { - static_assert(is_enum_v, "magic_enum::detail::type_name requires enum type."); - [[maybe_unused]] constexpr auto custom = customize::enum_type_name(); static_assert(std::is_same_v, 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}; + return static_str{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(); - return static_string{name}; + return static_str{name}; } else { static_assert(always_false_v, "magic_enum::customize invalid."); } @@ -439,65 +452,66 @@ constexpr auto n() noexcept { if constexpr (supported::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::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().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().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().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 constexpr auto enum_name() noexcept { - static_assert(is_enum_v, "magic_enum::detail::enum_name requires enum type."); - [[maybe_unused]] constexpr auto custom = customize::enum_name(V); static_assert(std::is_same_v, 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}; + return static_str{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(); - return static_string{name}; + return static_str{name}; } else { static_assert(always_false_v, "magic_enum::customize invalid."); } @@ -508,8 +522,6 @@ inline constexpr auto enum_name_v = enum_name(); template constexpr bool is_valid() noexcept { - static_assert(is_enum_v, "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 > constexpr U ualue(std::size_t i) noexcept { - static_assert(is_enum_v, "magic_enum::detail::ualue requires enum type."); - if constexpr (std::is_same_v) { // 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 > constexpr E value(std::size_t i) noexcept { - static_assert(is_enum_v, "magic_enum::detail::value requires enum type."); - return static_cast(ualue(i)); } template > constexpr int reflected_min() noexcept { - static_assert(is_enum_v, "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 > constexpr int reflected_max() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); - if constexpr (S == enum_subtype::flags) { return std::numeric_limits::digits - 1; } else { @@ -592,39 +596,66 @@ constexpr int reflected_max() noexcept { } } -template -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 +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(I + O)>()) { \ + valid[I + O] = true; \ + ++count; \ + } \ } - return count; + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V); + + if constexpr ((I + 256) < Size) { + valid_count(valid, count); + } +#undef MAGIC_ENUM_V } -template -constexpr auto values(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); - constexpr bool valid[sizeof...(I)] = {is_valid(I)>()...}; - constexpr std::size_t count = values_count(valid); +template +struct valid_count_t { + std::size_t count = 0; + bool valid[N] = {}; +}; - if constexpr (count > 0) { +template +constexpr auto valid_count() noexcept { + valid_count_t vc; + valid_count(vc.valid, vc.count); + return vc; +} + +template +constexpr auto values() noexcept { + constexpr auto vc = valid_count(); + + if constexpr (vc.count > 0) { #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) - std::array values = {}; + std::array 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(i); } } #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) return values; #else - return to_array(values, std::make_index_sequence{}); + return to_array(values, std::make_index_sequence{}); #endif } else { return std::array{}; @@ -633,20 +664,17 @@ constexpr auto values(std::index_sequence) noexcept { template > constexpr auto values() noexcept { - static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); constexpr auto min = reflected_min(); constexpr auto max = reflected_max(); 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::max)(), "magic_enum::enum_range requires valid size."); - return values(std::make_index_sequence{}); + return values(); } template > -constexpr enum_subtype subtype() noexcept { - static_assert(is_enum_v, "magic_enum::detail::subtype requires enum type."); - +constexpr enum_subtype subtype(std::true_type) noexcept { if constexpr (std::is_same_v) { // bool special case return enum_subtype::common; } else if constexpr (has_is_flags::value) { @@ -671,8 +699,14 @@ constexpr enum_subtype subtype() noexcept { } } -template -inline constexpr auto subtype_v = subtype(); +template +constexpr enum_subtype subtype(std::false_type) noexcept { + // For non-enum type return default common subtype. + return enum_subtype::common; +} + +template > +inline constexpr auto subtype_v = subtype(std::is_enum{}); template inline constexpr auto values_v = values(); @@ -691,8 +725,6 @@ inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v constexpr auto names(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); - return std::array{{enum_name_v[I]>...}}; } @@ -704,8 +736,6 @@ using names_t = decltype((names_v)); template constexpr auto entries(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); - return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; } @@ -717,8 +747,6 @@ using entries_t = decltype((entries_v)); template > constexpr bool is_sparse() noexcept { - static_assert(is_enum_v, "magic_enum::detail::is_sparse requires enum type."); - if constexpr (count_v == 0) { return false; } else if constexpr (std::is_same_v) { // bool special case @@ -737,7 +765,6 @@ inline constexpr bool is_sparse_v = is_sparse(); template > constexpr U values_ors() noexcept { - static_assert(is_enum_v, "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 constexpr auto for_each(F&& f, std::index_sequence) { - static_assert(is_enum_v, "magic_enum::detail::for_each requires enum type."); constexpr bool has_void_return = (std::is_void_v[I]>>> || ...); constexpr bool all_same_return = (std::is_same_v[0]>>, std::invoke_result_t[I]>>> && ...); @@ -1025,8 +1041,6 @@ constexpr auto for_each(F&& f, std::index_sequence) { template constexpr bool all_invocable(std::index_sequence) { - static_assert(is_enum_v, "magic_enum::detail::all_invocable requires enum type."); - if constexpr (count_v == 0) { return false; } else { @@ -1079,14 +1093,14 @@ template } // Returns number of enum values. -template >> +template > [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t { return detail::count_v, S>; } // Returns enum value at specified index. // No bounds checking is performed: the behavior is undefined if index >= number of enum values. -template >> +template > [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { using D = std::decay_t; @@ -1100,7 +1114,7 @@ template >> } // Returns enum value at specified index. -template >> +template > [[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); @@ -1109,7 +1123,7 @@ template > } // Returns std::array with enum values, sorted by enum value. -template >> +template > [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { return detail::values_v, S>; } @@ -1128,7 +1142,7 @@ template // Obtains index in enum values from enum value. // Returns optional with index. -template >> +template > [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; using U = underlying_type_t; @@ -1189,7 +1203,7 @@ template // Returns name from enum value. // If enum value does not have name or value out of range, returns empty string. -template >> +template > [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; @@ -1236,13 +1250,13 @@ template } // Returns std::array with names, sorted by enum value. -template >> +template > [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { return detail::names_v, S>; } // Returns std::array with pairs (value, name), sorted by enum value. -template >> +template > [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { return detail::entries_v, 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 >> +template > [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; @@ -1320,7 +1334,7 @@ template // Obtains enum value from name. // Returns optional with enum value. -template >, typename BinaryPredicate = std::equal_to<>> +template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; @@ -1387,7 +1401,7 @@ template > } // Checks whether enum contains value with such value. -template >> +template > [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; @@ -1414,7 +1428,7 @@ template } // Checks whether enum contains value with such integer value. -template >> +template > [[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_t { using D = std::decay_t; @@ -1430,7 +1444,7 @@ template } // Checks whether enum contains enumerator with such name. -template >, typename BinaryPredicate = std::equal_to<>> +template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { using D = std::decay_t; @@ -1445,7 +1459,7 @@ template > return static_cast(enum_flags_cast(value, std::move(p))); } -template >, typename F, detail::enable_if_t = 0> +template , typename F, detail::enable_if_t = 0> constexpr auto enum_for_each(F&& f) { using D = std::decay_t; static_assert(std::is_enum_v, "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 diff --git a/include/magic_enum_containers.hpp b/include/magic_enum_containers.hpp index 9d04d07..8779d5c 100644 --- a/include/magic_enum_containers.hpp +++ b/include/magic_enum_containers.hpp @@ -41,283 +41,259 @@ namespace magic_enum::containers { namespace detail { - template - [[maybe_unused]] constexpr static bool is_transparent_v {}; +template +[[maybe_unused]] constexpr static bool is_transparent_v{}; - template - constexpr static bool is_transparent_v> {true}; +template +constexpr static bool is_transparent_v>{true}; - template , typename T1, typename T2> - constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) { - auto first1 = t1.begin(); - auto last1 = t1.end(); - auto first2 = t2.begin(); - auto last2 = t2.end(); +template , typename T1, typename T2> +constexpr bool equal(T1 &&t1, T2 &&t2, Eq &&eq = {}) { + auto first1 = t1.begin(); + auto last1 = t1.end(); + auto first2 = t2.begin(); + auto last2 = t2.end(); - for (; first1 != last1; ++first1, ++first2) { - if (first2 == last2 || !eq(*first1, *first2)) { - return false; - } + for (; first1 != last1; ++first1, ++first2) { + if (first2 == last2 || !eq(*first1, *first2)) { + return false; } - return first2 == last2; } + return first2 == last2; +} - template , typename T1, typename T2> - constexpr bool lexicographical_compare(T1&& t1, T2&& t2, Cmp&& cmp = {}) noexcept { - auto first1 = t1.begin(); - auto last1 = t1.end(); - auto first2 = t2.begin(); - auto last2 = t2.end(); +template , typename T1, typename T2> +constexpr bool lexicographical_compare(T1 &&t1, T2 &&t2, Cmp &&cmp = {}) noexcept { + auto first1 = t1.begin(); + auto last1 = t1.end(); + auto first2 = t2.begin(); + auto last2 = t2.end(); - // 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; } + // copied from std::lexicographical_compare + for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) { + if (cmp(*first1, *first2)) { + return true; } - return (first1 == last1) && (first2 != last2); - } - - template - constexpr std::size_t popcount( T x ) noexcept { - std::size_t c = 0; - while (x > 0) { - c += x & 1; - x >>= 1; + if (cmp(*first2, *first1)) { + return false; } - return c; } + return (first1 == last1) && (first2 != last2); +} - template , typename ForwardIt, typename E> - constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) { - auto count = std::distance(first, last); +template +constexpr std::size_t popcount(T x) noexcept { + std::size_t c = 0; + while (x > 0) { + c += x & 1; + x >>= 1; + } + return c; +} - for (auto it = first; count > 0;) { - auto step = count / 2; - std::advance(it, step); - if (comp(*it, e)) { - first = ++it; - count -= step + 1; - } - else { - count = step; - } +template , typename ForwardIt, typename E> +constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E &&e, Cmp &&comp = {}) { + auto count = std::distance(first, last); + + for (auto it = first; count > 0;) { + auto step = count / 2; + std::advance(it, step); + if (comp(*it, e)) { + first = ++it; + count -= step + 1; + } else { + count = step; } - return first; } + return first; +} - template , typename BidirIt, typename E> - constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) { - const auto first = lower_bound(begin, end, e, comp); - return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp] (auto&& lhs, auto&& rhs) { - return comp(rhs, lhs); - }).base()}; - } +template , typename BidirIt, typename E> +constexpr auto equal_range(BidirIt begin, BidirIt end, E &&e, Cmp &&comp = {}) { + const auto first = lower_bound(begin, end, e, comp); + return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp](auto &&lhs, auto &&rhs) { + return comp(rhs, lhs); + }).base()}; +} - template , typename = void> - struct indexing { - [[nodiscard]] constexpr static auto get_indices() noexcept { - // reverse result index mapping - std::array()> rev_res{}; +template , typename = void> +struct indexing { + [[nodiscard]] constexpr static auto get_indices() noexcept { + // reverse result index mapping + std::array()> rev_res{}; - // std::iota - for (std::size_t i = 0; i < enum_count(); ++i) { - rev_res[i] = i; - } + // std::iota + for (std::size_t i = 0; i < enum_count(); ++i) { + rev_res[i] = i; + } - constexpr auto orig_values = enum_values(); - constexpr Cmp cmp{}; + constexpr auto orig_values = enum_values(); + constexpr Cmp cmp{}; - // ~std::sort - for (std::size_t i = 0; i < enum_count(); ++i) { - for (std::size_t j = i+1; j < enum_count(); ++j) { - if (cmp(orig_values[rev_res[j]], orig_values[rev_res[i]])) { - auto tmp = rev_res[i]; - rev_res[i] = rev_res[j]; - rev_res[j] = tmp; - } + // ~std::sort + for (std::size_t i = 0; i < enum_count(); ++i) { + for (std::size_t j = i + 1; j < enum_count(); ++j) { + if (cmp(orig_values[rev_res[j]], orig_values[rev_res[i]])) { + auto tmp = rev_res[i]; + rev_res[i] = rev_res[j]; + rev_res[j] = tmp; } } - - std::array()> sorted_values{}; - // reverse the sorted indices - std::array()> res{}; - for (std::size_t i = 0; i < enum_count(); ++i) { - res[rev_res[i]] = i; - sorted_values[i] = orig_values[rev_res[i]]; - } - - return std::pair{sorted_values, res}; } - constexpr static inline std::array()> values = get_indices().first; - constexpr static inline const std::array()>* values_v = &values; - constexpr static inline std::array()> reindex = get_indices().second; - - [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { - if (auto opt = enum_index(val)) { - return reindex[*opt]; - } - return {}; + std::array()> sorted_values{}; + // reverse the sorted indices + std::array()> res{}; + for (std::size_t i = 0; i < enum_count(); ++i) { + res[rev_res[i]] = i; + sorted_values[i] = orig_values[rev_res[i]]; } + + return std::pair{sorted_values, res}; + } + + constexpr static inline std::array()> values = get_indices().first; + constexpr static inline const std::array()> *values_v = &values; + constexpr static inline std::array()> reindex = get_indices().second; + + [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { + if (auto opt = enum_index(val)) { + return reindex[*opt]; + } + return {}; + } +}; + +template +struct indexing> && (std::is_same_v> || std::is_same_v>)>> { + constexpr static inline const std::array()> *values_v = &enum_values(); + [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { return enum_index(val); } +}; + +template +struct indexing { + using is_transparent = std::true_type; + template + [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { + constexpr indexing ix{}; + return ix(val); + } +}; + +template , 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)); } +}; + +template +struct name_sort_impl { + using is_transparent = std::true_type; + template + struct FullCmp : S {}; + + template + struct FullCmp && std::is_invocable_v>> { + [[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare(s1, s2); } }; - template - struct indexing> && - (std::is_same_v> || std::is_same_v>)>> { - constexpr static inline const std::array()>* values_v = &enum_values(); - [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { - return enum_index(val); + template + [[nodiscard]] constexpr inline std::enable_if_t< + // at least one of need to be an enum type + (std::is_enum_v> || std::is_enum_v>)&& + // if both is enum, only accept if the same enum + (!std::is_enum_v> || !std::is_enum_v> || std::is_same_v)&& + // is invocable with comparator + (std::is_invocable_r_v, std::conditional_t>, string_view, E1>, + std::conditional_t>, string_view, E2>>), + bool> + operator()(E1 e1, E2 e2) const noexcept { + using D1 = std::decay_t; + using D2 = std::decay_t; + constexpr FullCmp<> cmp{}; + + if constexpr (std::is_enum_v && std::is_enum_v) { + return cmp(enum_name(e1), enum_name(e2)); + } else if constexpr (std::is_enum_v) { + return cmp(enum_name(e1), e2); + } else /* if constexpr (std::is_enum_v) */ { + return cmp(e1, enum_name(e2)); } - }; + } +}; - template - struct indexing { - using is_transparent = std::true_type; - template - [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { - constexpr indexing ix{}; - return ix(val); - } - }; +struct raw_access_t {}; - template , - 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)); - } - }; +template +struct FilteredIterator { + Parent parent; + Iterator first; + Iterator last; + Iterator current; + Getter getter; + Predicate predicate; - template - struct name_sort_impl { - using is_transparent = std::true_type; - template - struct FullCmp : S {}; + using iterator_category = std::bidirectional_iterator_tag; + using value_type = std::remove_reference_t>; + using difference_type = std::ptrdiff_t; + using pointer = value_type *; + using reference = value_type &; - template - struct FullCmp && - std::is_invocable_v>> { - [[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept { - return lexicographical_compare(s1, s2); - } - }; + constexpr FilteredIterator() noexcept = default; + constexpr FilteredIterator(const FilteredIterator &) = default; + constexpr FilteredIterator &operator=(const FilteredIterator &) = default; + constexpr FilteredIterator(FilteredIterator &&) noexcept = default; + constexpr FilteredIterator &operator=(FilteredIterator &&) noexcept = default; - template - [[nodiscard]] constexpr inline std::enable_if_t< - // at least one of need to be an enum type - (std::is_enum_v> || std::is_enum_v>) && - // if both is enum, only accept if the same enum - (!std::is_enum_v> || !std::is_enum_v> || std::is_same_v) && - // is invocable with comparator - (std::is_invocable_r_v, - std::conditional_t>, string_view, E1>, - std::conditional_t>, string_view, E2>>), bool> operator()(E1 e1, E2 e2) const noexcept { - using D1 = std::decay_t; - using D2 = std::decay_t; - constexpr FullCmp<> cmp{}; + template && std::is_convertible_v> *> + constexpr explicit FilteredIterator(const FilteredIterator &other) + : parent(other.parent), first(other.first), last(other.last), current(other.current), getter(other.getter), predicate(other.predicate) {} - if constexpr (std::is_enum_v && std::is_enum_v) { - return cmp(enum_name(e1), enum_name(e2)); - } else if constexpr (std::is_enum_v) { - return cmp(enum_name(e1), e2); - } else /* if constexpr (std::is_enum_v) */ { - return cmp(e1, enum_name(e2)); - } - } - }; + ~FilteredIterator() = default; - struct raw_access_t {}; - - template - struct FilteredIterator { - Parent parent; - Iterator first; - Iterator last; - Iterator current; - Getter getter; - Predicate predicate; - - using iterator_category = std::bidirectional_iterator_tag; - using value_type = std::remove_reference_t>; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - constexpr FilteredIterator() noexcept = default; - constexpr FilteredIterator(const FilteredIterator&) = default; - constexpr FilteredIterator& operator=(const FilteredIterator&) = default; - constexpr FilteredIterator(FilteredIterator&&) noexcept = default; - constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default; - - template && std::is_convertible_v>*> - constexpr explicit FilteredIterator(const FilteredIterator& other) - : 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)} - { - if (current == first && !predicate(parent, current)) { - ++*this; - } - } - - [[nodiscard]] constexpr reference operator*() const { - return getter(parent, current); - } - - [[nodiscard]] constexpr pointer operator->() const { - return std::addressof(**this); - } - - constexpr FilteredIterator& operator++() { - do { - ++current; - } while(current != last && !predicate(parent, current)); - return *this; - } - - [[nodiscard]] constexpr FilteredIterator operator++(int) { - FilteredIterator cp = *this; + 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)} { + if (current == first && !predicate(parent, current)) { ++*this; - return cp; } + } - constexpr FilteredIterator& operator--() { - do { - --current; - } while(current != first && !predicate(parent, current)); - return *this; - } + [[nodiscard]] constexpr reference operator*() const { return getter(parent, current); } - [[nodiscard]] constexpr FilteredIterator operator--(int) { - FilteredIterator cp = *this; - --*this; - return cp; - } + [[nodiscard]] constexpr pointer operator->() const { return std::addressof(**this); } - [[nodiscard]] friend constexpr bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) { - return lhs.current == rhs.current; - } + constexpr FilteredIterator &operator++() { + do { + ++current; + } while (current != last && !predicate(parent, current)); + return *this; + } - [[nodiscard]] friend constexpr bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) { - return lhs.current != rhs.current; - } - }; -} // detail + [[nodiscard]] constexpr FilteredIterator operator++(int) { + FilteredIterator cp = *this; + ++*this; + return cp; + } + + constexpr FilteredIterator &operator--() { + do { + --current; + } while (current != first && !predicate(parent, current)); + return *this; + } + + [[nodiscard]] constexpr FilteredIterator operator--(int) { + FilteredIterator cp = *this; + --*this; + 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; } +}; + +} // namespace detail template using name_less [[maybe_unused]] = detail::name_sort_impl; @@ -333,7 +309,6 @@ using default_indexing = detail::indexing; template > using comparator_indexing [[maybe_unused]] = detail::indexing; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ARRAY // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -341,7 +316,7 @@ template > struct array { static_assert(std::is_enum_v); static_assert(std::is_trivially_constructible_v); - static_assert(enum_count() == 0 || Index{}(enum_values().front()) ); // check Index is constexpr + static_assert(enum_count() == 0 || Index{}(enum_values().front())); // check Index is constexpr using index_type = Index; using container_type = std::array()>; @@ -372,105 +347,59 @@ 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) { + constexpr void fill(const V &value) { + for (auto &v : a) { v = value; } } - constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v) { + constexpr void swap(array &other) noexcept(std::is_nothrow_swappable_v) { for (std::size_t i{}; i < a.size(); ++i) { auto v = std::move(other.a[i]); other.a[i] = std::move(a[i]); @@ -478,63 +407,51 @@ 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; }; namespace detail { - template - constexpr array> to_array_impl(T (&a)[N], std::index_sequence) { - return {{a[I]...}}; - } - - template - constexpr array> to_array_impl(T (&&a)[N], std::index_sequence) { - return {{std::move(a[I])...}}; - } +template +constexpr array> to_array_impl(T (&a)[N], std::index_sequence) { + return {{a[I]...}}; } +template +constexpr array> to_array_impl(T(&&a)[N], std::index_sequence) { + return {{std::move(a[I])...}}; +} + +} // namespace detail + template constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T (&a)[N]) { return detail::to_array_impl(a, std::make_index_sequence{}); } template -constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T (&&a)[N]) { +constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T(&&a)[N]) { return detail::to_array_impl(std::move(a), std::make_index_sequence{}); } -template -constexpr std::enable_if_t<(enum_count() == sizeof...(Ts)), array>>> make_array(Ts&& ... ts) { +template +constexpr std::enable_if_t<(enum_count() == sizeof...(Ts)), array>>> make_array(Ts &&... ts) { return {{std::forward(ts)...}}; } -inline constexpr detail::raw_access_t raw_access {}; - +inline constexpr detail::raw_access_t raw_access{}; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BITSET // @@ -543,18 +460,19 @@ template > class bitset { static_assert(std::is_enum_v); static_assert(std::is_trivially_constructible_v); - static_assert(enum_count() == 0 || Index{}(enum_values().front()) ); // check Index is constexpr + static_assert(enum_count() == 0 || Index{}(enum_values().front())); // check Index is constexpr using base_type = std::conditional_t() <= 8, std::uint_least8_t, std::conditional_t() <= 16, std::uint_least16_t, std::conditional_t() <= 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() > 0 ? (enum_count() - 1) / bits_per_base + 1 : 0); constexpr static std::size_t not_interested = base_type_count * bits_per_base - enum_count(); constexpr static base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1; - template + template class reference_impl { friend class bitset; @@ -562,18 +480,14 @@ class bitset { std::size_t num_index; 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)}) - {} + 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)}) {} constexpr reference_impl(parent_t parent, std::pair 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 { + constexpr reference_impl &operator=(bool v) noexcept { if (v) { parent->a[num_index] |= bit_index; } else { @@ -582,7 +496,7 @@ class bitset { return *this; } - constexpr reference_impl& operator=(const reference_impl& v) noexcept { + constexpr reference_impl &operator=(const reference_impl &v) noexcept { if (this == &v) { return *this; } @@ -590,15 +504,11 @@ 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(*this); - } + [[nodiscard]] constexpr bool operator~() const noexcept { return !static_cast(*this); } - constexpr reference_impl& flip() noexcept { + constexpr reference_impl &flip() noexcept { *this = ~*this; return *this; } @@ -618,11 +528,12 @@ class bitset { } return res; } + public: using index_type = Index; using container_type = std::array; using reference = reference_impl<>; - using const_reference = reference_impl; + using const_reference = reference_impl; constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept : a{{}} {} @@ -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,29 +566,23 @@ 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::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::length(str), n)}, 0, n, zero, one) {} constexpr bitset(std::initializer_list starters) : a{{}} { - if constexpr (magic_enum::detail::is_flags_v) { - for (auto& f : starters) { + if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { + for (auto &f : starters) { *this |= bitset(f); } } else { - for (auto& f : starters) { + for (auto &f : starters) { set(f); } } } template - constexpr explicit bitset(std::enable_if_t, E> starter) : a{{}} { + constexpr explicit bitset(std::enable_if_t == magic_enum::detail::enum_subtype::flags, E> starter) : a{{}} { auto u = enum_underlying(starter); for (E v : enum_values()) { if (auto ul = enum_underlying(v); (ul & u) != 0) { @@ -695,10 +596,8 @@ public: } template > - 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)) { + 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(sv.substr(0, to), cmp)) { set(v); } else { @@ -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(const_reference(this, *index_type{}(pos))); - } + [[nodiscard]] constexpr bool operator[](E pos) const noexcept { return static_cast(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)) { @@ -755,7 +646,7 @@ public: } [[nodiscard]] constexpr bool any() const noexcept { - for (auto& v : a) { + for (auto &v : a) { if (v > 0) { return true; } @@ -763,41 +654,35 @@ 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{}; - for (auto& v : a) { + for (auto &v : a) { c += detail::popcount(v); } return c; } - [[nodiscard]] constexpr std::size_t size() const noexcept { - return enum_count(); - } + [[nodiscard]] constexpr std::size_t size() const noexcept { return enum_count(); } - [[nodiscard]] constexpr std::size_t max_size() const noexcept { - return enum_count(); - } + [[nodiscard]] constexpr std::size_t max_size() const noexcept { return enum_count(); } - constexpr bitset& operator&= (const bitset& other) noexcept { + constexpr bitset &operator&=(const bitset &other) noexcept { for (std::size_t i{}; i < base_type_count; ++i) { a[i] &= other.a[i]; } return *this; } - constexpr bitset& operator|= (const bitset& other) noexcept { + constexpr bitset &operator|=(const bitset &other) noexcept { for (std::size_t i{}; i < base_type_count; ++i) { a[i] |= other.a[i]; } return *this; } - constexpr bitset& operator^= (const bitset& other) noexcept { + constexpr bitset &operator^=(const bitset &other) noexcept { for (std::size_t i{}; i < base_type_count; ++i) { a[i] ^= other.a[i]; } @@ -816,7 +701,7 @@ public: return res; } - constexpr bitset& set() noexcept { + constexpr bitset &set() noexcept { for (std::size_t i{}; i < base_type_count - (not_interested > 0); ++i) { a[i] = ~base_type{}; } @@ -827,7 +712,7 @@ public: return *this; } - constexpr bitset& set(E pos, bool value = true) { + constexpr bitset &set(E pos, bool value = true) { if (auto ix = index_type{}(pos)) { reference{this, *ix} = value; return *this; @@ -835,11 +720,9 @@ 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) { + constexpr bitset &reset(E pos) { if (auto ix = index_type{}(pos)) { reference{this, *ix} = false; return *this; @@ -847,32 +730,30 @@ 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 { + [[nodiscard]] friend constexpr bitset operator&(const bitset &lhs, const bitset &rhs) noexcept { bitset cp = lhs; cp &= rhs; return cp; } - [[nodiscard]] friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept { + [[nodiscard]] friend constexpr bitset operator|(const bitset &lhs, const bitset &rhs) noexcept { bitset cp = lhs; cp |= rhs; return cp; } - [[nodiscard]] friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept { + [[nodiscard]] friend constexpr bitset operator^(const bitset &lhs, const bitset &rhs) noexcept { bitset cp = lhs; cp ^= rhs; return cp; } template - [[nodiscard]] constexpr explicit operator std::enable_if_t, E>() const { + [[nodiscard]]constexpr explicit operator std::enable_if_t == magic_enum::detail::enum_subtype::flags, E>() const { E res{}; - for (auto& e : enum_values()) { + for (auto &e : enum_values()) { if (test(e)) { res |= e; } @@ -881,27 +762,21 @@ public: } [[nodiscard]] string to_string(char sep = '|') const { - // if constexpr (magic_enum::detail::is_flags_v) { - // return enum_flags_name(static_cast(*this), sep); - // } else { - string name; + string name; - for (auto& e : enum_values()) { - if (test(e)) { - if (!name.empty()) { - name.append(1, sep); - } - auto n = enum_name(e); - name.append(n.data(), n.size()); + for (auto &e : enum_values()) { + if (test(e)) { + if (!name.empty()) { + name.append(1, sep); } + auto n = enum_name(e); + name.append(n.data(), n.size()); } - return name; - // } + } + 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,19 +785,13 @@ public: return name; } - [[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { - return to_(raw); - } + [[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { return to_(raw); } - [[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { - return to_(raw); - } + [[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { return to_(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) { + friend std::istream &operator>>(std::istream &i, bitset &bs) { string s; if (i >> s; !s.empty()) { bs = bitset(string_view{s}); @@ -934,7 +803,6 @@ private: container_type a; }; - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SET // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -942,17 +810,13 @@ template > class set { using index_type = detail::indexing; 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; using key_type = E; using value_type = E; @@ -960,12 +824,12 @@ public: using difference_type = std::ptrdiff_t; using key_compare = CExprLess; using value_compare = CExprLess; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; - using iterator = detail::FilteredIterator; - using const_iterator = detail::FilteredIterator; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = value_type *; + using const_pointer = const value_type *; + using iterator = detail::FilteredIterator; + using const_iterator = detail::FilteredIterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; @@ -985,7 +849,7 @@ public: } template - constexpr explicit set(std::enable_if_t, E> starter) { + constexpr explicit set(std::enable_if_t == magic_enum::detail::enum_subtype::flags, E> starter) { auto u = enum_underlying(starter); for (E v : enum_values()) { if ((enum_underlying(v) & u) != 0) { @@ -994,71 +858,49 @@ public: } } - constexpr set(const set&) noexcept = default; - constexpr set(set&&) noexcept = default; + constexpr set(const set &) noexcept = default; + constexpr set(set &&) noexcept = default; - constexpr set& operator=(const set&) noexcept = default; - constexpr set& operator=(set&&) noexcept = default; - constexpr set& operator=(std::initializer_list ilist) { + constexpr set &operator=(const set &) noexcept = default; + constexpr set &operator=(set &&) noexcept = default; + constexpr set &operator=(std::initializer_list ilist) { for (auto e : ilist) { insert(e); } } 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(); s = 0; } - constexpr std::pair insert(const value_type& value) noexcept { + constexpr std::pair insert(const value_type &value) noexcept { if (auto i = index_type{}(value)) { typename container_type::reference ref = a[value]; bool r = !ref; @@ -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 insert(value_type&& value) noexcept { - return insert(value); - } + constexpr std::pair 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 constexpr void insert(InputIt first, InputIt last) noexcept { @@ -1100,14 +934,10 @@ public: } template - constexpr std::pair emplace(Args&&... args) noexcept { - return insert({std::forward(args)...}); - } + constexpr std::pair emplace(Args &&... args) noexcept { return insert({std::forward(args)...}); } template - constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept { - return emplace(std::forward(args)...).first; - } + constexpr iterator emplace_hint(const_iterator, Args &&... args) noexcept { return emplace(std::forward(args)...).first; } constexpr iterator erase(const_iterator pos) noexcept { erase(*pos++); @@ -1115,11 +945,13 @@ public: } constexpr iterator erase(const_iterator first, const_iterator last) noexcept { - while((first = erase(first)) != last) { ; } + while ((first = erase(first)) != last) { + ; + } return first; } - constexpr size_type erase(const key_type& key) noexcept { + constexpr size_type erase(const key_type &key) noexcept { typename container_type::reference ref = a[key]; bool res = ref; if (res) { @@ -1130,27 +962,24 @@ public: } template - constexpr std::enable_if_t, size_type> erase(K&& x) noexcept { + constexpr std::enable_if_t, 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; } - void swap(set& other) noexcept { + void swap(set &other) noexcept { set cp = *this; *this = other; 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 - [[nodiscard]] constexpr std::enable_if_t, size_type> count(const K& x) const { + [[nodiscard]] constexpr std::enable_if_t, size_type> count(const K &x) const { 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; ++first) { c += count(*first); @@ -1158,16 +987,14 @@ public: return c; } - [[nodiscard]] constexpr const_iterator find(const key_type & key) const noexcept { + [[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(); } template - [[nodiscard]] constexpr std::enable_if_t, const_iterator> find(const K& x) const { + [[nodiscard]] constexpr std::enable_if_t, const_iterator> find(const K &x) const { for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); first != last; ++first) { if (a.test(*first)) { return find(*first); @@ -1176,76 +1003,66 @@ 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 - [[nodiscard]] constexpr std::enable_if_t, bool> contains(const K& x) const noexcept { + [[nodiscard]] constexpr std::enable_if_t, bool> contains(const K &x) const noexcept { return count(x) > 0; } - [[nodiscard]] constexpr std::pair equal_range(const key_type& key) const noexcept { + [[nodiscard]] constexpr std::pair equal_range(const key_type &key) const noexcept { return {lower_bound(key), upper_bound(key)}; } template - [[nodiscard]] constexpr std::enable_if_t, std::pair> equal_range(const K& x) const noexcept { + [[nodiscard]] constexpr std::enable_if_t, std::pair> equal_range(const K &x) const noexcept { return {lower_bound(x), upper_bound(x)}; } - [[nodiscard]] constexpr const_iterator lower_bound(const key_type& key) const noexcept { + [[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(); } template - [[nodiscard]] constexpr std::enable_if_t, const_iterator> lower_bound(const K& x) const noexcept { + [[nodiscard]] constexpr std::enable_if_t, const_iterator> lower_bound(const K &x) const noexcept { auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); return first != last ? lower_bound(*first) : end(); } - [[nodiscard]] constexpr const_iterator upper_bound(const key_type& key) const noexcept { + [[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(); } template - [[nodiscard]] constexpr std::enable_if_t, const_iterator> upper_bound(const K& x) const noexcept { + [[nodiscard]] constexpr std::enable_if_t, const_iterator> upper_bound(const K &x) const noexcept { auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); 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; } + [[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; + } - for (auto& e : *index_type::values_v) { + for (auto &e : *index_type::values_v) { if (auto c = rhs.contains(e); c != lhs.contains(e)) { return c; } @@ -1253,22 +1070,16 @@ 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 size_type erase_if(Pred pred) { auto old_size = size(); - for (auto i = begin(), last = end(); i != last; ) { + for (auto i = begin(), last = end(); i != last;) { if (pred(*i)) { i = erase(i); } else { @@ -1284,54 +1095,58 @@ private: std::size_t s{}; }; +} // namespace magic_enum::containers + namespace std { - template - constexpr std::enable_if_t<(std::is_integral_v && - I < magic_enum::enum_count()), V&> get( magic_enum::containers::array& a ) noexcept { - return a.a[I]; - } - template - constexpr std::enable_if_t<(std::is_integral_v && - I < magic_enum::enum_count()), V&&> get( magic_enum::containers::array&& a ) noexcept { - return std::move(a.a[I]); - } - - template - constexpr std::enable_if_t<(std::is_integral_v && - I < magic_enum::enum_count()), const V&> get( const magic_enum::containers::array& a ) noexcept { - return a.a[I]; - } - - template - constexpr std::enable_if_t<(std::is_integral_v && - I < magic_enum::enum_count()), const V&&> get( const magic_enum::containers::array&& a ) noexcept { - return std::move(a.a[I]); - } - - template - constexpr std::enable_if_t && - magic_enum::enum_contains(Enum), V&> get( magic_enum::containers::array& a ) noexcept { - return a[Enum]; - } - - template - constexpr std::enable_if_t && - magic_enum::enum_contains(Enum), V&&> get( magic_enum::containers::array&& a ) noexcept { - return std::move(a[Enum]); - } - - template - constexpr std::enable_if_t && - magic_enum::enum_contains(Enum), const V&> get( const magic_enum::containers::array& a ) noexcept { - return a[Enum]; - } - - template - constexpr std::enable_if_t && - magic_enum::enum_contains(Enum), const V&&> get( const magic_enum::containers::array&& a ) noexcept { - return std::move(a[Enum]); - } +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), V &> +get(magic_enum::containers::array &a) noexcept { + return a.a[I]; } +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), V &&> +get(magic_enum::containers::array &&a) noexcept { + return std::move(a.a[I]); +} + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), const V &> +get(const magic_enum::containers::array &a) noexcept { + return a.a[I]; +} + +template +constexpr std::enable_if_t<(std::is_integral_v && I < magic_enum::enum_count()), const V &&> +get(const magic_enum::containers::array &&a) noexcept { + return std::move(a.a[I]); +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), V &> +get(magic_enum::containers::array &a) noexcept { + return a[Enum]; +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), V &&> +get(magic_enum::containers::array &&a) noexcept { + return std::move(a[Enum]); +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), const V &> +get(const magic_enum::containers::array &a) noexcept { + return a[Enum]; +} + +template +constexpr std::enable_if_t && magic_enum::enum_contains(Enum), const V &&> +get(const magic_enum::containers::array &&a) noexcept { + return std::move(a[Enum]); +} + +} // namespace std + #endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP diff --git a/include/magic_enum_switch.hpp b/include/magic_enum_switch.hpp index 7520d96..41dd9cf 100644 --- a/include/magic_enum_switch.hpp +++ b/include/magic_enum_switch.hpp @@ -142,7 +142,7 @@ constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) { } // namespace magic_enum::detail -template >, typename F, typename R = detail::result_t> +template , typename F, typename R = detail::result_t> constexpr decltype(auto) enum_switch(F&& f, E value) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); @@ -165,7 +165,7 @@ constexpr decltype(auto) enum_switch(F&& f, E value) { return enum_switch(std::forward(f), value); } -template >, typename F, typename R = detail::result_t> +template , typename F, typename R = detail::result_t> constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ba4dede..aabf550 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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() diff --git a/test/test_containers.cpp b/test/test_containers.cpp index 918eaaf..73145e5 100644 --- a/test/test_containers.cpp +++ b/test/test_containers.cpp @@ -37,10 +37,15 @@ #include #include +#include #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; +}; enum class Empty {};