From 77ab2446d48636fd17e4f05b00cf0ae9ca0e95af Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Fri, 31 Jan 2025 19:14:36 +0100 Subject: enum_set enhancements, step 2 * remove support of size computation based on "magic" enum element because Oracle SunPro compilers crash on it. * enhance handling of enum_set with explicit size. --- Tests/CMakeLib/testCMExtEnumSet.cxx | 58 ++++++------- Utilities/std/cmext/enum_set | 162 ++++++++++++++++++------------------ 2 files changed, 106 insertions(+), 114 deletions(-) diff --git a/Tests/CMakeLib/testCMExtEnumSet.cxx b/Tests/CMakeLib/testCMExtEnumSet.cxx index c08ea11..218b837 100644 --- a/Tests/CMakeLib/testCMExtEnumSet.cxx +++ b/Tests/CMakeLib/testCMExtEnumSet.cxx @@ -68,21 +68,6 @@ void testDeclaration() ++failed; } } - { - enum class Test : std::uint8_t - { - A, - B, - C, - D, - cm_count = D - }; - cm::enum_set testSet1; - - if (testSet1.size() != 0 || testSet1.max_size() != 4) { - ++failed; - } - } } void testIteration() @@ -94,10 +79,9 @@ void testIteration() A, B, C, - D, - cm_count = D + D }; - cm::enum_set testSet{ Test::A, Test::C, Test::B }; + cm::enum_set testSet{ Test::A, Test::C, Test::B }; if (testSet.size() != 3) { ++failed; @@ -134,8 +118,7 @@ void testEdition() B, C, D, - E, - cm_count = E + E }; { @@ -281,32 +264,42 @@ void testEdition() } } { - cm::enum_set testSet1; - cm::enum_set testSet2{ Test::A, Test::C, Test::B }; + using ESet = cm::enum_set; + ESet testSet1; + ESet testSet2{ Test::A, Test::C, Test::B }; testSet1.set(); if (testSet1.size() != 5 || testSet1.size() != testSet1.max_size()) { ++failed; } - testSet1.flip(Test::D | Test::E); + testSet1.flip({ Test::D, Test::E }); if (testSet1.size() != 3 || testSet1 != testSet2) { ++failed; } - testSet1.flip(Test::D); - testSet2 += Test::D; + testSet1.flip(Test::D | Test::E); + testSet2 += Test::D + Test::E; + if (testSet1.size() != 5 || testSet1 != testSet2) { + ++failed; + } + testSet1.flip(Test::E); + testSet2 -= Test::E; if (testSet1.size() != 4 || testSet1 != testSet2) { ++failed; } testSet1 ^= { Test::A, Test::B, Test::E, Test::D }; - testSet2 = Test::C + Test::E; + testSet2 = { Test::C, Test::E }; if (testSet1.size() != 2 || testSet1 != testSet2) { ++failed; } - testSet1 ^= Test::A | Test::B | Test::E; + testSet1 ^= { Test::A, Test::B, Test::E }; testSet2 = { Test::A, Test::B, Test::C }; if (testSet1.size() != 3 || testSet1 != testSet2) { ++failed; } + testSet2 = Test::A | Test::B | Test::C; + if (testSet1.size() != 3 || testSet1 != testSet2) { + ++failed; + } } } @@ -320,8 +313,7 @@ void testChecks() A, B, C, - D, - cm_count = D + D }; cm::enum_set testSet; @@ -353,11 +345,10 @@ void testChecks() A, B, C, - D, - cm_count = D + D }; - cm::enum_set testSet; + cm::enum_set testSet; if (!testSet.none()) { ++failed; @@ -382,8 +373,7 @@ void testChecks() A, B, C, - D, - cm_count = D + D }; cm::enum_set testSet1; diff --git a/Utilities/std/cmext/enum_set b/Utilities/std/cmext/enum_set index f851d29..f1d615a 100644 --- a/Utilities/std/cmext/enum_set +++ b/Utilities/std/cmext/enum_set @@ -31,12 +31,6 @@ // enum class Example : unsigned { A, B, C, D }; // using ExampleSet = enum_set; // -// Another possibility is to add, at the end of the list, the definition -// 'cm_count' with the value of the precedent definition: -// -// enum class Example : unsigned { A, B, C, D, cm_count = D }; -// using ExampleSet = enum_set; -// // To facilitate the usage of the enum_set, operators '+' and '|' can be used // as alternate to the 'initializer_list': // @@ -47,21 +41,6 @@ namespace cm { -namespace internals { -template -struct enum_size -{ - static constexpr auto value = - std::numeric_limits::type>::digits; -}; -template -struct enum_size> -{ - static constexpr auto value = - static_cast::type>(Enum::cm_count) + 1; -}; -} - template class enum_set_iterator { @@ -144,7 +123,9 @@ private: }; template < - typename Enum, std::size_t Size = internals::enum_size::value, + typename Enum, + std::size_t Size = + std::numeric_limits::type>::digits, typename cm::enable_if_t< cm::is_scoped_enum::value && std::is_unsigned::type>::value, @@ -152,6 +133,8 @@ template < class enum_set { public: + static constexpr std::size_t set_size = Size; + using key_type = Enum; using value_type = Enum; using size_type = typename std::underlying_type::type; @@ -169,6 +152,14 @@ public: constexpr enum_set() noexcept = default; enum_set(key_type e) { this->insert(e); } enum_set(enum_set const& other) noexcept { this->insert(other); } + template ::value, int> = 0> + enum_set(enum_set const& other) noexcept + { + static_assert(Size < enum_set::set_size, "Incompatible sizes"); + + this->insert(other.cbegin(), other.cend()); + } enum_set(std::initializer_list list) { this->insert(list); } enum_set& operator=(key_type e) @@ -446,12 +437,12 @@ public: } private: - template - friend inline bool operator==(enum_set const& lhs, - enum_set const& rhs) noexcept; + template + friend inline bool operator==(enum_set const& lhs, + enum_set const& rhs) noexcept; - template - friend inline void erase_if(enum_set& set, Predicate pred); + template + friend inline void erase_if(enum_set& set, Predicate pred); friend class enum_set_iterator; friend class enum_set_iterator; @@ -462,99 +453,104 @@ private: }; // non-member functions for enum_set -template -inline enum_set operator+(enum_set const& lhs, Enum rhs) +template +inline enum_set operator+(enum_set const& lhs, + Enum rhs) { - return enum_set{ lhs } += rhs; + return enum_set{ lhs } += rhs; } -template -inline enum_set operator+(enum_set const& lhs, - enum_set const& rhs) noexcept +template +inline enum_set operator+(enum_set const& lhs, + enum_set const& rhs) noexcept { - return enum_set{ lhs } += rhs; + return enum_set{ lhs } += rhs; } -template -inline enum_set operator+(enum_set const& lhs, - std::initializer_list const rhs) +template +inline enum_set operator+(enum_set const& lhs, + std::initializer_list const rhs) { - return enum_set{ lhs } += rhs; + return enum_set{ lhs } += rhs; } -template -inline cm::enum_set operator|(cm::enum_set const& lhs, Enum rhs) +template +inline cm::enum_set operator|(cm::enum_set const& lhs, + Enum rhs) { - return enum_set{ lhs } |= rhs; + return enum_set{ lhs } |= rhs; } -template -inline cm::enum_set operator|(Enum lhs, cm::enum_set const& rhs) +template +inline cm::enum_set operator|(Enum lhs, + cm::enum_set const& rhs) { - return enum_set{ lhs } |= rhs; + return enum_set{ lhs } |= rhs; } -template -inline cm::enum_set operator|(cm::enum_set const& lhs, - cm::enum_set const& rhs) +template +inline cm::enum_set operator|(cm::enum_set const& lhs, + cm::enum_set const& rhs) { - return enum_set{ lhs } |= rhs; + return enum_set{ lhs } |= rhs; } -template -inline enum_set operator-(enum_set const& lhs, Enum rhs) +template +inline enum_set operator-(enum_set const& lhs, + Enum rhs) { - return enum_set{ lhs } -= rhs; + return enum_set{ lhs } -= rhs; } -template -inline enum_set operator-(enum_set const& lhs, - enum_set const& rhs) noexcept +template +inline enum_set operator-(enum_set const& lhs, + enum_set const& rhs) noexcept { - return enum_set{ lhs } -= rhs; + return enum_set{ lhs } -= rhs; } -template -inline enum_set operator-(enum_set const& lhs, - std::initializer_list const rhs) +template +inline enum_set operator-(enum_set const& lhs, + std::initializer_list const rhs) { - return enum_set{ lhs } -= rhs; + return enum_set{ lhs } -= rhs; } -template -inline enum_set operator^(enum_set const& lhs, Enum rhs) +template +inline enum_set operator^(enum_set const& lhs, + Enum rhs) { - return enum_set{ lhs } ^= rhs; + return enum_set{ lhs } ^= rhs; } -template -inline enum_set operator^(enum_set const& lhs, - enum_set const& rhs) noexcept +template +inline enum_set operator^(enum_set const& lhs, + enum_set const& rhs) noexcept { - return enum_set{ lhs } ^= rhs; + return enum_set{ lhs } ^= rhs; } -template -inline enum_set operator^(enum_set const& lhs, - std::initializer_list const rhs) +template +inline enum_set operator^(enum_set const& lhs, + std::initializer_list const rhs) { - return enum_set{ lhs } ^= rhs; + return enum_set{ lhs } ^= rhs; } -template -inline bool operator==(enum_set const& lhs, - enum_set const& rhs) noexcept +template +inline bool operator==(enum_set const& lhs, + enum_set const& rhs) noexcept { return lhs.Set == rhs.Set; } -template -inline bool operator!=(enum_set const& lhs, - enum_set const& rhs) noexcept +template +inline bool operator!=(enum_set const& lhs, + enum_set const& rhs) noexcept { return !(lhs == rhs); } -template -inline void erase(enum_set& set, Enum value) +template +inline void erase(enum_set& set, Enum value) { set.erase(value); } -template -inline void erase_if(enum_set& set, Predicate pred) +template +inline void erase_if(enum_set& set, Predicate pred) { for (std::size_t index = 0; index < set.Set.size(); ++index) { if (set.Set.test(index) && pred(static_cast(index))) { @@ -564,6 +560,12 @@ inline void erase_if(enum_set& set, Predicate pred) } } // namespace cm +// +// WARNING: the following two functions rely on an enum_set without +// explicit size. +// +// TODO: ensure compatibility with any enum_set definitions. +// template ::value, int> = 0> inline cm::enum_set operator+(Enum lhs, Enum rhs) -- cgit v0.12