Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /* A set abstraction for enumeration values. */
8 :
9 : #ifndef mozilla_EnumSet_h
10 : #define mozilla_EnumSet_h
11 :
12 : #include "mozilla/Assertions.h"
13 : #include "mozilla/Attributes.h"
14 :
15 : #include <initializer_list>
16 :
17 : #include <stdint.h>
18 :
19 : namespace mozilla {
20 :
21 : /**
22 : * EnumSet<T> is a set of values defined by an enumeration. It is implemented
23 : * using a 32 bit mask for each value so it will only work for enums with an int
24 : * representation less than 32. It works both for enum and enum class types.
25 : */
26 : template<typename T>
27 : class EnumSet
28 : {
29 : public:
30 843 : EnumSet()
31 843 : : mBitField(0)
32 : {
33 843 : initVersion();
34 843 : }
35 :
36 0 : MOZ_IMPLICIT EnumSet(T aEnum)
37 0 : : mBitField(bitFor(aEnum))
38 0 : { }
39 :
40 0 : EnumSet(T aEnum1, T aEnum2)
41 0 : : mBitField(bitFor(aEnum1) |
42 0 : bitFor(aEnum2))
43 : {
44 0 : initVersion();
45 0 : }
46 :
47 : EnumSet(T aEnum1, T aEnum2, T aEnum3)
48 : : mBitField(bitFor(aEnum1) |
49 : bitFor(aEnum2) |
50 : bitFor(aEnum3))
51 : {
52 : initVersion();
53 : }
54 :
55 : EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
56 : : mBitField(bitFor(aEnum1) |
57 : bitFor(aEnum2) |
58 : bitFor(aEnum3) |
59 : bitFor(aEnum4))
60 : {
61 : initVersion();
62 : }
63 :
64 36 : MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
65 36 : : mBitField(0)
66 : {
67 204 : for (auto value : list) {
68 168 : (*this) += value;
69 : }
70 36 : initVersion();
71 36 : }
72 :
73 0 : EnumSet(const EnumSet& aEnumSet)
74 0 : : mBitField(aEnumSet.mBitField)
75 : {
76 0 : initVersion();
77 0 : }
78 :
79 : /**
80 : * Add an element
81 : */
82 470 : void operator+=(T aEnum)
83 : {
84 470 : incVersion();
85 470 : mBitField |= bitFor(aEnum);
86 470 : }
87 :
88 : /**
89 : * Add an element
90 : */
91 : EnumSet<T> operator+(T aEnum) const
92 : {
93 : EnumSet<T> result(*this);
94 : result += aEnum;
95 : return result;
96 : }
97 :
98 : /**
99 : * Union
100 : */
101 0 : void operator+=(const EnumSet<T> aEnumSet)
102 : {
103 0 : incVersion();
104 0 : mBitField |= aEnumSet.mBitField;
105 0 : }
106 :
107 : /**
108 : * Union
109 : */
110 : EnumSet<T> operator+(const EnumSet<T> aEnumSet) const
111 : {
112 : EnumSet<T> result(*this);
113 : result += aEnumSet;
114 : return result;
115 : }
116 :
117 : /**
118 : * Remove an element
119 : */
120 : void operator-=(T aEnum)
121 : {
122 : incVersion();
123 : mBitField &= ~(bitFor(aEnum));
124 : }
125 :
126 : /**
127 : * Remove an element
128 : */
129 : EnumSet<T> operator-(T aEnum) const
130 : {
131 : EnumSet<T> result(*this);
132 : result -= aEnum;
133 : return result;
134 : }
135 :
136 : /**
137 : * Remove a set of elements
138 : */
139 0 : void operator-=(const EnumSet<T> aEnumSet)
140 : {
141 0 : incVersion();
142 0 : mBitField &= ~(aEnumSet.mBitField);
143 0 : }
144 :
145 : /**
146 : * Remove a set of elements
147 : */
148 0 : EnumSet<T> operator-(const EnumSet<T> aEnumSet) const
149 : {
150 0 : EnumSet<T> result(*this);
151 0 : result -= aEnumSet;
152 0 : return result;
153 : }
154 :
155 : /**
156 : * Clear
157 : */
158 0 : void clear()
159 : {
160 0 : incVersion();
161 0 : mBitField = 0;
162 0 : }
163 :
164 : /**
165 : * Intersection
166 : */
167 : void operator&=(const EnumSet<T> aEnumSet)
168 : {
169 : incVersion();
170 : mBitField &= aEnumSet.mBitField;
171 : }
172 :
173 : /**
174 : * Intersection
175 : */
176 : EnumSet<T> operator&(const EnumSet<T> aEnumSet) const
177 : {
178 : EnumSet<T> result(*this);
179 : result &= aEnumSet;
180 : return result;
181 : }
182 :
183 : /**
184 : * Equality
185 : */
186 0 : bool operator==(const EnumSet<T> aEnumSet) const
187 : {
188 0 : return mBitField == aEnumSet.mBitField;
189 : }
190 :
191 : /**
192 : * Test is an element is contained in the set.
193 : */
194 528 : bool contains(T aEnum) const
195 : {
196 528 : return mBitField & bitFor(aEnum);
197 : }
198 :
199 : /**
200 : * Return the number of elements in the set.
201 : */
202 : uint8_t size() const
203 : {
204 : uint8_t count = 0;
205 : for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
206 : if (bitField & 1) {
207 : count++;
208 : }
209 : }
210 : return count;
211 : }
212 :
213 42 : bool isEmpty() const
214 : {
215 42 : return mBitField == 0;
216 : }
217 :
218 0 : uint32_t serialize() const
219 : {
220 0 : return mBitField;
221 : }
222 :
223 204 : void deserialize(uint32_t aValue)
224 : {
225 204 : incVersion();
226 204 : mBitField = aValue;
227 204 : }
228 :
229 : class ConstIterator
230 : {
231 : const EnumSet<T>* mSet;
232 : uint32_t mPos;
233 : #ifdef DEBUG
234 : uint64_t mVersion;
235 : #endif
236 :
237 108 : void checkVersion() {
238 : // Check that the set has not been modified while being iterated.
239 108 : MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
240 108 : }
241 :
242 : public:
243 18 : ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
244 18 : : mSet(&aSet), mPos(aPos)
245 : {
246 : #ifdef DEBUG
247 18 : mVersion = mSet->mVersion;
248 : #endif
249 18 : MOZ_ASSERT(aPos <= kMaxBits);
250 18 : if (aPos != kMaxBits && !mSet->contains(T(mPos)))
251 9 : ++*this;
252 18 : }
253 :
254 : ConstIterator(const ConstIterator& aOther)
255 : : mSet(aOther.mSet), mPos(aOther.mPos)
256 : {
257 : #ifdef DEBUG
258 : mVersion = aOther.mVersion;
259 : checkVersion();
260 : #endif
261 : }
262 :
263 : ConstIterator(ConstIterator&& aOther)
264 : : mSet(aOther.mSet), mPos(aOther.mPos)
265 : {
266 : #ifdef DEBUG
267 : mVersion = aOther.mVersion;
268 : checkVersion();
269 : #endif
270 : aOther.mSet = nullptr;
271 : }
272 :
273 18 : ~ConstIterator() {
274 18 : checkVersion();
275 18 : }
276 :
277 33 : bool operator==(const ConstIterator& other) {
278 33 : MOZ_ASSERT(mSet == other.mSet);
279 33 : checkVersion();
280 33 : return mPos == other.mPos;
281 : }
282 :
283 33 : bool operator!=(const ConstIterator& other) {
284 33 : return !(*this == other);
285 : }
286 :
287 24 : T operator*() {
288 24 : MOZ_ASSERT(mSet);
289 24 : MOZ_ASSERT(mPos < kMaxBits);
290 24 : MOZ_ASSERT(mSet->contains(T(mPos)));
291 24 : checkVersion();
292 24 : return T(mPos);
293 : }
294 :
295 33 : ConstIterator& operator++() {
296 33 : MOZ_ASSERT(mSet);
297 33 : MOZ_ASSERT(mPos < kMaxBits);
298 33 : checkVersion();
299 288 : do {
300 288 : mPos++;
301 288 : } while (mPos < kMaxBits && !mSet->contains(T(mPos)));
302 33 : return *this;
303 : }
304 : };
305 :
306 9 : ConstIterator begin() const {
307 9 : return ConstIterator(*this, 0);
308 : }
309 :
310 9 : ConstIterator end() const {
311 9 : return ConstIterator(*this, kMaxBits);
312 : }
313 :
314 : private:
315 998 : static uint32_t bitFor(T aEnum)
316 : {
317 998 : uint32_t bitNumber = (uint32_t)aEnum;
318 998 : MOZ_ASSERT(bitNumber < kMaxBits);
319 998 : return 1U << bitNumber;
320 : }
321 :
322 879 : void initVersion() {
323 : #ifdef DEBUG
324 879 : mVersion = 0;
325 : #endif
326 879 : }
327 :
328 674 : void incVersion() {
329 : #ifdef DEBUG
330 674 : mVersion++;
331 : #endif
332 674 : }
333 :
334 : static const size_t kMaxBits = 32;
335 : uint32_t mBitField;
336 :
337 : #ifdef DEBUG
338 : uint64_t mVersion;
339 : #endif
340 : };
341 :
342 : } // namespace mozilla
343 :
344 : #endif /* mozilla_EnumSet_h_*/
|