• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SRC_UTILS_ENUM_SET_H_
16 #define SRC_UTILS_ENUM_SET_H_
17 
18 #include <cstdint>
19 #include <functional>
20 #include <ostream>
21 #include <type_traits>
22 #include <utility>
23 
24 namespace tint {
25 namespace utils {
26 
27 /// EnumSet is a set of enum values.
28 /// @note As the EnumSet is backed by a single uint64_t value, it can only hold
29 /// enum values in the range [0 .. 63].
30 template <typename ENUM>
31 struct EnumSet {
32  public:
33   /// Enum is the enum type this EnumSet wraps
34   using Enum = ENUM;
35 
36   /// Constructor. Initializes the EnumSet with zero.
37   constexpr EnumSet() = default;
38 
39   /// Copy constructor.
40   /// @param s the set to copy
41   constexpr EnumSet(const EnumSet& s) = default;
42 
43   /// Constructor. Initializes the EnumSet with the given values.
44   /// @param values the enumerator values to construct the set with
45   template <typename... VALUES>
EnumSetEnumSet46   explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {}
47 
48   /// Copy assignment operator.
49   /// @param set the set to assign to this set
50   /// @return this set so calls can be chained
51   inline EnumSet& operator=(const EnumSet& set) = default;
52 
53   /// Copy assignment operator.
54   /// @param e the enum value
55   /// @return this set so calls can be chained
56   inline EnumSet& operator=(Enum e) { return *this = EnumSet{e}; }
57 
58   /// Adds all the given values to this set
59   /// @param values the values to add
60   /// @return this set so calls can be chained
61   template <typename... VALUES>
AddEnumSet62   inline EnumSet& Add(VALUES... values) {
63     return Add(EnumSet(std::forward<VALUES>(values)...));
64   }
65 
66   /// Removes all the given values from this set
67   /// @param values the values to remove
68   /// @return this set so calls can be chained
69   template <typename... VALUES>
RemoveEnumSet70   inline EnumSet& Remove(VALUES... values) {
71     return Remove(EnumSet(std::forward<VALUES>(values)...));
72   }
73 
74   /// Adds all of s to this set
75   /// @param s the enum value
76   /// @return this set so calls can be chained
AddEnumSet77   inline EnumSet& Add(EnumSet s) { return (*this = *this + s); }
78 
79   /// Removes all of s from this set
80   /// @param s the enum value
81   /// @return this set so calls can be chained
RemoveEnumSet82   inline EnumSet& Remove(EnumSet s) { return (*this = *this - s); }
83 
84   /// @param e the enum value
85   /// @returns a copy of this set with e added
86   inline EnumSet operator+(Enum e) const {
87     EnumSet out;
88     out.set = set | Bit(e);
89     return out;
90   }
91 
92   /// @param e the enum value
93   /// @returns a copy of this set with e removed
94   inline EnumSet operator-(Enum e) const {
95     EnumSet out;
96     out.set = set & ~Bit(e);
97     return out;
98   }
99 
100   /// @param s the other set
101   /// @returns the union of this set with s (this ∪ rhs)
102   inline EnumSet operator+(EnumSet s) const {
103     EnumSet out;
104     out.set = set | s.set;
105     return out;
106   }
107 
108   /// @param s the other set
109   /// @returns the set of entries found in this but not in s (this \ s)
110   inline EnumSet operator-(EnumSet s) const {
111     EnumSet out;
112     out.set = set & ~s.set;
113     return out;
114   }
115 
116   /// @param s the other set
117   /// @returns the intersection of this set with s (this ∩ rhs)
118   inline EnumSet operator&(EnumSet s) const {
119     EnumSet out;
120     out.set = set & s.set;
121     return out;
122   }
123 
124   /// @param e the enum value
125   /// @return true if the set contains `e`
ContainsEnumSet126   inline bool Contains(Enum e) const { return (set & Bit(e)) != 0; }
127 
128   /// @return true if the set is empty
EmptyEnumSet129   inline bool Empty() const { return set == 0; }
130 
131   /// Equality operator
132   /// @param rhs the other EnumSet to compare this to
133   /// @return true if this EnumSet is equal to rhs
134   inline bool operator==(EnumSet rhs) const { return set == rhs.set; }
135 
136   /// Inequality operator
137   /// @param rhs the other EnumSet to compare this to
138   /// @return true if this EnumSet is not equal to rhs
139   inline bool operator!=(EnumSet rhs) const { return set != rhs.set; }
140 
141   /// Equality operator
142   /// @param rhs the enum to compare this to
143   /// @return true if this EnumSet only contains `rhs`
144   inline bool operator==(Enum rhs) const { return set == Bit(rhs); }
145 
146   /// Inequality operator
147   /// @param rhs the enum to compare this to
148   /// @return false if this EnumSet only contains `rhs`
149   inline bool operator!=(Enum rhs) const { return set != Bit(rhs); }
150 
151   /// @return the underlying value for the EnumSet
ValueEnumSet152   inline uint64_t Value() const { return set; }
153 
154   /// Iterator provides read-only, unidirectional iterator over the enums of an
155   /// EnumSet.
156   class Iterator {
157     static constexpr int8_t kEnd = 63;
158 
IteratorEnumSet159     Iterator(uint64_t s, int8_t b) : set(s), pos(b) {}
160 
161     /// Make the constructor accessible to the EnumSet.
162     friend struct EnumSet;
163 
164    public:
165     /// @return the Enum value at this point in the iterator
166     Enum operator*() const { return static_cast<Enum>(pos); }
167 
168     /// Increments the iterator
169     /// @returns this iterator
170     Iterator& operator++() {
171       while (pos < kEnd) {
172         pos++;
173         if (set & (static_cast<uint64_t>(1) << static_cast<uint64_t>(pos))) {
174           break;
175         }
176       }
177       return *this;
178     }
179 
180     /// Equality operator
181     /// @param rhs the Iterator to compare this to
182     /// @return true if the two iterators are equal
183     bool operator==(const Iterator& rhs) const {
184       return set == rhs.set && pos == rhs.pos;
185     }
186 
187     /// Inequality operator
188     /// @param rhs the Iterator to compare this to
189     /// @return true if the two iterators are different
190     bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
191 
192    private:
193     const uint64_t set;
194     int8_t pos;
195   };
196 
197   /// @returns an read-only iterator to the beginning of the set
beginEnumSet198   Iterator begin() {
199     auto it = Iterator{set, -1};
200     ++it;  // Move to first set bit
201     return it;
202   }
203 
204   /// @returns an iterator to the beginning of the set
endEnumSet205   Iterator end() { return Iterator{set, Iterator::kEnd}; }
206 
207  private:
BitEnumSet208   static constexpr uint64_t Bit(Enum value) {
209     return static_cast<uint64_t>(1) << static_cast<uint64_t>(value);
210   }
211 
UnionEnumSet212   static constexpr uint64_t Union() { return 0; }
213 
214   template <typename FIRST, typename... VALUES>
UnionEnumSet215   static constexpr uint64_t Union(FIRST first, VALUES... values) {
216     return Bit(first) | Union(values...);
217   }
218 
219   uint64_t set = 0;
220 };
221 
222 /// Writes the EnumSet to the std::ostream.
223 /// @param out the std::ostream to write to
224 /// @param set the EnumSet to write
225 /// @returns out so calls can be chained
226 template <typename ENUM>
227 inline std::ostream& operator<<(std::ostream& out, EnumSet<ENUM> set) {
228   out << "{";
229   bool first = true;
230   for (auto e : set) {
231     if (!first) {
232       out << ", ";
233     }
234     first = false;
235     out << e;
236   }
237   return out << "}";
238 }
239 
240 }  // namespace utils
241 }  // namespace tint
242 
243 namespace std {
244 
245 /// Custom std::hash specialization for tint::utils::EnumSet<T>
246 template <typename T>
247 class hash<tint::utils::EnumSet<T>> {
248  public:
249   /// @param e the EnumSet to create a hash for
250   /// @return the hash value
operator()251   inline std::size_t operator()(const tint::utils::EnumSet<T>& e) const {
252     return std::hash<uint64_t>()(e.Value());
253   }
254 };
255 
256 }  // namespace std
257 
258 #endif  // SRC_UTILS_ENUM_SET_H_
259