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"
15 #include <initializer_list>
16 #include <type_traits>
23 * EnumSet<T, U> is a set of values defined by an enumeration. It is implemented
24 * using a bit mask with the size of U for each value. It works both for enum
25 * and enum class types.
27 template <typename T
, typename Serialized
= typename
std::make_unsigned
<
28 typename
std::underlying_type
<T
>::type
>::type
>
33 constexpr EnumSet() : mBitField(0) {}
35 constexpr MOZ_IMPLICIT
EnumSet(T aEnum
) : mBitField(bitFor(aEnum
)) {}
37 constexpr EnumSet(T aEnum1
, T aEnum2
)
38 : mBitField(bitFor(aEnum1
) | bitFor(aEnum2
)) {}
40 constexpr EnumSet(T aEnum1
, T aEnum2
, T aEnum3
)
41 : mBitField(bitFor(aEnum1
) | bitFor(aEnum2
) | bitFor(aEnum3
)) {}
43 constexpr EnumSet(T aEnum1
, T aEnum2
, T aEnum3
, T aEnum4
)
44 : mBitField(bitFor(aEnum1
) | bitFor(aEnum2
) | bitFor(aEnum3
) |
47 constexpr MOZ_IMPLICIT
EnumSet(std::initializer_list
<T
> list
) : mBitField(0) {
48 for (auto value
: list
) {
54 constexpr EnumSet(const EnumSet
& aEnumSet
) : mBitField(aEnumSet
.mBitField
) {}
56 constexpr EnumSet
& operator=(const EnumSet
& aEnumSet
) {
57 mBitField
= aEnumSet
.mBitField
;
66 constexpr void operator+=(T aEnum
) {
68 mBitField
|= bitFor(aEnum
);
74 constexpr EnumSet
operator+(T aEnum
) const {
75 EnumSet
result(*this);
83 void operator+=(const EnumSet
& aEnumSet
) {
85 mBitField
|= aEnumSet
.mBitField
;
91 EnumSet
operator+(const EnumSet
& aEnumSet
) const {
92 EnumSet
result(*this);
100 void operator-=(T aEnum
) {
102 mBitField
&= ~(bitFor(aEnum
));
108 EnumSet
operator-(T aEnum
) const {
109 EnumSet
result(*this);
115 * Remove a set of elements
117 void operator-=(const EnumSet
& aEnumSet
) {
119 mBitField
&= ~(aEnumSet
.mBitField
);
123 * Remove a set of elements
125 EnumSet
operator-(const EnumSet
& aEnumSet
) const {
126 EnumSet
result(*this);
142 void operator&=(const EnumSet
& aEnumSet
) {
144 mBitField
&= aEnumSet
.mBitField
;
150 EnumSet
operator&(const EnumSet
& aEnumSet
) const {
151 EnumSet
result(*this);
159 bool operator==(const EnumSet
& aEnumSet
) const {
160 return mBitField
== aEnumSet
.mBitField
;
166 bool operator==(T aEnum
) const { return mBitField
== bitFor(aEnum
); }
171 bool operator!=(const EnumSet
& aEnumSet
) const {
172 return !operator==(aEnumSet
);
178 bool operator!=(T aEnum
) const { return !operator==(aEnum
); }
181 * Test is an element is contained in the set.
183 bool contains(T aEnum
) const { return mBitField
& bitFor(aEnum
); }
186 * Test if a set is contained in the set.
188 bool contains(const EnumSet
& aEnumSet
) const {
189 return (mBitField
& aEnumSet
.mBitField
) == aEnumSet
.mBitField
;
193 * Return the number of elements in the set.
195 uint8_t size() const {
197 for (Serialized bitField
= mBitField
; bitField
; bitField
>>= 1) {
205 bool isEmpty() const { return mBitField
== 0; }
207 Serialized
serialize() const { return mBitField
; }
209 void deserialize(Serialized aValue
) {
214 class ConstIterator
{
221 void checkVersion() const {
222 // Check that the set has not been modified while being iterated.
223 MOZ_ASSERT_IF(mSet
, mSet
->mVersion
== mVersion
);
227 ConstIterator(const EnumSet
& aSet
, uint32_t aPos
)
228 : mSet(&aSet
), mPos(aPos
) {
230 mVersion
= mSet
->mVersion
;
232 MOZ_ASSERT(aPos
<= kMaxBits
);
233 if (aPos
!= kMaxBits
&& !mSet
->contains(T(mPos
))) ++*this;
236 ConstIterator(const ConstIterator
& aOther
)
237 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
239 mVersion
= aOther
.mVersion
;
244 ConstIterator(ConstIterator
&& aOther
)
245 : mSet(aOther
.mSet
), mPos(aOther
.mPos
) {
247 mVersion
= aOther
.mVersion
;
250 aOther
.mSet
= nullptr;
253 ~ConstIterator() { checkVersion(); }
255 bool operator==(const ConstIterator
& other
) const {
256 MOZ_ASSERT(mSet
== other
.mSet
);
258 return mPos
== other
.mPos
;
261 bool operator!=(const ConstIterator
& other
) const {
262 return !(*this == other
);
265 T
operator*() const {
267 MOZ_ASSERT(mPos
< kMaxBits
);
268 MOZ_ASSERT(mSet
->contains(T(mPos
)));
273 ConstIterator
& operator++() {
275 MOZ_ASSERT(mPos
< kMaxBits
);
279 } while (mPos
< kMaxBits
&& !mSet
->contains(T(mPos
)));
284 ConstIterator
begin() const { return ConstIterator(*this, 0); }
286 ConstIterator
end() const { return ConstIterator(*this, kMaxBits
); }
289 constexpr static Serialized
bitFor(T aEnum
) {
290 auto bitNumber
= static_cast<Serialized
>(aEnum
);
291 MOZ_DIAGNOSTIC_ASSERT(bitNumber
< kMaxBits
);
292 return static_cast<Serialized
>(Serialized
{1} << bitNumber
);
295 constexpr void incVersion() {
301 static const size_t kMaxBits
= sizeof(Serialized
) * 8;
303 Serialized mBitField
;
306 uint64_t mVersion
= 0;
310 } // namespace mozilla
312 #endif /* mozilla_EnumSet_h_*/