зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1733963 - Part 1: Make BitSet work as storage for EnumSet. r=glandium
Differential Revision: https://phabricator.services.mozilla.com/D127447
This commit is contained in:
Родитель
8f4fabfec4
Коммит
f31ef6faa9
|
@ -29,7 +29,7 @@ class Array {
|
|||
using ElementType = T;
|
||||
static constexpr size_t Length = _Length;
|
||||
|
||||
Array() = default;
|
||||
constexpr Array() = default;
|
||||
|
||||
template <typename... Args>
|
||||
MOZ_IMPLICIT constexpr Array(Args&&... aArgs)
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#define mozilla_BitSet_h
|
||||
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
|
@ -28,10 +30,18 @@ class BitSet {
|
|||
private:
|
||||
static constexpr size_t kBitsPerWord = 8 * sizeof(Word);
|
||||
static constexpr size_t kNumWords = (N + kBitsPerWord - 1) / kBitsPerWord;
|
||||
static constexpr size_t kPaddingBits = (kNumWords * kBitsPerWord) - N;
|
||||
static constexpr Word kPaddingMask = Word(-1) >> kPaddingBits;
|
||||
|
||||
// The zeroth bit in the bitset is the least significant bit of mStorage[0].
|
||||
Array<Word, kNumWords> mStorage;
|
||||
|
||||
constexpr void ResetPaddingBits() {
|
||||
if constexpr (kPaddingBits != 0) {
|
||||
mStorage[kNumWords - 1] &= kPaddingMask;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
class Reference {
|
||||
public:
|
||||
|
@ -52,7 +62,7 @@ class BitSet {
|
|||
size_t mPos;
|
||||
};
|
||||
|
||||
BitSet() { ResetAll(); }
|
||||
constexpr BitSet() : mStorage() {}
|
||||
|
||||
BitSet(const BitSet& aOther) { *this = aOther; }
|
||||
|
||||
|
@ -72,6 +82,17 @@ class BitSet {
|
|||
return mStorage[aPos / kBitsPerWord] & (Word(1) << (aPos % kBitsPerWord));
|
||||
}
|
||||
|
||||
constexpr bool IsEmpty() const {
|
||||
for (const Word& word : mStorage) {
|
||||
if (word) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() { return !IsEmpty(); }
|
||||
|
||||
constexpr bool operator[](size_t aPos) const { return Test(aPos); }
|
||||
|
||||
Reference operator[](size_t aPos) {
|
||||
|
@ -92,17 +113,58 @@ class BitSet {
|
|||
return *this;
|
||||
}
|
||||
|
||||
BitSet operator~() const {
|
||||
BitSet result = *this;
|
||||
result.Flip();
|
||||
return result;
|
||||
}
|
||||
|
||||
BitSet& operator&=(const BitSet<N, Word>& aOther) {
|
||||
for (size_t i = 0; i < ArrayLength(mStorage); i++) {
|
||||
mStorage[i] &= aOther.mStorage[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitSet operator&(const BitSet<N, Word>& aOther) const {
|
||||
BitSet result = *this;
|
||||
result &= aOther;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const BitSet<N, Word>& aOther) const {
|
||||
return mStorage == aOther.mStorage;
|
||||
}
|
||||
|
||||
size_t Count() const {
|
||||
size_t count = 0;
|
||||
|
||||
for (const Word& word : mStorage) {
|
||||
if constexpr (kBitsPerWord > 32) {
|
||||
count += CountPopulation64(word);
|
||||
} else {
|
||||
count += CountPopulation32(word);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Set all bits to false.
|
||||
void ResetAll() { PodArrayZero(mStorage); }
|
||||
|
||||
// Set all bits to true.
|
||||
void SetAll() {
|
||||
memset(mStorage.begin(), 0xff, kNumWords * sizeof(Word));
|
||||
constexpr size_t paddingBits = (kNumWords * kBitsPerWord) - N;
|
||||
constexpr Word paddingMask = Word(-1) >> paddingBits;
|
||||
if constexpr (paddingBits != 0) {
|
||||
mStorage[kNumWords - 1] &= paddingMask;
|
||||
ResetPaddingBits();
|
||||
}
|
||||
|
||||
void Flip() {
|
||||
for (Word& word : mStorage) {
|
||||
word = ~word;
|
||||
}
|
||||
|
||||
ResetPaddingBits();
|
||||
}
|
||||
|
||||
Span<Word> Storage() { return mStorage; }
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
|
@ -22,15 +23,16 @@ namespace mozilla {
|
|||
/**
|
||||
* EnumSet<T, U> is a set of values defined by an enumeration. It is implemented
|
||||
* using a bit mask with the size of U for each value. It works both for enum
|
||||
* and enum class types.
|
||||
* and enum class types. EnumSet also works with U being a BitSet.
|
||||
*/
|
||||
template <typename T, typename Serialized = typename std::make_unsigned<
|
||||
typename std::underlying_type<T>::type>::type>
|
||||
class EnumSet {
|
||||
public:
|
||||
typedef T valueType;
|
||||
using valueType = T;
|
||||
using serializedType = Serialized;
|
||||
|
||||
constexpr EnumSet() : mBitField(0) {}
|
||||
constexpr EnumSet() : mBitField() {}
|
||||
|
||||
constexpr MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) {}
|
||||
|
||||
|
@ -44,7 +46,7 @@ class EnumSet {
|
|||
: mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3) |
|
||||
bitFor(aEnum4)) {}
|
||||
|
||||
constexpr MOZ_IMPLICIT EnumSet(std::initializer_list<T> list) : mBitField(0) {
|
||||
constexpr MOZ_IMPLICIT EnumSet(std::initializer_list<T> list) : mBitField() {
|
||||
for (auto value : list) {
|
||||
(*this) += value;
|
||||
}
|
||||
|
@ -133,7 +135,7 @@ class EnumSet {
|
|||
*/
|
||||
void clear() {
|
||||
incVersion();
|
||||
mBitField = 0;
|
||||
mBitField = Serialized();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,7 +182,9 @@ class EnumSet {
|
|||
/**
|
||||
* Test is an element is contained in the set.
|
||||
*/
|
||||
bool contains(T aEnum) const { return mBitField & bitFor(aEnum); }
|
||||
bool contains(T aEnum) const {
|
||||
return static_cast<bool>(mBitField & bitFor(aEnum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a set is contained in the set.
|
||||
|
@ -192,17 +196,25 @@ class EnumSet {
|
|||
/**
|
||||
* Return the number of elements in the set.
|
||||
*/
|
||||
uint8_t size() const {
|
||||
uint8_t count = 0;
|
||||
for (Serialized bitField = mBitField; bitField; bitField >>= 1) {
|
||||
if (bitField & 1) {
|
||||
count++;
|
||||
size_t size() const {
|
||||
if constexpr (std::is_unsigned_v<Serialized>) {
|
||||
if constexpr (kMaxBits > 32) {
|
||||
return CountPopulation64(mBitField);
|
||||
} else {
|
||||
return CountPopulation32(mBitField);
|
||||
}
|
||||
} else {
|
||||
return mBitField.Count();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return mBitField == 0; }
|
||||
bool isEmpty() const {
|
||||
if constexpr (std::is_unsigned_v<Serialized>) {
|
||||
return mBitField == 0;
|
||||
} else {
|
||||
return mBitField.IsEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Serialized serialize() const { return mBitField; }
|
||||
|
||||
|
@ -230,7 +242,9 @@ class EnumSet {
|
|||
mVersion = mSet->mVersion;
|
||||
#endif
|
||||
MOZ_ASSERT(aPos <= kMaxBits);
|
||||
if (aPos != kMaxBits && !mSet->contains(T(mPos))) ++*this;
|
||||
if (aPos != kMaxBits && !mSet->contains(T(mPos))) {
|
||||
++*this;
|
||||
}
|
||||
}
|
||||
|
||||
ConstIterator(const ConstIterator& aOther)
|
||||
|
@ -287,9 +301,15 @@ class EnumSet {
|
|||
|
||||
private:
|
||||
constexpr static Serialized bitFor(T aEnum) {
|
||||
auto bitNumber = static_cast<Serialized>(aEnum);
|
||||
auto bitNumber = static_cast<size_t>(aEnum);
|
||||
MOZ_DIAGNOSTIC_ASSERT(bitNumber < kMaxBits);
|
||||
return static_cast<Serialized>(Serialized{1} << bitNumber);
|
||||
if constexpr (std::is_unsigned_v<Serialized>) {
|
||||
return static_cast<Serialized>(Serialized{1} << bitNumber);
|
||||
} else {
|
||||
Serialized bitField;
|
||||
bitField[bitNumber] = true;
|
||||
return bitField;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void incVersion() {
|
||||
|
@ -298,7 +318,15 @@ class EnumSet {
|
|||
#endif
|
||||
}
|
||||
|
||||
static const size_t kMaxBits = sizeof(Serialized) * 8;
|
||||
constexpr size_t MaxBits() const {
|
||||
if constexpr (std::is_unsigned_v<Serialized>) {
|
||||
return sizeof(Serialized) * 8;
|
||||
} else {
|
||||
return mBitField.Size();
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr size_t kMaxBits = EnumSet().MaxBits();
|
||||
|
||||
Serialized mBitField;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче