Mypal/mfbt/EnumSet.h

344 lines
6.1 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 = 0;
#endif
};
} // namespace mozilla
#endif /* mozilla_EnumSet_h_*/