diff --git a/example/example_containers_set.cpp b/example/example_containers_set.cpp index a1925d818..9a81ef99a 100644 --- a/example/example_containers_set.cpp +++ b/example/example_containers_set.cpp @@ -26,10 +26,6 @@ # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. #endif -#ifdef _WIN32 -#define _ITERATOR_DEBUG_LEVEL 0 -#endif - #include #include diff --git a/include/magic_enum_containers.hpp b/include/magic_enum_containers.hpp index 6f3156b70..d712af28a 100644 --- a/include/magic_enum_containers.hpp +++ b/include/magic_enum_containers.hpp @@ -48,10 +48,10 @@ namespace magic_enum::containers { namespace detail { template -[[maybe_unused]] constexpr static bool is_transparent_v{}; +static constexpr bool is_transparent_v{}; template -constexpr static bool is_transparent_v>{true}; +static constexpr bool is_transparent_v>{true}; template , typename T1, typename T2> constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) { @@ -100,7 +100,6 @@ constexpr std::size_t popcount(T x) noexcept { 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); @@ -121,8 +120,8 @@ constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) { } template , typename = void> -struct indexing { - [[nodiscard]] constexpr static auto get_indices() noexcept { +class indexing { + [[nodiscard]] static constexpr auto get_indices() noexcept { // reverse result index mapping std::array()> rev_res{}; @@ -156,37 +155,66 @@ struct indexing { 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; + static constexpr auto indices = get_indices(); + + public: + static constexpr auto& values = indices.first; + + [[nodiscard]] static constexpr const E* begin() noexcept { + return values.data(); + } - [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { + [[nodiscard]] static constexpr const E* end() noexcept { + return values.data() + values.size(); + } + + [[nodiscard]] static constexpr optional at(E val) noexcept { if (auto opt = enum_index(val)) { - return reindex[*opt]; + return indices.second[*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); } +class indexing> && (std::is_same_v> || std::is_same_v>)>> { + public: + static constexpr auto& values = enum_values(); + + [[nodiscard]] static constexpr const E* begin() noexcept { + return values.data(); + } + + [[nodiscard]] static constexpr const E* end() noexcept { + return values.data() + values.size(); + } + + [[nodiscard]] static constexpr optional at(E val) noexcept { return enum_index(val); } }; template struct indexing { using is_transparent = std::true_type; + + template + [[nodiscard]] static constexpr const E* begin() noexcept { + return indexing::begin(); + } + template - [[nodiscard]] constexpr inline optional operator()(E val) const noexcept { - constexpr indexing ix{}; - return ix(val); + [[nodiscard]] static constexpr const E* end() noexcept { + return indexing::end(); + } + + template + [[nodiscard]] constexpr optional at(E val) noexcept { + return indexing::at(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)); } + [[nodiscard]] constexpr bool operator()(E e1, E e2) const noexcept { return OP{}(enum_name(e1), enum_name(e2)); } }; template @@ -197,18 +225,17 @@ struct name_sort_impl { 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); } + [[nodiscard]] constexpr bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare(s1, s2); } }; template - [[nodiscard]] constexpr inline std::enable_if_t< + [[nodiscard]] constexpr std::enable_if_t< // at least one of need to be an enum type - (std::is_enum_v> || std::is_enum_v>)&& + (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)&& + (!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>>), + (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; @@ -248,13 +275,10 @@ struct FilteredIterator { constexpr FilteredIterator(FilteredIterator&&) noexcept = default; constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default; - template && std::is_convertible_v>*> + 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)) { @@ -300,18 +324,20 @@ struct FilteredIterator { } // namespace detail template -using name_less [[maybe_unused]] = detail::name_sort_impl; +using name_less = detail::name_sort_impl; + template -using name_greater [[maybe_unused]] = detail::name_sort_impl>; +using name_greater = detail::name_sort_impl>; -using name_less_ci [[maybe_unused]] = detail::name_sort_impl>>; -using name_greater_ci [[maybe_unused]] = detail::name_sort_impl>>; +using name_less_case_insensitive = detail::name_sort_impl>>; + +using name_greater_case_insensitive = detail::name_sort_impl>>; template using default_indexing = detail::indexing; template > -using comparator_indexing [[maybe_unused]] = detail::indexing; +using comparator_indexing = detail::indexing; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ARRAY // @@ -320,7 +346,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::at(enum_values().front())); // check Index is constexpr using index_type = Index; using container_type = std::array()>; @@ -338,22 +364,22 @@ struct array { using const_reverse_iterator = typename container_type::const_reverse_iterator; constexpr reference at(E pos) { - if (auto index = index_type{}(pos)) { + if (auto index = index_type::at(pos)) { return a[*index]; } MAGIC_ENUM_THROW(std::out_of_range("enum array::at: unrecognized position")); } constexpr const_reference at(E pos) const { - if (auto index = index_type{}(pos)) { + if (auto index = index_type::at(pos)) { return a[*index]; } MAGIC_ENUM_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) { return a[*index_type::at(pos)]; } - [[nodiscard]] constexpr const_reference operator[](E pos) const noexcept { return a[*index_type{}(pos)]; } + [[nodiscard]] constexpr const_reference operator[](E pos) const { return a[*index_type::at(pos)]; } [[nodiscard]] constexpr reference front() noexcept { return a.front(); } @@ -464,17 +490,17 @@ 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::at(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; + static constexpr std::size_t bits_per_base = sizeof(base_type) * 8; + static constexpr std::size_t base_type_count = (enum_count() > 0 ? (enum_count() - 1) / bits_per_base + 1 : 0); + static constexpr std::size_t not_interested = base_type_count * bits_per_base - enum_count(); + static constexpr base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1; template class reference_impl { @@ -618,12 +644,12 @@ class bitset { [[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 { return static_cast(const_reference(this, *index_type::at(pos))); } - [[nodiscard]] constexpr reference operator[](E pos) noexcept { return reference{this, *index_type{}(pos)}; } + [[nodiscard]] constexpr reference operator[](E pos) { return reference{this, *index_type::at(pos)}; } constexpr bool test(E pos) const { - if (auto ix = index_type{}(pos)) { + if (auto ix = index_type::at(pos)) { return static_cast(const_reference(this, *ix)); } MAGIC_ENUM_THROW(std::out_of_range("enum bitset::test: unrecognized position")); @@ -714,7 +740,7 @@ class bitset { } constexpr bitset& set(E pos, bool value = true) { - if (auto ix = index_type{}(pos)) { + if (auto ix = index_type::at(pos)) { reference{this, *ix} = value; return *this; } @@ -724,7 +750,7 @@ class bitset { constexpr bitset& reset() noexcept { return *this = bitset{}; } constexpr bitset& reset(E pos) { - if (auto ix = index_type{}(pos)) { + if (auto ix = index_type::at(pos)) { reference{this, *ix} = false; return *this; } @@ -754,7 +780,7 @@ class bitset { template [[nodiscard]] constexpr explicit operator std::enable_if_t == magic_enum::detail::enum_subtype::flags, E>() const { E res{}; - for (auto& e : enum_values()) { + for (const auto& e : enum_values()) { if (test(e)) { res |= e; } @@ -765,7 +791,7 @@ class bitset { [[nodiscard]] string to_string(char_type sep = static_cast('|')) const { string name; - for (auto& e : enum_values()) { + for (const auto& e : enum_values()) { if (test(e)) { if (!name.empty()) { name.append(1, sep); @@ -873,11 +899,11 @@ class set { } 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::begin(), index_type::end(), index_type::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::begin(), index_type::end(), index_type::end()}; } constexpr const_iterator cbegin() const noexcept { return begin(); } @@ -904,7 +930,7 @@ class set { } constexpr std::pair insert(const value_type& value) noexcept { - if (auto i = index_type{}(value)) { + if (auto i = index_type::at(value)) { typename container_type::reference ref = a[value]; bool r = !ref; if (r) { @@ -912,7 +938,7 @@ class set { ++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::begin(), index_type::end(), &(index_type::values[*i])}, r}; } return {end(), false}; } @@ -953,7 +979,6 @@ class set { constexpr iterator erase(const_iterator first, const_iterator last) noexcept { while ((first = erase(first)) != last) { - ; } return first; } @@ -971,7 +996,7 @@ class set { template constexpr std::enable_if_t, size_type> erase(K&& x) noexcept { size_type c = 0; - 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::begin(), index_type::end(), x, key_compare{}); first != last;) { c += erase(*first++); } return c; @@ -983,26 +1008,27 @@ class set { 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::at(key) && a[key]; } template [[nodiscard]] constexpr std::enable_if_t, size_type> count(const K& x) const { size_type c = 0; - for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); first != last; ++first) { + for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { c += count(*first); } return c; } [[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]}; + if (auto i = index_type::at(key); i && a.test(key)) { + return const_iterator{this, index_type::begin(), index_type::end(), &(index_type::values[*i])}; + } return end(); } template [[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) { + for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { if (a.test(*first)) { return find(*first); } @@ -1025,8 +1051,8 @@ class set { } [[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]}; + if (auto i = index_type::at(key)) { + auto it = const_iterator{this, index_type::begin(), index_type::end(), &(index_type::values[*i])}; return a.test(key) ? it : std::next(it); } return end(); @@ -1034,20 +1060,20 @@ class set { template [[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{}); + auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); return first != last ? lower_bound(*first) : end(); } [[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]}); + if (auto i = index_type::at(key)) { + return std::next(const_iterator{this, index_type::begin(), index_type::end(), &(index_type::values[*i])}); } return end(); } template [[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{}); + auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); return first != last ? upper_bound(*std::prev(last)) : end(); } @@ -1067,7 +1093,7 @@ class set { return false; } - for (auto& e : *index_type::values_v) { + for (auto& e : index_type::values) { if (auto c = rhs.contains(e); c != lhs.contains(e)) { return c; } @@ -1093,7 +1119,6 @@ class set { } return old_size - size(); } - //... private: container_type a; diff --git a/test/test_containers.cpp b/test/test_containers.cpp index e9cbf4b4c..30d1e7390 100644 --- a/test/test_containers.cpp +++ b/test/test_containers.cpp @@ -30,10 +30,6 @@ # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. #endif -#ifdef _WIN32 -#define _ITERATOR_DEBUG_LEVEL 0 -#endif - #define CATCH_CONFIG_MAIN #include