Merge topic 'enum_set-enhancements'

4d48958965 enum_set enhancements, step 3

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !10335
This commit is contained in:
Brad King 2025-02-15 12:31:17 +00:00 committed by Kitware Robot
commit f9e51b61cd
2 changed files with 171 additions and 99 deletions

View File

@ -14,24 +14,44 @@ namespace {
int failed = 0;
enum class Test : std::uint8_t
{
A,
B,
C,
D,
E
};
using EnumSetTest = cm::enum_set<Test>;
enum class Test2 : std::uint8_t
{
A,
B,
C,
D,
E
};
using EnumSetTest2 = cm::enum_set<Test2, 5>;
}
CM_ENUM_SET_TRAITS(EnumSetTest)
CM_ENUM_SET_TRAITS(EnumSetTest2)
namespace {
void testDeclaration()
{
std::cout << "testDeclaration()" << std::endl;
{
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test> testSet1;
cm::enum_set<Test> testSet2 = Test::A;
cm::enum_set<Test> testSet3 = Test::A | Test::C;
cm::enum_set<Test> testSet4 = Test::A + Test::C;
cm::enum_set<Test> testSet5{ Test::A, Test::C };
cm::enum_set<Test> testSet6 = testSet3;
EnumSetTest testSet1;
EnumSetTest testSet2 = Test::A;
EnumSetTest testSet3 = Test::A | Test::C;
EnumSetTest testSet4 = Test::A + Test::C;
EnumSetTest testSet5{ Test::A, Test::C };
EnumSetTest testSet6 = testSet3;
if (!testSet1.empty()) {
++failed;
@ -48,15 +68,50 @@ void testDeclaration()
}
}
{
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test> testSet1;
cm::enum_set<Test, 4> testSet2;
EnumSetTest2 testSet1;
EnumSetTest2 testSet2 = Test2::A;
EnumSetTest2 testSet3 = Test2::A | Test2::C;
EnumSetTest2 testSet4 = Test2::A + Test2::C;
EnumSetTest2 testSet5{ Test2::A, Test2::C };
EnumSetTest2 testSet6 = testSet3;
if (!testSet1.empty()) {
++failed;
}
if (testSet2.size() != 1) {
++failed;
}
if (testSet3.size() != 2 || testSet4.size() != 2 || testSet5.size() != 2 ||
testSet6.size() != 2) {
++failed;
}
if (testSet3 != testSet4 || testSet4 != testSet5 || testSet5 != testSet6) {
++failed;
}
}
{
using LocalEnumSetTest = cm::enum_set<Test>;
LocalEnumSetTest testSet1;
LocalEnumSetTest testSet2 = Test::A;
LocalEnumSetTest testSet3{ Test::A, Test::C };
LocalEnumSetTest testSet4 = testSet3;
if (!testSet1.empty()) {
++failed;
}
if (testSet2.size() != 1) {
++failed;
}
if (testSet3.size() != 2 || testSet4.size() != 2) {
++failed;
}
if (testSet3 != testSet4) {
++failed;
}
}
{
EnumSetTest testSet1;
EnumSetTest2 testSet2;
if (testSet1.size() != 0 ||
testSet1.max_size() !=
@ -64,7 +119,7 @@ void testDeclaration()
typename std::underlying_type<Test>::type>::digits) {
++failed;
}
if (testSet2.size() != 0 || testSet2.max_size() != 4) {
if (testSet2.size() != 0 || testSet2.max_size() != 5) {
++failed;
}
}
@ -74,14 +129,7 @@ void testIteration()
{
std::cout << "testIteration()" << std::endl;
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test, 4> testSet{ Test::A, Test::C, Test::B };
EnumSetTest2 testSet{ Test2::A, Test2::C, Test2::B };
if (testSet.size() != 3) {
++failed;
@ -112,17 +160,8 @@ void testEdition()
{
std::cout << "testEdition()" << std::endl;
enum class Test : std::uint8_t
{
A,
B,
C,
D,
E
};
{
cm::enum_set<Test> testSet{ Test::A, Test::C, Test::B };
EnumSetTest testSet{ Test::A, Test::C, Test::B };
auto pos = testSet.insert(Test::E);
if (!pos.second || testSet.size() != 4 || *(pos.first) != Test::E ||
@ -144,7 +183,7 @@ void testEdition()
}
}
{
cm::enum_set<Test> testSet{ Test::A, Test::C, Test::B };
EnumSetTest testSet{ Test::A, Test::C, Test::B };
testSet += { Test::D, Test::E };
@ -173,8 +212,8 @@ void testEdition()
}
}
{
cm::enum_set<Test> testSet1{ Test::A, Test::C, Test::B };
cm::enum_set<Test> testSet2{ Test::A, Test::D, Test::E };
EnumSetTest testSet1{ Test::A, Test::C, Test::B };
EnumSetTest testSet2{ Test::A, Test::D, Test::E };
testSet1.insert(testSet2.cbegin(), testSet2.cend());
std::set<std::uint8_t> reference{ static_cast<std::uint8_t>(Test::A),
@ -204,8 +243,8 @@ void testEdition()
}
}
{
cm::enum_set<Test> testSet1{ Test::A, Test::C, Test::B };
cm::enum_set<Test> testSet2{ Test::C, Test::E };
EnumSetTest testSet1{ Test::A, Test::C, Test::B };
EnumSetTest testSet2{ Test::C, Test::E };
testSet1.flip(Test::A);
if (testSet1.size() != 2 || testSet1.contains(Test::A)) {
@ -224,7 +263,7 @@ void testEdition()
}
}
{
cm::enum_set<Test> testSet1;
EnumSetTest testSet1;
auto testSet2 = Test::A + Test::C + Test::B;
testSet1.set({ Test::A, Test::C, Test::B });
@ -264,39 +303,38 @@ void testEdition()
}
}
{
using ESet = cm::enum_set<Test, 5>;
ESet testSet1;
ESet testSet2{ Test::A, Test::C, Test::B };
EnumSetTest2 testSet1;
EnumSetTest2 testSet2{ Test2::A, Test2::C, Test2::B };
testSet1.set();
if (testSet1.size() != 5 || testSet1.size() != testSet1.max_size()) {
++failed;
}
testSet1.flip({ Test::D, Test::E });
testSet1.flip({ Test2::D, Test2::E });
if (testSet1.size() != 3 || testSet1 != testSet2) {
++failed;
}
testSet1.flip(Test::D | Test::E);
testSet2 += Test::D + Test::E;
testSet1.flip(Test2::D | Test2::E);
testSet2 += Test2::D + Test2::E;
if (testSet1.size() != 5 || testSet1 != testSet2) {
++failed;
}
testSet1.flip(Test::E);
testSet2 -= Test::E;
testSet1.flip(Test2::E);
testSet2 -= Test2::E;
if (testSet1.size() != 4 || testSet1 != testSet2) {
++failed;
}
testSet1 ^= { Test::A, Test::B, Test::E, Test::D };
testSet2 = { Test::C, Test::E };
testSet1 ^= { Test2::A, Test2::B, Test2::E, Test2::D };
testSet2 = { Test2::C, Test2::E };
if (testSet1.size() != 2 || testSet1 != testSet2) {
++failed;
}
testSet1 ^= { Test::A, Test::B, Test::E };
testSet2 = { Test::A, Test::B, Test::C };
testSet1 ^= { Test2::A, Test2::B, Test2::E };
testSet2 = { Test2::A, Test2::B, Test2::C };
if (testSet1.size() != 3 || testSet1 != testSet2) {
++failed;
}
testSet2 = Test::A | Test::B | Test::C;
testSet2 = Test2::A | Test2::B | Test2::C;
if (testSet1.size() != 3 || testSet1 != testSet2) {
++failed;
}
@ -308,15 +346,7 @@ void testChecks()
std::cout << "testChecks()" << std::endl;
{
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test> testSet;
EnumSetTest testSet;
if (!testSet.empty()) {
++failed;
@ -340,15 +370,7 @@ void testChecks()
}
}
{
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test, 4> testSet;
EnumSetTest2 testSet;
if (!testSet.none()) {
++failed;
@ -357,7 +379,7 @@ void testChecks()
++failed;
}
testSet = Test::A;
testSet = Test2::A;
if (!testSet.any() || testSet.none() || testSet.all()) {
++failed;
}
@ -368,16 +390,8 @@ void testChecks()
}
}
{
enum class Test : std::uint8_t
{
A,
B,
C,
D
};
cm::enum_set<Test> testSet1;
cm::enum_set<Test> testSet2{ Test::A, Test::C };
EnumSetTest testSet1;
EnumSetTest testSet2{ Test::A, Test::C };
if (!testSet1.none_of(testSet2) || testSet1.any_of(testSet2) ||
testSet1.all_of(testSet2)) {

View File

@ -561,21 +561,79 @@ inline void erase_if(enum_set<Enum, Size>& set, Predicate pred)
} // namespace cm
//
// WARNING: the following two functions rely on an enum_set without
// explicit size.
// WARNING: the following two operators rely on the enum_set_traits<Enum>
// struct definition.
// The macro CM_ENUM_SET_TRAITS(EnumSet) can be used to define this structure.
//
// TODO: ensure compatibility with any enum_set definitions.
// Notes:
// When CM_ENUM_SET_TRAITS is used, the following restrictions applies:
// * Due to language constraints, the enum_set_traits specialization must
// occur outside of any namespace or function definition.
// * Only one enum_set instantiation is supported per enum class type.
//
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)
template <typename Enum>
struct cm_enum_set_traits
{
return cm::enum_set<Enum>{ lhs, rhs };
};
namespace cm {
template <typename Enum, typename = cm::void_t<>>
struct is_enum_set : std::false_type
{
};
template <typename Enum>
struct is_enum_set<Enum, cm::void_t<typename cm_enum_set_traits<Enum>::type>>
: std::true_type
{
};
}
#if defined(__SUNPRO_CC) && defined(__sparc)
// Oracle DeveloperStudio C++ compiler on Solaris/Sparc crash on the following
// template declarations, so declare explicitly the operators.
// Helper macro to define the enum_set_traits struct specialization.
# define CM_ENUM_SET_TRAITS(E) \
template <> \
struct cm_enum_set_traits<E::value_type> \
{ \
using type = E; \
using value_type = E::value_type; \
}; \
\
inline E operator+(E::value_type lhs, E::value_type rhs) \
{ \
return { lhs, rhs }; \
} \
\
inline E operator|(E::value_type lhs, E::value_type rhs) \
{ \
return { lhs, rhs }; \
}
#else
// Helper macro to define the enum_set_traits struct specialization.
# define CM_ENUM_SET_TRAITS(E) \
template <> \
struct cm_enum_set_traits<E::value_type> \
{ \
using type = E; \
using value_type = E::value_type; \
};
template <typename Enum,
typename cm::enable_if_t<cm::is_enum_set<Enum>::value, int> = 0>
inline typename cm_enum_set_traits<Enum>::type operator+(Enum lhs, Enum rhs)
{
return { lhs, rhs };
}
// Alternate syntax
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)
typename cm::enable_if_t<cm::is_enum_set<Enum>::value, int> = 0>
inline typename cm_enum_set_traits<Enum>::type operator|(Enum lhs, Enum rhs)
{
return cm::enum_set<Enum>{ lhs, rhs };
return { lhs, rhs };
}
#endif