tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_*/