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>
diff --git a/src/utils/enum_set.h b/src/utils/enum_set.h
index 3a71f78..87da779 100644
--- a/src/utils/enum_set.h
+++ b/src/utils/enum_set.h
@@ -19,6 +19,7 @@
#include <functional>
#include <ostream>
#include <type_traits>
+#include <utility>
namespace tint {
namespace utils {
@@ -40,25 +41,88 @@
template <typename... 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
/// @return this set so calls can be chained
- inline EnumSet& Add(Enum e) {
- set |= Bit(e);
- return *this;
+ inline EnumSet& operator=(Enum e) { return *this = EnumSet{e}; }
+
+ /// 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
- /// @param e the enum value
+ /// Removes all the given values from this set
+ /// @param values the values to remove
/// @return this set so calls can be chained
- inline EnumSet& Remove(Enum e) {
- set &= ~Bit(e);
- return *this;
+ template <typename... VALUES>
+ inline EnumSet& Remove(VALUES... values) {
+ 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
/// @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
/// @param rhs the other EnumSet to compare this to
diff --git a/src/utils/enum_set_test.cc b/src/utils/enum_set_test.cc
index 9a5186d..b7f5b72 100644
--- a/src/utils/enum_set_test.cc
+++ b/src/utils/enum_set_test.cc
@@ -44,6 +44,7 @@
EXPECT_FALSE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
+ EXPECT_TRUE(set.Empty());
}
TEST(EnumSetTest, ConstructWithSingle) {
@@ -51,6 +52,7 @@
EXPECT_FALSE(set.Contains(E::A));
EXPECT_TRUE(set.Contains(E::B));
EXPECT_FALSE(set.Contains(E::C));
+ EXPECT_FALSE(set.Empty());
}
TEST(EnumSetTest, ConstructWithMultiple) {
@@ -58,9 +60,26 @@
EXPECT_TRUE(set.Contains(E::A));
EXPECT_FALSE(set.Contains(E::B));
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;
set.Add(E::B);
EXPECT_FALSE(set.Contains(E::A));
@@ -68,7 +87,7 @@
EXPECT_FALSE(set.Contains(E::C));
}
-TEST(EnumSetTest, Remove) {
+TEST(EnumSetTest, RemoveEnum) {
EnumSet<E> set(E::A, E::B);
set.Remove(E::B);
EXPECT_TRUE(set.Contains(E::A));
@@ -76,6 +95,73 @@
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) {
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));