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.
This commit is contained in:
Marc Chevrier
2025-01-31 19:14:36 +01:00
parent f28d76aeb4
commit 77ab2446d4
2 changed files with 106 additions and 114 deletions

View File

@@ -68,21 +68,6 @@ void testDeclaration()
++failed;
}
}
{
enum class Test : std::uint8_t
{
A,
B,
C,
D,
cm_count = D
};
cm::enum_set<Test> 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<Test> testSet{ Test::A, Test::C, Test::B };
cm::enum_set<Test, 4> 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<Test> testSet1;
cm::enum_set<Test> testSet2{ Test::A, Test::C, Test::B };
using ESet = cm::enum_set<Test, 5>;
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<Test> testSet;
@@ -353,11 +345,10 @@ void testChecks()
A,
B,
C,
D,
cm_count = D
D
};
cm::enum_set<Test> testSet;
cm::enum_set<Test, 4> testSet;
if (!testSet.none()) {
++failed;
@@ -382,8 +373,7 @@ void testChecks()
A,
B,
C,
D,
cm_count = D
D
};
cm::enum_set<Test> testSet1;

View File

@@ -31,12 +31,6 @@
// enum class Example : unsigned { A, B, C, D };
// using ExampleSet = enum_set<Example, 4>;
//
// 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<Example>;
//
// 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 <typename Enum, typename U = void>
struct enum_size
{
static constexpr auto value =
std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
};
template <typename Enum>
struct enum_size<Enum, cm::void_t<decltype(Enum::cm_count)>>
{
static constexpr auto value =
static_cast<typename std::underlying_type<Enum>::type>(Enum::cm_count) + 1;
};
}
template <typename EnumSet>
class enum_set_iterator
{
@@ -144,7 +123,9 @@ private:
};
template <
typename Enum, std::size_t Size = internals::enum_size<Enum>::value,
typename Enum,
std::size_t Size =
std::numeric_limits<typename std::underlying_type<Enum>::type>::digits,
typename cm::enable_if_t<
cm::is_scoped_enum<Enum>::value &&
std::is_unsigned<typename std::underlying_type<Enum>::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<Enum>::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 <typename E,
typename cm::enable_if_t<std::is_same<Enum, E>::value, int> = 0>
enum_set(enum_set<E> const& other) noexcept
{
static_assert(Size < enum_set<E>::set_size, "Incompatible sizes");
this->insert(other.cbegin(), other.cend());
}
enum_set(std::initializer_list<value_type> list) { this->insert(list); }
enum_set& operator=(key_type e)
@@ -446,12 +437,12 @@ public:
}
private:
template <typename E>
friend inline bool operator==(enum_set<E> const& lhs,
enum_set<E> const& rhs) noexcept;
template <typename E, std::size_t S>
friend inline bool operator==(enum_set<E, S> const& lhs,
enum_set<E, S> const& rhs) noexcept;
template <typename E, typename Predicate>
friend inline void erase_if(enum_set<E>& set, Predicate pred);
template <typename E, std::size_t S, typename Predicate>
friend inline void erase_if(enum_set<E, S>& set, Predicate pred);
friend class enum_set_iterator<enum_set>;
friend class enum_set_iterator<enum_set const>;
@@ -462,99 +453,104 @@ private:
};
// non-member functions for enum_set
template <typename Enum>
inline enum_set<Enum> operator+(enum_set<Enum> const& lhs, Enum rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,
Enum rhs)
{
return enum_set<Enum>{ lhs } += rhs;
return enum_set<Enum, Size>{ lhs } += rhs;
}
template <typename Enum>
inline enum_set<Enum> operator+(enum_set<Enum> const& lhs,
enum_set<Enum> const& rhs) noexcept
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,
enum_set<Enum, Size> const& rhs) noexcept
{
return enum_set<Enum>{ lhs } += rhs;
return enum_set<Enum, Size>{ lhs } += rhs;
}
template <typename Enum>
inline enum_set<Enum> operator+(enum_set<Enum> const& lhs,
std::initializer_list<Enum> const rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,
std::initializer_list<Enum> const rhs)
{
return enum_set<Enum>{ lhs } += rhs;
return enum_set<Enum, Size>{ lhs } += rhs;
}
template <typename Enum>
inline cm::enum_set<Enum> operator|(cm::enum_set<Enum> const& lhs, Enum rhs)
template <typename Enum, std::size_t Size>
inline cm::enum_set<Enum, Size> operator|(cm::enum_set<Enum, Size> const& lhs,
Enum rhs)
{
return enum_set<Enum>{ lhs } |= rhs;
return enum_set<Enum, Size>{ lhs } |= rhs;
}
template <typename Enum>
inline cm::enum_set<Enum> operator|(Enum lhs, cm::enum_set<Enum> const& rhs)
template <typename Enum, std::size_t Size>
inline cm::enum_set<Enum, Size> operator|(Enum lhs,
cm::enum_set<Enum, Size> const& rhs)
{
return enum_set<Enum>{ lhs } |= rhs;
return enum_set<Enum, Size>{ lhs } |= rhs;
}
template <typename Enum>
inline cm::enum_set<Enum> operator|(cm::enum_set<Enum> const& lhs,
cm::enum_set<Enum> const& rhs)
template <typename Enum, std::size_t Size>
inline cm::enum_set<Enum, Size> operator|(cm::enum_set<Enum, Size> const& lhs,
cm::enum_set<Enum, Size> const& rhs)
{
return enum_set<Enum>{ lhs } |= rhs;
return enum_set<Enum, Size>{ lhs } |= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator-(enum_set<Enum> const& lhs, Enum rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,
Enum rhs)
{
return enum_set<Enum>{ lhs } -= rhs;
return enum_set<Enum, Size>{ lhs } -= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator-(enum_set<Enum> const& lhs,
enum_set<Enum> const& rhs) noexcept
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,
enum_set<Enum, Size> const& rhs) noexcept
{
return enum_set<Enum>{ lhs } -= rhs;
return enum_set<Enum, Size>{ lhs } -= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator-(enum_set<Enum> const& lhs,
std::initializer_list<Enum> const rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,
std::initializer_list<Enum> const rhs)
{
return enum_set<Enum>{ lhs } -= rhs;
return enum_set<Enum, Size>{ lhs } -= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator^(enum_set<Enum> const& lhs, Enum rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,
Enum rhs)
{
return enum_set<Enum>{ lhs } ^= rhs;
return enum_set<Enum, Size>{ lhs } ^= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator^(enum_set<Enum> const& lhs,
enum_set<Enum> const& rhs) noexcept
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,
enum_set<Enum, Size> const& rhs) noexcept
{
return enum_set<Enum>{ lhs } ^= rhs;
return enum_set<Enum, Size>{ lhs } ^= rhs;
}
template <typename Enum>
inline enum_set<Enum> operator^(enum_set<Enum> const& lhs,
std::initializer_list<Enum> const rhs)
template <typename Enum, std::size_t Size>
inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,
std::initializer_list<Enum> const rhs)
{
return enum_set<Enum>{ lhs } ^= rhs;
return enum_set<Enum, Size>{ lhs } ^= rhs;
}
template <typename Enum>
inline bool operator==(enum_set<Enum> const& lhs,
enum_set<Enum> const& rhs) noexcept
template <typename Enum, std::size_t Size>
inline bool operator==(enum_set<Enum, Size> const& lhs,
enum_set<Enum, Size> const& rhs) noexcept
{
return lhs.Set == rhs.Set;
}
template <typename Enum>
inline bool operator!=(enum_set<Enum> const& lhs,
enum_set<Enum> const& rhs) noexcept
template <typename Enum, std::size_t Size>
inline bool operator!=(enum_set<Enum, Size> const& lhs,
enum_set<Enum, Size> const& rhs) noexcept
{
return !(lhs == rhs);
}
template <typename Enum>
inline void erase(enum_set<Enum>& set, Enum value)
template <typename Enum, std::size_t Size>
inline void erase(enum_set<Enum, Size>& set, Enum value)
{
set.erase(value);
}
template <typename Enum, typename Predicate>
inline void erase_if(enum_set<Enum>& set, Predicate pred)
template <typename Enum, std::size_t Size, typename Predicate>
inline void erase_if(enum_set<Enum, Size>& set, Predicate pred)
{
for (std::size_t index = 0; index < set.Set.size(); ++index) {
if (set.Set.test(index) && pred(static_cast<Enum>(index))) {
@@ -564,6 +560,12 @@ inline void erase_if(enum_set<Enum>& 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 <typename Enum,
typename cm::enable_if_t<cm::is_scoped_enum<Enum>::value, int> = 0>
inline cm::enum_set<Enum> operator+(Enum lhs, Enum rhs)