summaryrefslogtreecommitdiff
path: root/mfbt/EnumSet.h
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/EnumSet.h')
-rw-r--r--mfbt/EnumSet.h344
1 files changed, 344 insertions, 0 deletions
diff --git a/mfbt/EnumSet.h b/mfbt/EnumSet.h
new file mode 100644
index 0000000000..5282ab30c3
--- /dev/null
+++ b/mfbt/EnumSet.h
@@ -0,0 +1,344 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A set abstraction for enumeration values. */
+
+#ifndef mozilla_EnumSet_h
+#define mozilla_EnumSet_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+
+#include <initializer_list>
+
+#include <stdint.h>
+
+namespace mozilla {
+
+/**
+ * EnumSet<T> is a set of values defined by an enumeration. It is implemented
+ * using a 32 bit mask for each value so it will only work for enums with an int
+ * representation less than 32. It works both for enum and enum class types.
+ */
+template<typename T>
+class EnumSet
+{
+public:
+ EnumSet()
+ : mBitField(0)
+ {
+ initVersion();
+ }
+
+ MOZ_IMPLICIT EnumSet(T aEnum)
+ : mBitField(bitFor(aEnum))
+ { }
+
+ EnumSet(T aEnum1, T aEnum2)
+ : mBitField(bitFor(aEnum1) |
+ bitFor(aEnum2))
+ {
+ initVersion();
+ }
+
+ EnumSet(T aEnum1, T aEnum2, T aEnum3)
+ : mBitField(bitFor(aEnum1) |
+ bitFor(aEnum2) |
+ bitFor(aEnum3))
+ {
+ initVersion();
+ }
+
+ EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
+ : mBitField(bitFor(aEnum1) |
+ bitFor(aEnum2) |
+ bitFor(aEnum3) |
+ bitFor(aEnum4))
+ {
+ initVersion();
+ }
+
+ MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
+ : mBitField(0)
+ {
+ for (auto value : list) {
+ (*this) += value;
+ }
+ initVersion();
+ }
+
+ EnumSet(const EnumSet& aEnumSet)
+ : mBitField(aEnumSet.mBitField)
+ {
+ initVersion();
+ }
+
+ /**
+ * Add an element
+ */
+ void operator+=(T aEnum)
+ {
+ incVersion();
+ mBitField |= bitFor(aEnum);
+ }
+
+ /**
+ * Add an element
+ */
+ EnumSet<T> operator+(T aEnum) const
+ {
+ EnumSet<T> result(*this);
+ result += aEnum;
+ return result;
+ }
+
+ /**
+ * Union
+ */
+ void operator+=(const EnumSet<T> aEnumSet)
+ {
+ incVersion();
+ mBitField |= aEnumSet.mBitField;
+ }
+
+ /**
+ * Union
+ */
+ EnumSet<T> operator+(const EnumSet<T> aEnumSet) const
+ {
+ EnumSet<T> result(*this);
+ result += aEnumSet;
+ return result;
+ }
+
+ /**
+ * Remove an element
+ */
+ void operator-=(T aEnum)
+ {
+ incVersion();
+ mBitField &= ~(bitFor(aEnum));
+ }
+
+ /**
+ * Remove an element
+ */
+ EnumSet<T> operator-(T aEnum) const
+ {
+ EnumSet<T> result(*this);
+ result -= aEnum;
+ return result;
+ }
+
+ /**
+ * Remove a set of elements
+ */
+ void operator-=(const EnumSet<T> aEnumSet)
+ {
+ incVersion();
+ mBitField &= ~(aEnumSet.mBitField);
+ }
+
+ /**
+ * Remove a set of elements
+ */
+ EnumSet<T> operator-(const EnumSet<T> aEnumSet) const
+ {
+ EnumSet<T> result(*this);
+ result -= aEnumSet;
+ return result;
+ }
+
+ /**
+ * Clear
+ */
+ void clear()
+ {
+ incVersion();
+ mBitField = 0;
+ }
+
+ /**
+ * Intersection
+ */
+ void operator&=(const EnumSet<T> aEnumSet)
+ {
+ incVersion();
+ mBitField &= aEnumSet.mBitField;
+ }
+
+ /**
+ * Intersection
+ */
+ EnumSet<T> operator&(const EnumSet<T> aEnumSet) const
+ {
+ EnumSet<T> result(*this);
+ result &= aEnumSet;
+ return result;
+ }
+
+ /**
+ * Equality
+ */
+ bool operator==(const EnumSet<T> aEnumSet) const
+ {
+ return mBitField == aEnumSet.mBitField;
+ }
+
+ /**
+ * Test is an element is contained in the set.
+ */
+ bool contains(T aEnum) const
+ {
+ return mBitField & bitFor(aEnum);
+ }
+
+ /**
+ * Return the number of elements in the set.
+ */
+ uint8_t size() const
+ {
+ uint8_t count = 0;
+ for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
+ if (bitField & 1) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ bool isEmpty() const
+ {
+ return mBitField == 0;
+ }
+
+ uint32_t serialize() const
+ {
+ return mBitField;
+ }
+
+ void deserialize(uint32_t aValue)
+ {
+ incVersion();
+ mBitField = aValue;
+ }
+
+ class ConstIterator
+ {
+ const EnumSet<T>* mSet;
+ uint32_t mPos;
+#ifdef DEBUG
+ uint64_t mVersion;
+#endif
+
+ void checkVersion() {
+ // Check that the set has not been modified while being iterated.
+ MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
+ }
+
+ public:
+ ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
+ : mSet(&aSet), mPos(aPos)
+ {
+#ifdef DEBUG
+ mVersion = mSet->mVersion;
+#endif
+ MOZ_ASSERT(aPos <= kMaxBits);
+ if (aPos != kMaxBits && !mSet->contains(T(mPos)))
+ ++*this;
+ }
+
+ ConstIterator(const ConstIterator& aOther)
+ : mSet(aOther.mSet), mPos(aOther.mPos)
+ {
+#ifdef DEBUG
+ mVersion = aOther.mVersion;
+ checkVersion();
+#endif
+ }
+
+ ConstIterator(ConstIterator&& aOther)
+ : mSet(aOther.mSet), mPos(aOther.mPos)
+ {
+#ifdef DEBUG
+ mVersion = aOther.mVersion;
+ checkVersion();
+#endif
+ aOther.mSet = nullptr;
+ }
+
+ ~ConstIterator() {
+ checkVersion();
+ }
+
+ bool operator==(const ConstIterator& other) {
+ MOZ_ASSERT(mSet == other.mSet);
+ checkVersion();
+ return mPos == other.mPos;
+ }
+
+ bool operator!=(const ConstIterator& other) {
+ return !(*this == other);
+ }
+
+ T operator*() {
+ MOZ_ASSERT(mSet);
+ MOZ_ASSERT(mPos < kMaxBits);
+ MOZ_ASSERT(mSet->contains(T(mPos)));
+ checkVersion();
+ return T(mPos);
+ }
+
+ ConstIterator& operator++() {
+ MOZ_ASSERT(mSet);
+ MOZ_ASSERT(mPos < kMaxBits);
+ checkVersion();
+ do {
+ mPos++;
+ } while (mPos < kMaxBits && !mSet->contains(T(mPos)));
+ return *this;
+ }
+ };
+
+ ConstIterator begin() const {
+ return ConstIterator(*this, 0);
+ }
+
+ ConstIterator end() const {
+ return ConstIterator(*this, kMaxBits);
+ }
+
+private:
+ static uint32_t bitFor(T aEnum)
+ {
+ uint32_t bitNumber = (uint32_t)aEnum;
+ MOZ_ASSERT(bitNumber < kMaxBits);
+ return 1U << bitNumber;
+ }
+
+ void initVersion() {
+#ifdef DEBUG
+ mVersion = 0;
+#endif
+ }
+
+ void incVersion() {
+#ifdef DEBUG
+ mVersion++;
+#endif
+ }
+
+ static const size_t kMaxBits = 32;
+ uint32_t mBitField;
+
+#ifdef DEBUG
+ uint64_t mVersion;
+#endif
+};
+
+} // namespace mozilla
+
+#endif /* mozilla_EnumSet_h_*/