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 {
186 return static_cast<bool>(mBitField
& bitFor(aEnum
));
190 * Test if a set is contained in the set.
192 bool contains(const EnumSet
& aEnumSet
) const {
193 return (mBitField
& aEnumSet
.mBitField
) == aEnumSet
.mBitField
;
197 * Return the number of elements in the set.
199 size_t size() const {
200 if constexpr (std::is_unsigned_v
<Serialized
>) {
201 if constexpr (kMaxBits
> 32) {
202 return CountPopulation64(mBitField
);
204 return CountPopulation32(mBitField
);
207 return mBitField
.Count();
211 bool isEmpty() const {
212 if constexpr (std::is_unsigned_v
<Serialized
>) {
213 return mBitField
== 0;
215 return mBitField
.IsEmpty();
219 Serialized
serialize() const { return mBitField
; }
221 void deserialize(Serialized aValue
) {
226 class ConstIterator
{
233 void checkVersion() const {
234 // Check that the set has not been modified while being iterated.
235 MOZ_ASSERT_IF(mSet
, mSet
->mVersion
== mVersion
);
239 ConstIterator(const EnumSet
& aSet
, uint32_t aPos
)
240 : mSet(&aSet
), mPos(aPos
) {
242 mVersion
= mSet
->mVersion
;
244 MOZ_ASSERT(aPos
<= kMaxBits
);
245 if (aPos
!= kMaxBits
&& !mSet
->contains(T(mPos
))) {
250 ConstIterator(const ConstIterator
& aOther
)
251 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
253 mVersion
= aOther
.mVersion
;
258 ConstIterator(ConstIterator
&& aOther
)
259 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
261 mVersion
= aOther
.mVersion
;
264 aOther
.mSet
= nullptr;
267 ~ConstIterator() { checkVersion(); }
269 bool operator==(const ConstIterator
& other
) const {
270 MOZ_ASSERT(mSet
== other
.mSet
);
272 return mPos
== other
.mPos
;
275 bool operator!=(const ConstIterator
& other
) const {
276 return !(*this == other
);
279 T
operator*() const {
281 MOZ_ASSERT(mPos
< kMaxBits
);
282 MOZ_ASSERT(mSet
->contains(T(mPos
)));
287 ConstIterator
& operator++() {
289 MOZ_ASSERT(mPos
< kMaxBits
);
293 } while (mPos
< kMaxBits
&& !mSet
->contains(T(mPos
)));
298 ConstIterator
begin() const { return ConstIterator(*this, 0); }
300 ConstIterator
end() const { return ConstIterator(*this, kMaxBits
); }
303 constexpr static Serialized
bitFor(T aEnum
) {
304 auto bitNumber
= static_cast<size_t>(aEnum
);
305 MOZ_DIAGNOSTIC_ASSERT(bitNumber
< kMaxBits
);
306 if constexpr (std::is_unsigned_v
<Serialized
>) {
307 return static_cast<Serialized
>(Serialized
{1} << bitNumber
);
310 bitField
[bitNumber
] = true;
315 constexpr void incVersion() {
321 static constexpr size_t MaxBits() {
322 if constexpr (std::is_unsigned_v
<Serialized
>) {
323 return sizeof(Serialized
) * 8;
325 return Serialized::Size();
329 static constexpr size_t kMaxBits
= MaxBits();
331 Serialized mBitField
;
334 uint64_t mVersion
= 0;
338 } // namespace mozilla
340 #endif /* mozilla_EnumSet_h_*/