EnumSet.h (8081B)
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 #include "mozilla/MathAlgorithms.h" 15 16 #include <cstdint> 17 #include <initializer_list> 18 #include <type_traits> 19 20 namespace mozilla { 21 22 /** 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. EnumSet also works with U being a BitSet. 26 */ 27 template <typename T, 28 typename Serialized = std::make_unsigned_t<std::underlying_type_t<T>>> 29 class EnumSet { 30 public: 31 using valueType = T; 32 using serializedType = Serialized; 33 34 constexpr EnumSet() : mBitField() {} 35 36 constexpr MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(BitFor(aEnum)) {} 37 38 constexpr EnumSet(T aEnum1, T aEnum2) 39 : mBitField(BitFor(aEnum1) | BitFor(aEnum2)) {} 40 41 constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3) 42 : mBitField(BitFor(aEnum1) | BitFor(aEnum2) | BitFor(aEnum3)) {} 43 44 constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) 45 : mBitField(BitFor(aEnum1) | BitFor(aEnum2) | BitFor(aEnum3) | 46 BitFor(aEnum4)) {} 47 48 constexpr MOZ_IMPLICIT EnumSet(std::initializer_list<T> list) : mBitField() { 49 for (auto value : list) { 50 (*this) += value; 51 } 52 } 53 54 constexpr explicit EnumSet(Serialized aValue) : mBitField(aValue) {} 55 56 #ifdef DEBUG 57 constexpr EnumSet(const EnumSet& aEnumSet) : mBitField(aEnumSet.mBitField) {} 58 59 constexpr EnumSet& operator=(const EnumSet& aEnumSet) { 60 mBitField = aEnumSet.mBitField; 61 IncVersion(); 62 return *this; 63 } 64 #endif 65 66 /** 67 * Add an element 68 */ 69 constexpr void operator+=(T aEnum) { 70 IncVersion(); 71 mBitField |= BitFor(aEnum); 72 } 73 74 /** 75 * Add an element 76 */ 77 constexpr EnumSet operator+(T aEnum) const { 78 EnumSet result(*this); 79 result += aEnum; 80 return result; 81 } 82 83 /** 84 * Union 85 */ 86 constexpr void operator+=(const EnumSet& aEnumSet) { 87 IncVersion(); 88 mBitField |= aEnumSet.mBitField; 89 } 90 91 /** 92 * Union 93 */ 94 constexpr EnumSet operator+(const EnumSet& aEnumSet) const { 95 EnumSet result(*this); 96 result += aEnumSet; 97 return result; 98 } 99 100 /** 101 * Remove an element 102 */ 103 constexpr void operator-=(T aEnum) { 104 IncVersion(); 105 mBitField &= ~(BitFor(aEnum)); 106 } 107 108 /** 109 * Remove an element 110 */ 111 constexpr EnumSet operator-(T aEnum) const { 112 EnumSet result(*this); 113 result -= aEnum; 114 return result; 115 } 116 117 /** 118 * Remove a set of elements 119 */ 120 constexpr void operator-=(const EnumSet& aEnumSet) { 121 IncVersion(); 122 mBitField &= ~(aEnumSet.mBitField); 123 } 124 125 /** 126 * Remove a set of elements 127 */ 128 constexpr EnumSet operator-(const EnumSet& aEnumSet) const { 129 EnumSet result(*this); 130 result -= aEnumSet; 131 return result; 132 } 133 134 /** 135 * Clear 136 */ 137 constexpr void clear() { 138 IncVersion(); 139 mBitField = Serialized(); 140 } 141 142 /** 143 * Intersection 144 */ 145 constexpr void operator&=(const EnumSet& aEnumSet) { 146 IncVersion(); 147 mBitField &= aEnumSet.mBitField; 148 } 149 150 /** 151 * Intersection 152 */ 153 constexpr EnumSet operator&(const EnumSet& aEnumSet) const { 154 EnumSet result(*this); 155 result &= aEnumSet; 156 return result; 157 } 158 159 /** 160 * Equality 161 */ 162 constexpr bool operator==(const EnumSet& aEnumSet) const { 163 return mBitField == aEnumSet.mBitField; 164 } 165 166 /** 167 * Equality 168 */ 169 constexpr bool operator==(T aEnum) const { 170 return mBitField == BitFor(aEnum); 171 } 172 173 /** 174 * Not equal 175 */ 176 constexpr bool operator!=(const EnumSet& aEnumSet) const { 177 return !operator==(aEnumSet); 178 } 179 180 /** 181 * Not equal 182 */ 183 constexpr bool operator!=(T aEnum) const { return !operator==(aEnum); } 184 185 /** 186 * Test is an element is contained in the set. 187 */ 188 constexpr bool contains(T aEnum) const { return HasBitFor(aEnum); } 189 190 /** 191 * Test if a set is contained in the set. 192 */ 193 constexpr bool contains(const EnumSet& aEnumSet) const { 194 return (mBitField & aEnumSet.mBitField) == aEnumSet.mBitField; 195 } 196 197 /** 198 * Return the number of elements in the set. 199 */ 200 size_t size() const { 201 if constexpr (std::is_unsigned_v<Serialized>) { 202 if constexpr (kMaxBits > 32) { 203 return CountPopulation64(mBitField); 204 } else { 205 return CountPopulation32(mBitField); 206 } 207 } else { 208 return mBitField.Count(); 209 } 210 } 211 212 constexpr bool isEmpty() const { 213 if constexpr (std::is_unsigned_v<Serialized>) { 214 return mBitField == 0; 215 } else { 216 return mBitField.IsEmpty(); 217 } 218 } 219 220 Serialized serialize() const { return mBitField; } 221 222 void deserialize(Serialized aValue) { 223 IncVersion(); 224 mBitField = aValue; 225 } 226 227 class ConstIterator { 228 const EnumSet* mSet; 229 size_t mPos; 230 #ifdef DEBUG 231 uint64_t mVersion; 232 #endif 233 234 void checkVersion() const { 235 // Check that the set has not been modified while being iterated. 236 MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion); 237 } 238 239 public: 240 ConstIterator(const EnumSet& aSet, size_t aPos) : mSet(&aSet), mPos(aPos) { 241 #ifdef DEBUG 242 mVersion = mSet->mVersion; 243 #endif 244 MOZ_ASSERT(aPos <= kMaxBits); 245 if (aPos != kMaxBits && !mSet->HasBitAt(mPos)) { 246 ++*this; 247 } 248 } 249 250 ConstIterator(const ConstIterator& aOther) 251 : mSet(aOther.mSet), mPos(aOther.mPos) { 252 #ifdef DEBUG 253 mVersion = aOther.mVersion; 254 checkVersion(); 255 #endif 256 } 257 258 ConstIterator(ConstIterator&& aOther) 259 : mSet(aOther.mSet), mPos(aOther.mPos) { 260 #ifdef DEBUG 261 mVersion = aOther.mVersion; 262 checkVersion(); 263 #endif 264 aOther.mSet = nullptr; 265 } 266 267 ~ConstIterator() { checkVersion(); } 268 269 bool operator==(const ConstIterator& other) const { 270 MOZ_ASSERT(mSet == other.mSet); 271 checkVersion(); 272 return mPos == other.mPos; 273 } 274 275 bool operator!=(const ConstIterator& other) const { 276 return !(*this == other); 277 } 278 279 T operator*() const { 280 MOZ_ASSERT(mSet); 281 MOZ_ASSERT(mPos < kMaxBits); 282 MOZ_ASSERT(mSet->HasBitAt(mPos)); 283 checkVersion(); 284 return T(mPos); 285 } 286 287 ConstIterator& operator++() { 288 MOZ_ASSERT(mSet); 289 MOZ_ASSERT(mPos < kMaxBits); 290 checkVersion(); 291 do { 292 mPos++; 293 } while (mPos < kMaxBits && !mSet->HasBitAt(mPos)); 294 return *this; 295 } 296 }; 297 298 ConstIterator begin() const { return ConstIterator(*this, 0); } 299 300 ConstIterator end() const { return ConstIterator(*this, kMaxBits); } 301 302 private: 303 constexpr static Serialized BitFor(T aEnum) { 304 const auto pos = static_cast<size_t>(aEnum); 305 return BitAt(pos); 306 } 307 308 constexpr static Serialized BitAt(size_t aPos) { 309 MOZ_DIAGNOSTIC_ASSERT(aPos < kMaxBits); 310 if constexpr (std::is_unsigned_v<Serialized>) { 311 return static_cast<Serialized>(Serialized{1} << aPos); 312 } else { 313 Serialized bitField; 314 bitField[aPos] = true; 315 return bitField; 316 } 317 } 318 319 constexpr bool HasBitFor(T aEnum) const { 320 const auto pos = static_cast<size_t>(aEnum); 321 return HasBitAt(pos); 322 } 323 324 constexpr bool HasBitAt(size_t aPos) const { 325 if constexpr (std::is_unsigned_v<Serialized>) { 326 return mBitField & BitAt(aPos); 327 } else { 328 // for std::bitset and mozilla::BitSet 329 return mBitField.test(aPos); 330 } 331 } 332 333 constexpr void IncVersion() { 334 #ifdef DEBUG 335 mVersion++; 336 #endif 337 } 338 339 static constexpr size_t MaxBits() { 340 if constexpr (std::is_unsigned_v<Serialized>) { 341 return sizeof(Serialized) * 8; 342 } else { 343 return Serialized().size(); 344 } 345 } 346 347 static constexpr size_t kMaxBits = MaxBits(); 348 349 Serialized mBitField; 350 351 #ifdef DEBUG 352 uint64_t mVersion = 0; 353 #endif 354 }; 355 356 } // namespace mozilla 357 358 #endif /* mozilla_EnumSet_h_*/