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/. */
7 /* A set abstraction for enumeration values. */
9 #ifndef mozilla_EnumSet_h
10 #define mozilla_EnumSet_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/MathAlgorithms.h"
16 #include <initializer_list>
17 #include <type_traits>
24 * EnumSet<T, U> is a set of values defined by an enumeration. It is implemented
25 * using a bit mask with the size of U for each value. It works both for enum
26 * and enum class types. EnumSet also works with U being a BitSet.
28 template <typename T
, typename Serialized
= typename
std::make_unsigned
<
29 typename
std::underlying_type
<T
>::type
>::type
>
33 using serializedType
= Serialized
;
35 constexpr EnumSet() : mBitField() {}
37 constexpr MOZ_IMPLICIT
EnumSet(T aEnum
) : mBitField(BitFor(aEnum
)) {}
39 constexpr EnumSet(T aEnum1
, T aEnum2
)
40 : mBitField(BitFor(aEnum1
) | BitFor(aEnum2
)) {}
42 constexpr EnumSet(T aEnum1
, T aEnum2
, T aEnum3
)
43 : mBitField(BitFor(aEnum1
) | BitFor(aEnum2
) | BitFor(aEnum3
)) {}
45 constexpr EnumSet(T aEnum1
, T aEnum2
, T aEnum3
, T aEnum4
)
46 : mBitField(BitFor(aEnum1
) | BitFor(aEnum2
) | BitFor(aEnum3
) |
49 constexpr MOZ_IMPLICIT
EnumSet(std::initializer_list
<T
> list
) : mBitField() {
50 for (auto value
: list
) {
56 constexpr EnumSet(const EnumSet
& aEnumSet
) : mBitField(aEnumSet
.mBitField
) {}
58 constexpr EnumSet
& operator=(const EnumSet
& aEnumSet
) {
59 mBitField
= aEnumSet
.mBitField
;
68 constexpr void operator+=(T aEnum
) {
70 mBitField
|= BitFor(aEnum
);
76 constexpr EnumSet
operator+(T aEnum
) const {
77 EnumSet
result(*this);
85 void operator+=(const EnumSet
& aEnumSet
) {
87 mBitField
|= aEnumSet
.mBitField
;
93 EnumSet
operator+(const EnumSet
& aEnumSet
) const {
94 EnumSet
result(*this);
102 void operator-=(T aEnum
) {
104 mBitField
&= ~(BitFor(aEnum
));
110 EnumSet
operator-(T aEnum
) const {
111 EnumSet
result(*this);
117 * Remove a set of elements
119 void operator-=(const EnumSet
& aEnumSet
) {
121 mBitField
&= ~(aEnumSet
.mBitField
);
125 * Remove a set of elements
127 EnumSet
operator-(const EnumSet
& aEnumSet
) const {
128 EnumSet
result(*this);
138 mBitField
= Serialized();
144 void operator&=(const EnumSet
& aEnumSet
) {
146 mBitField
&= aEnumSet
.mBitField
;
152 EnumSet
operator&(const EnumSet
& aEnumSet
) const {
153 EnumSet
result(*this);
161 bool operator==(const EnumSet
& aEnumSet
) const {
162 return mBitField
== aEnumSet
.mBitField
;
168 bool operator==(T aEnum
) const { return mBitField
== BitFor(aEnum
); }
173 bool operator!=(const EnumSet
& aEnumSet
) const {
174 return !operator==(aEnumSet
);
180 bool operator!=(T aEnum
) const { return !operator==(aEnum
); }
183 * Test is an element is contained in the set.
185 bool contains(T aEnum
) const { return HasBitFor(aEnum
); }
188 * Test if a set is contained in the set.
190 bool contains(const EnumSet
& aEnumSet
) const {
191 return (mBitField
& aEnumSet
.mBitField
) == aEnumSet
.mBitField
;
195 * Return the number of elements in the set.
197 size_t size() const {
198 if constexpr (std::is_unsigned_v
<Serialized
>) {
199 if constexpr (kMaxBits
> 32) {
200 return CountPopulation64(mBitField
);
202 return CountPopulation32(mBitField
);
205 return mBitField
.Count();
209 bool isEmpty() const {
210 if constexpr (std::is_unsigned_v
<Serialized
>) {
211 return mBitField
== 0;
213 return mBitField
.IsEmpty();
217 Serialized
serialize() const { return mBitField
; }
219 void deserialize(Serialized aValue
) {
224 class ConstIterator
{
231 void checkVersion() const {
232 // Check that the set has not been modified while being iterated.
233 MOZ_ASSERT_IF(mSet
, mSet
->mVersion
== mVersion
);
237 ConstIterator(const EnumSet
& aSet
, size_t aPos
) : mSet(&aSet
), mPos(aPos
) {
239 mVersion
= mSet
->mVersion
;
241 MOZ_ASSERT(aPos
<= kMaxBits
);
242 if (aPos
!= kMaxBits
&& !mSet
->HasBitAt(mPos
)) {
247 ConstIterator(const ConstIterator
& aOther
)
248 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
250 mVersion
= aOther
.mVersion
;
255 ConstIterator(ConstIterator
&& aOther
)
256 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
258 mVersion
= aOther
.mVersion
;
261 aOther
.mSet
= nullptr;
264 ~ConstIterator() { checkVersion(); }
266 bool operator==(const ConstIterator
& other
) const {
267 MOZ_ASSERT(mSet
== other
.mSet
);
269 return mPos
== other
.mPos
;
272 bool operator!=(const ConstIterator
& other
) const {
273 return !(*this == other
);
276 T
operator*() const {
278 MOZ_ASSERT(mPos
< kMaxBits
);
279 MOZ_ASSERT(mSet
->HasBitAt(mPos
));
284 ConstIterator
& operator++() {
286 MOZ_ASSERT(mPos
< kMaxBits
);
290 } while (mPos
< kMaxBits
&& !mSet
->HasBitAt(mPos
));
295 ConstIterator
begin() const { return ConstIterator(*this, 0); }
297 ConstIterator
end() const { return ConstIterator(*this, kMaxBits
); }
300 constexpr static Serialized
BitFor(T aEnum
) {
301 const auto pos
= static_cast<size_t>(aEnum
);
305 constexpr static Serialized
BitAt(size_t aPos
) {
306 MOZ_DIAGNOSTIC_ASSERT(aPos
< kMaxBits
);
307 if constexpr (std::is_unsigned_v
<Serialized
>) {
308 return static_cast<Serialized
>(Serialized
{1} << aPos
);
311 bitField
[aPos
] = true;
316 constexpr bool HasBitFor(T aEnum
) const {
317 const auto pos
= static_cast<size_t>(aEnum
);
318 return HasBitAt(pos
);
321 constexpr bool HasBitAt(size_t aPos
) const {
322 return static_cast<bool>(mBitField
& BitAt(aPos
));
325 constexpr void IncVersion() {
331 static constexpr size_t MaxBits() {
332 if constexpr (std::is_unsigned_v
<Serialized
>) {
333 return sizeof(Serialized
) * 8;
335 return Serialized::Size();
339 static constexpr size_t kMaxBits
= MaxBits();
341 Serialized mBitField
;
344 uint64_t mVersion
= 0;
348 } // namespace mozilla
350 #endif /* mozilla_EnumSet_h_*/