2020-10-11 22:03:33 +00:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
|
|
|
#ifndef mozilla_BitSet_h
|
|
|
|
#define mozilla_BitSet_h
|
|
|
|
|
|
|
|
#include "mozilla/Array.h"
|
2021-11-09 12:34:51 +00:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2021-01-20 10:03:53 +00:00
|
|
|
#include "mozilla/PodOperations.h"
|
2020-10-11 22:03:33 +00:00
|
|
|
#include "mozilla/Span.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An object like std::bitset but which provides access to the underlying
|
|
|
|
* storage.
|
|
|
|
*
|
|
|
|
* The limited API is due to expedience only; feel free to flesh out any
|
|
|
|
* std::bitset-like members.
|
|
|
|
*/
|
|
|
|
template <size_t N, typename Word = size_t>
|
|
|
|
class BitSet {
|
2021-01-20 10:03:53 +00:00
|
|
|
static_assert(std::is_unsigned_v<Word>,
|
|
|
|
"The Word type must be an unsigned integral type");
|
|
|
|
|
2020-10-11 22:03:33 +00:00
|
|
|
private:
|
|
|
|
static constexpr size_t kBitsPerWord = 8 * sizeof(Word);
|
2021-01-20 10:03:53 +00:00
|
|
|
static constexpr size_t kNumWords = (N + kBitsPerWord - 1) / kBitsPerWord;
|
2021-11-09 12:34:51 +00:00
|
|
|
static constexpr size_t kPaddingBits = (kNumWords * kBitsPerWord) - N;
|
|
|
|
static constexpr Word kPaddingMask = Word(-1) >> kPaddingBits;
|
2020-10-11 22:03:33 +00:00
|
|
|
|
|
|
|
// The zeroth bit in the bitset is the least significant bit of mStorage[0].
|
|
|
|
Array<Word, kNumWords> mStorage;
|
|
|
|
|
2021-11-09 12:34:51 +00:00
|
|
|
constexpr void ResetPaddingBits() {
|
|
|
|
if constexpr (kPaddingBits != 0) {
|
|
|
|
mStorage[kNumWords - 1] &= kPaddingMask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 22:03:33 +00:00
|
|
|
public:
|
|
|
|
class Reference {
|
|
|
|
public:
|
|
|
|
Reference(BitSet<N, Word>& aBitSet, size_t aPos)
|
|
|
|
: mBitSet(aBitSet), mPos(aPos) {}
|
|
|
|
|
|
|
|
Reference& operator=(bool aValue) {
|
|
|
|
auto bit = Word(1) << (mPos % kBitsPerWord);
|
|
|
|
auto& word = mBitSet.mStorage[mPos / kBitsPerWord];
|
|
|
|
word = (word & ~bit) | (aValue ? bit : 0);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_IMPLICIT operator bool() const { return mBitSet.Test(mPos); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
BitSet<N, Word>& mBitSet;
|
|
|
|
size_t mPos;
|
|
|
|
};
|
|
|
|
|
2021-11-09 12:34:51 +00:00
|
|
|
constexpr BitSet() : mStorage() {}
|
2020-10-11 22:03:33 +00:00
|
|
|
|
|
|
|
BitSet(const BitSet& aOther) { *this = aOther; }
|
|
|
|
|
|
|
|
BitSet& operator=(const BitSet& aOther) {
|
|
|
|
PodCopy(mStorage.begin(), aOther.mStorage.begin(), kNumWords);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit BitSet(Span<Word, kNumWords> aStorage) {
|
2021-01-20 10:03:53 +00:00
|
|
|
PodCopy(mStorage.begin(), aStorage.Elements(), kNumWords);
|
2020-10-11 22:03:33 +00:00
|
|
|
}
|
|
|
|
|
2021-01-20 10:03:53 +00:00
|
|
|
constexpr size_t Size() const { return N; }
|
|
|
|
|
2020-10-11 22:03:33 +00:00
|
|
|
constexpr bool Test(size_t aPos) const {
|
|
|
|
MOZ_ASSERT(aPos < N);
|
|
|
|
return mStorage[aPos / kBitsPerWord] & (Word(1) << (aPos % kBitsPerWord));
|
|
|
|
}
|
|
|
|
|
2021-11-09 12:34:51 +00:00
|
|
|
constexpr bool IsEmpty() const {
|
|
|
|
for (const Word& word : mStorage) {
|
|
|
|
if (word) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit constexpr operator bool() { return !IsEmpty(); }
|
|
|
|
|
2020-10-11 22:03:33 +00:00
|
|
|
constexpr bool operator[](size_t aPos) const { return Test(aPos); }
|
|
|
|
|
|
|
|
Reference operator[](size_t aPos) {
|
|
|
|
MOZ_ASSERT(aPos < N);
|
|
|
|
return {*this, aPos};
|
|
|
|
}
|
|
|
|
|
|
|
|
BitSet operator|(const BitSet<N, Word>& aOther) {
|
|
|
|
BitSet result = *this;
|
|
|
|
result |= aOther;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-11-09 12:34:51 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-01-20 10:03:53 +00:00
|
|
|
// Set all bits to false.
|
|
|
|
void ResetAll() { PodArrayZero(mStorage); }
|
|
|
|
|
|
|
|
// Set all bits to true.
|
|
|
|
void SetAll() {
|
|
|
|
memset(mStorage.begin(), 0xff, kNumWords * sizeof(Word));
|
2021-11-09 12:34:51 +00:00
|
|
|
ResetPaddingBits();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Flip() {
|
|
|
|
for (Word& word : mStorage) {
|
|
|
|
word = ~word;
|
2021-01-20 10:03:53 +00:00
|
|
|
}
|
2021-11-09 12:34:51 +00:00
|
|
|
|
|
|
|
ResetPaddingBits();
|
2021-01-20 10:03:53 +00:00
|
|
|
}
|
|
|
|
|
2020-10-11 22:03:33 +00:00
|
|
|
Span<Word> Storage() { return mStorage; }
|
|
|
|
|
|
|
|
Span<const Word> Storage() const { return mStorage; }
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // mozilla_BitSet_h
|