utils: Add more methods to EnumSet

Add assignment operators and methods for adding, removing and operators for performing set arithmatic.

Change-Id: I13d30734354f503180f75480866b54034f647c2a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/71320
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2021-12-01 16:17:00 +00:00 committed by Tint LUCI CQ
parent 77e2c6f0b2
commit 62394b2492
2 changed files with 162 additions and 12 deletions

View File

@ -19,6 +19,7 @@
#include <functional> #include <functional>
#include <ostream> #include <ostream>
#include <type_traits> #include <type_traits>
#include <utility>
namespace tint { namespace tint {
namespace utils { namespace utils {
@ -40,25 +41,88 @@ struct EnumSet {
template <typename... VALUES> template <typename... VALUES>
explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {} explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {}
/// Adds e to this set /// Copy assignment operator.
/// @param set the set to assign to this set
/// @return this set so calls can be chained
inline EnumSet& operator=(const EnumSet& set) = default;
/// Copy assignment operator.
/// @param e the enum value /// @param e the enum value
/// @return this set so calls can be chained /// @return this set so calls can be chained
inline EnumSet& Add(Enum e) { inline EnumSet& operator=(Enum e) { return *this = EnumSet{e}; }
set |= Bit(e);
return *this; /// Adds all the given values to this set
/// @param values the values to add
/// @return this set so calls can be chained
template <typename... VALUES>
inline EnumSet& Add(VALUES... values) {
return Add(EnumSet(std::forward<VALUES>(values)...));
} }
/// Removes e from this set /// Removes all the given values from this set
/// @param e the enum value /// @param values the values to remove
/// @return this set so calls can be chained /// @return this set so calls can be chained
inline EnumSet& Remove(Enum e) { template <typename... VALUES>
set &= ~Bit(e); inline EnumSet& Remove(VALUES... values) {
return *this; return Remove(EnumSet(std::forward<VALUES>(values)...));
}
/// Adds all of s to this set
/// @param s the enum value
/// @return this set so calls can be chained
inline EnumSet& Add(EnumSet s) { return (*this = *this + s); }
/// Removes all of s from this set
/// @param s the enum value
/// @return this set so calls can be chained
inline EnumSet& Remove(EnumSet s) { return (*this = *this - s); }
/// @param e the enum value
/// @returns a copy of this set with e added
inline EnumSet operator+(Enum e) const {
EnumSet out;
out.set = set | Bit(e);
return out;
}
/// @param e the enum value
/// @returns a copy of this set with e removed
inline EnumSet operator-(Enum e) const {
EnumSet out;
out.set = set & ~Bit(e);
return out;
}
/// @param s the other set
/// @returns the union of this set with s (this rhs)
inline EnumSet operator+(EnumSet s) const {
EnumSet out;
out.set = set | s.set;
return out;
}
/// @param s the other set
/// @returns the set of entries found in this but not in s (this \ s)
inline EnumSet operator-(EnumSet s) const {
EnumSet out;
out.set = set & ~s.set;
return out;
}
/// @param s the other set
/// @returns the intersection of this set with s (this ∩ rhs)
inline EnumSet operator&(EnumSet s) const {
EnumSet out;
out.set = set & s.set;
return out;
} }
/// @param e the enum value /// @param e the enum value
/// @return true if the set contains `e` /// @return true if the set contains `e`
inline bool Contains(Enum e) { return (set & Bit(e)) != 0; } inline bool Contains(Enum e) const { return (set & Bit(e)) != 0; }
/// @return true if the set is empty
inline bool Empty() const { return set == 0; }
/// Equality operator /// Equality operator
/// @param rhs the other EnumSet to compare this to /// @param rhs the other EnumSet to compare this to

View File

@ -44,6 +44,7 @@ TEST(EnumSetTest, ConstructEmpty) {
EXPECT_FALSE(set.Contains(E::A)); EXPECT_FALSE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B)); EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C)); EXPECT_FALSE(set.Contains(E::C));
EXPECT_TRUE(set.Empty());
} }
TEST(EnumSetTest, ConstructWithSingle) { TEST(EnumSetTest, ConstructWithSingle) {
@ -51,6 +52,7 @@ TEST(EnumSetTest, ConstructWithSingle) {
EXPECT_FALSE(set.Contains(E::A)); EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B)); EXPECT_TRUE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C)); EXPECT_FALSE(set.Contains(E::C));
EXPECT_FALSE(set.Empty());
} }
TEST(EnumSetTest, ConstructWithMultiple) { TEST(EnumSetTest, ConstructWithMultiple) {
@ -58,9 +60,26 @@ TEST(EnumSetTest, ConstructWithMultiple) {
EXPECT_TRUE(set.Contains(E::A)); EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B)); EXPECT_FALSE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C)); EXPECT_TRUE(set.Contains(E::C));
EXPECT_FALSE(set.Empty());
} }
TEST(EnumSetTest, Add) { TEST(EnumSetTest, AssignSet) {
EnumSet<E> set;
set = EnumSet<E>(E::A, E::C);
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C));
}
TEST(EnumSetTest, AssignEnum) {
EnumSet<E> set(E::A);
set = E::B;
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, AddEnum) {
EnumSet<E> set; EnumSet<E> set;
set.Add(E::B); set.Add(E::B);
EXPECT_FALSE(set.Contains(E::A)); EXPECT_FALSE(set.Contains(E::A));
@ -68,7 +87,7 @@ TEST(EnumSetTest, Add) {
EXPECT_FALSE(set.Contains(E::C)); EXPECT_FALSE(set.Contains(E::C));
} }
TEST(EnumSetTest, Remove) { TEST(EnumSetTest, RemoveEnum) {
EnumSet<E> set(E::A, E::B); EnumSet<E> set(E::A, E::B);
set.Remove(E::B); set.Remove(E::B);
EXPECT_TRUE(set.Contains(E::A)); EXPECT_TRUE(set.Contains(E::A));
@ -76,6 +95,73 @@ TEST(EnumSetTest, Remove) {
EXPECT_FALSE(set.Contains(E::C)); EXPECT_FALSE(set.Contains(E::C));
} }
TEST(EnumSetTest, AddEnums) {
EnumSet<E> set;
set.Add(E::B, E::C);
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C));
}
TEST(EnumSetTest, RemoveEnums) {
EnumSet<E> set(E::A, E::B);
set.Remove(E::C, E::B);
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, AddEnumSet) {
EnumSet<E> set;
set.Add(EnumSet<E>{E::B, E::C});
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C));
}
TEST(EnumSetTest, RemoveEnumSet) {
EnumSet<E> set(E::A, E::B);
set.Remove(EnumSet<E>{E::B, E::C});
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, OperatorPlusEnum) {
EnumSet<E> set = EnumSet<E>{E::B} + E::C;
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C));
}
TEST(EnumSetTest, OperatorMinusEnum) {
EnumSet<E> set = EnumSet<E>{E::A, E::B} - E::B;
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, OperatorPlusSet) {
EnumSet<E> set = EnumSet<E>{E::B} + EnumSet<E>{E::B, E::C};
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_TRUE(set.Contains(E::C));
}
TEST(EnumSetTest, OperatorMinusSet) {
EnumSet<E> set = EnumSet<E>{E::A, E::B} - EnumSet<E>{E::B, E::C};
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, OperatorAnd) {
EnumSet<E> set = EnumSet<E>{E::A, E::B} & EnumSet<E>{E::B, E::C};
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
}
TEST(EnumSetTest, EqualitySet) { TEST(EnumSetTest, EqualitySet) {
EXPECT_TRUE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::B)); EXPECT_TRUE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::B));
EXPECT_FALSE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::C)); EXPECT_FALSE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::C));