#ifndef COMMON_BITSETITERATOR_H_
#define COMMON_BITSETITERATOR_H_
#include <stdint.h>
#include <array>
#include "common/angleutils.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/platform.h"
namespace angle
{
template <typename BitsT, typename ParamT>
constexpr BitsT Bit(ParamT x)
{
ASSERT(static_cast<size_t>(x) < sizeof(BitsT) * 8);
return (static_cast<BitsT>(1) << static_cast<size_t>(x));
}
template <typename BitsT, typename ParamT>
constexpr BitsT BitMask(ParamT x)
{
if (static_cast<size_t>(x) == 0)
{
return 0;
}
return ((Bit<BitsT>(static_cast<ParamT>(static_cast<size_t>(x) - 1)) - 1) << 1) | 1;
}
template <size_t N, typename BitsT, typename ParamT = std::size_t>
class BitSetT final
{
public:
class Reference final
{
public:
~Reference() {}
Reference &operator=(bool x)
{
mParent->set(mBit, x);
return *this;
}
explicit operator bool() const { return mParent->test(mBit); }
private:
friend class BitSetT;
Reference(BitSetT *parent, ParamT bit) : mParent(parent), mBit(bit) {}
BitSetT *mParent;
ParamT mBit;
};
class Iterator final
{
public:
Iterator(const BitSetT &bits);
Iterator &operator++();
bool operator==(const Iterator &other) const;
bool operator!=(const Iterator &other) const;
ParamT operator*() const;
void resetLaterBit(std::size_t index)
{
ASSERT(index > mCurrentBit);
mBitsCopy.reset(index);
}
void resetLaterBits(const BitSetT &bits)
{
BitSetT maskedBits = ~Mask(mCurrentBit + 1);
maskedBits &= bits;
mBitsCopy &= ~maskedBits;
}
void setLaterBit(std::size_t index)
{
ASSERT(index > mCurrentBit);
mBitsCopy.set(index);
}
void setLaterBits(const BitSetT &bits)
{
ASSERT((BitSetT(bits) &= Mask(mCurrentBit + 1)).none());
mBitsCopy |= bits;
}
private:
std::size_t getNextBit();
BitSetT mBitsCopy;
std::size_t mCurrentBit;
};
using value_type = BitsT;
using param_type = ParamT;
constexpr BitSetT();
constexpr explicit BitSetT(BitsT value);
constexpr explicit BitSetT(std::initializer_list<ParamT> init);
constexpr bool operator==(const BitSetT &other) const;
constexpr bool operator!=(const BitSetT &other) const;
constexpr bool operator[](ParamT pos) const;
Reference operator[](ParamT pos) { return Reference(this, pos); }
constexpr bool test(ParamT pos) const;
constexpr bool all() const;
constexpr bool any() const;
constexpr bool none() const;
constexpr std::size_t count() const;
constexpr bool hasGaps() const;
constexpr static std::size_t size() { return N; }
constexpr BitSetT &operator&=(const BitSetT &other);
constexpr BitSetT &operator|=(const BitSetT &other);
constexpr BitSetT &operator^=(const BitSetT &other);
constexpr BitSetT operator~() const;
constexpr BitSetT &operator&=(BitsT value);
constexpr BitSetT &operator|=(BitsT value);
constexpr BitSetT &operator^=(BitsT value);
constexpr BitSetT operator<<(std::size_t pos) const;
constexpr BitSetT &operator<<=(std::size_t pos);
constexpr BitSetT operator>>(std::size_t pos) const;
constexpr BitSetT &operator>>=(std::size_t pos);
constexpr BitSetT &set();
constexpr BitSetT &set(ParamT pos, bool value = true);
constexpr BitSetT &reset();
constexpr BitSetT &reset(ParamT pos);
constexpr BitSetT &flip();
constexpr BitSetT &flip(ParamT pos);
constexpr BitsT bits() const { return mBits; }
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(BitSetT()); }
constexpr static BitSetT Zero() { return BitSetT(); }
constexpr ParamT first() const;
constexpr ParamT last() const;
constexpr static BitSetT Mask(std::size_t x)
{
BitSetT result;
result.mBits = BitMask<BitsT>(static_cast<ParamT>(x));
return result;
}
private:
BitsT mBits;
};
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT>::BitSetT() : mBits(0)
{
static_assert(N > 0, "Bitset type cannot support zero bits.");
static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N).bits())
{}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT>::BitSetT(std::initializer_list<ParamT> init) : mBits(0)
{
for (ParamT element : init)
{
mBits |= Bit<BitsT>(element);
}
ASSERT(mBits == (mBits & Mask(N).bits()));
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::operator==(const BitSetT &other) const
{
return mBits == other.mBits;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::operator!=(const BitSetT &other) const
{
return mBits != other.mBits;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::operator[](ParamT pos) const
{
return test(pos);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::test(ParamT pos) const
{
return (mBits & Bit<BitsT>(pos)) != 0;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::all() const
{
ASSERT(mBits == (mBits & Mask(N).bits()));
return mBits == Mask(N).bits();
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::any() const
{
ASSERT(mBits == (mBits & Mask(N).bits()));
return (mBits != 0);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::none() const
{
ASSERT(mBits == (mBits & Mask(N).bits()));
return (mBits == 0);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr std::size_t BitSetT<N, BitsT, ParamT>::count() const
{
return gl::BitCount(mBits);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr bool BitSetT<N, BitsT, ParamT>::hasGaps() const
{
ASSERT(mBits == (mBits & Mask(N).bits()));
return (mBits != Mask(N).bits()) && ((mBits & (mBits + 1)) != 0);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(const BitSetT &other)
{
mBits &= other.mBits;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(const BitSetT &other)
{
mBits |= other.mBits;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(const BitSetT &other)
{
mBits = mBits ^ other.mBits;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator~() const
{
return BitSetT<N, BitsT, ParamT>(~mBits & Mask(N).bits());
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(BitsT value)
{
mBits &= value;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(BitsT value)
{
mBits |= value;
ASSERT(mBits == (mBits & Mask(N).bits()));
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(BitsT value)
{
mBits ^= value;
ASSERT(mBits == (mBits & Mask(N).bits()));
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator<<(std::size_t pos) const
{
return BitSetT<N, BitsT, ParamT>((mBits << pos) & Mask(N).bits());
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator<<=(std::size_t pos)
{
mBits = mBits << pos & Mask(N).bits();
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator>>(std::size_t pos) const
{
return BitSetT<N, BitsT, ParamT>(mBits >> pos);
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator>>=(std::size_t pos)
{
mBits = (mBits >> pos) & Mask(N).bits();
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set()
{
ASSERT(mBits == (mBits & Mask(N).bits()));
mBits = Mask(N).bits();
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set(ParamT pos, bool value)
{
ASSERT(static_cast<size_t>(pos) < N);
if (value)
{
mBits |= Bit<BitsT>(pos);
}
else
{
reset(pos);
}
ASSERT(mBits == (mBits & Mask(N).bits()));
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset()
{
ASSERT(mBits == (mBits & Mask(N).bits()));
mBits = 0;
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset(ParamT pos)
{
ASSERT(static_cast<size_t>(pos) < N);
ASSERT(mBits == (mBits & Mask(N).bits()));
mBits &= ~Bit<BitsT>(pos);
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip()
{
ASSERT(mBits == (mBits & Mask(N).bits()));
mBits ^= Mask(N).bits();
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip(ParamT pos)
{
ASSERT(static_cast<size_t>(pos) < N);
mBits ^= Bit<BitsT>(pos);
ASSERT(mBits == (mBits & Mask(N).bits()));
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
constexpr ParamT BitSetT<N, BitsT, ParamT>::first() const
{
ASSERT(!none());
return static_cast<ParamT>(gl::ScanForward(mBits));
}
template <size_t N, typename BitsT, typename ParamT>
constexpr ParamT BitSetT<N, BitsT, ParamT>::last() const
{
ASSERT(!none());
return static_cast<ParamT>(gl::ScanReverse(mBits));
}
template <size_t N, typename BitsT, typename ParamT>
BitSetT<N, BitsT, ParamT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
{
if (bits.any())
{
mCurrentBit = getNextBit();
}
}
template <size_t N, typename BitsT, typename ParamT>
ANGLE_INLINE typename BitSetT<N, BitsT, ParamT>::Iterator &
BitSetT<N, BitsT, ParamT>::Iterator::operator++()
{
ASSERT(mBitsCopy.any());
mBitsCopy.reset(static_cast<ParamT>(mCurrentBit));
mCurrentBit = getNextBit();
return *this;
}
template <size_t N, typename BitsT, typename ParamT>
bool BitSetT<N, BitsT, ParamT>::Iterator::operator==(const Iterator &other) const
{
return mBitsCopy == other.mBitsCopy;
}
template <size_t N, typename BitsT, typename ParamT>
bool BitSetT<N, BitsT, ParamT>::Iterator::operator!=(const Iterator &other) const
{
return !(*this == other);
}
template <size_t N, typename BitsT, typename ParamT>
ParamT BitSetT<N, BitsT, ParamT>::Iterator::operator*() const
{
return static_cast<ParamT>(mCurrentBit);
}
template <size_t N, typename BitsT, typename ParamT>
std::size_t BitSetT<N, BitsT, ParamT>::Iterator::getNextBit()
{
if (mBitsCopy.none())
{
return 0;
}
return gl::ScanForward(mBitsCopy.mBits);
}
template <size_t N>
using BitSet8 = BitSetT<N, uint8_t>;
template <size_t N>
using BitSet16 = BitSetT<N, uint16_t>;
template <size_t N>
using BitSet32 = BitSetT<N, uint32_t>;
static_assert(std::is_trivially_copyable<BitSet32<32>>(), "must be memcpy-able");
template <size_t N>
using BitSet64 = BitSetT<N, uint64_t>;
template <std::size_t N>
class BitSetArray;
namespace priv
{
template <size_t N, typename T>
using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
template <size_t N, typename Enable = void>
struct GetBitSet
{
using Type = BitSetArray<N>;
};
#if defined(ANGLE_IS_64_BIT_CPU)
template <size_t N>
struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
{
using Type = BitSet64<N>;
};
constexpr std::size_t kDefaultBitSetSize = 64;
using BaseBitSetType = BitSet64<kDefaultBitSetSize>;
#else
template <size_t N>
struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
{
using Type = BitSet32<N>;
};
constexpr std::size_t kDefaultBitSetSize = 32;
using BaseBitSetType = BitSet32<kDefaultBitSetSize>;
#endif
}
template <size_t N>
using BitSet = typename priv::GetBitSet<N>::Type;
template <std::size_t N>
class BitSetArray final
{
public:
using BaseBitSet = priv::BaseBitSetType;
using value_type = BaseBitSet::value_type;
using param_type = BaseBitSet::param_type;
constexpr BitSetArray();
constexpr explicit BitSetArray(uint64_t value);
constexpr explicit BitSetArray(std::initializer_list<param_type> init);
class Reference final
{
public:
~Reference() {}
Reference &operator=(bool x)
{
mParent.set(mPosition, x);
return *this;
}
explicit operator bool() const { return mParent.test(mPosition); }
private:
friend class BitSetArray;
Reference(BitSetArray &parent, std::size_t pos) : mParent(parent), mPosition(pos) {}
BitSetArray &mParent;
std::size_t mPosition;
};
class Iterator final
{
public:
Iterator(const BitSetArray<N> &bitSetArray, std::size_t index);
Iterator &operator++();
bool operator==(const Iterator &other) const;
bool operator!=(const Iterator &other) const;
size_t operator*() const;
void resetLaterBit(std::size_t pos)
{
ASSERT(pos > (mIndex * priv::kDefaultBitSetSize) + *mCurrentIterator);
prepareCopy();
mParentCopy.reset(pos);
updateIteratorBit(pos, false);
}
void setLaterBit(std::size_t pos)
{
ASSERT(pos > (mIndex * priv::kDefaultBitSetSize) + *mCurrentIterator);
prepareCopy();
mParentCopy.set(pos);
updateIteratorBit(pos, true);
}
void resetLaterBits(const BitSetArray &bits)
{
ASSERT(bits.first() > (mIndex * priv::kDefaultBitSetSize) + *mCurrentIterator);
prepareCopy();
mParentCopy &= ~bits;
updateIteratorBits(bits);
}
void setLaterBits(const BitSetArray &bits)
{
ASSERT(bits.first() > (mIndex * priv::kDefaultBitSetSize) + *mCurrentIterator);
prepareCopy();
mParentCopy |= bits;
updateIteratorBits(bits);
}
private:
ANGLE_INLINE void prepareCopy()
{
ASSERT(mParent.mBaseBitSetArray[mIndex].end() ==
mParentCopy.mBaseBitSetArray[mIndex].end());
if (mParentCopy.none())
{
mParentCopy = mParent;
mCurrentParent = &mParentCopy;
}
}
ANGLE_INLINE void updateIteratorBit(std::size_t pos, bool setBit)
{
size_t index = pos >> kShiftForDivision;
size_t offset = pos & kDefaultBitSetSizeMinusOne;
if (index == mIndex)
{
if (setBit)
{
mCurrentIterator.setLaterBit(offset);
}
else
{
mCurrentIterator.resetLaterBit(offset);
}
}
}
ANGLE_INLINE void updateIteratorBits(const BitSetArray &bits)
{
mCurrentIterator.setLaterBits(bits.mBaseBitSetArray[mIndex]);
}
size_t mIndex;
const BitSetArray &mParent;
BitSetArray mParentCopy;
const BitSetArray *mCurrentParent;
typename BaseBitSet::Iterator mCurrentIterator;
};
constexpr static std::size_t size() { return N; }
Iterator begin() const { return Iterator(*this, 0); }
Iterator end() const { return Iterator(*this, kArraySize); }
constexpr BitSetArray &operator&=(const BitSetArray &other);
constexpr BitSetArray &operator|=(const BitSetArray &other);
constexpr BitSetArray &operator^=(const BitSetArray &other);
constexpr BitSetArray<N> operator&(const angle::BitSetArray<N> &other) const;
constexpr BitSetArray<N> operator|(const angle::BitSetArray<N> &other) const;
constexpr BitSetArray<N> operator^(const angle::BitSetArray<N> &other) const;
constexpr bool operator==(const angle::BitSetArray<N> &other) const;
constexpr bool operator!=(const angle::BitSetArray<N> &other) const;
constexpr BitSetArray operator~() const;
constexpr bool operator[](std::size_t pos) const;
constexpr Reference operator[](std::size_t pos)
{
ASSERT(pos < size());
return Reference(*this, pos);
}
constexpr BitSetArray &set();
constexpr BitSetArray &set(std::size_t pos, bool value = true);
constexpr BitSetArray &reset();
constexpr BitSetArray &reset(std::size_t pos);
constexpr bool test(std::size_t pos) const;
constexpr bool all() const;
constexpr bool any() const;
constexpr bool none() const;
constexpr std::size_t count() const;
constexpr bool intersects(const BitSetArray &other) const;
constexpr BitSetArray<N> &flip();
constexpr param_type first() const;
constexpr param_type last() const;
constexpr value_type bits(size_t index) const;
constexpr static size_t ArraySize() { return kArraySize; }
template <size_t M = N>
constexpr auto bits() const
-> std::enable_if_t<priv::kDefaultBitSetSize == 32 && M <= 64, uint64_t>
{
static_assert(kArraySize == 2);
uint64_t result = mBaseBitSetArray[1].bits();
return (result << 32) | mBaseBitSetArray[0].bits();
}
constexpr static BitSetArray Mask(std::size_t x);
template <std::size_t BitSetSize, std::enable_if_t<(BitSetSize < 64), int> = 0>
constexpr void initFromValue(uint64_t value);
template <std::size_t BitSetSize, std::enable_if_t<(BitSetSize >= 64), int> = 0>
constexpr void initFromValue(uint64_t value);
private:
static constexpr std::size_t kDefaultBitSetSizeMinusOne = priv::kDefaultBitSetSize - 1;
static constexpr std::size_t kShiftForDivision =
static_cast<std::size_t>(rx::Log2(static_cast<unsigned int>(priv::kDefaultBitSetSize)));
static constexpr std::size_t kArraySize =
((N + kDefaultBitSetSizeMinusOne) >> kShiftForDivision);
constexpr static std::size_t kLastElementCount = (N & kDefaultBitSetSizeMinusOne);
constexpr static std::size_t kLastElementMask =
priv::BaseBitSetType::Mask(kLastElementCount == 0 ? priv::kDefaultBitSetSize
: kLastElementCount)
.bits();
std::array<BaseBitSet, kArraySize> mBaseBitSetArray;
};
static_assert(std::is_trivially_copyable<BitSetArray<32>>(), "must be memcpy-able");
template <std::size_t N>
constexpr BitSetArray<N>::BitSetArray()
{
static_assert(N > priv::kDefaultBitSetSize, "BitSetArray type can't support requested size.");
reset();
}
template <std::size_t N>
constexpr BitSetArray<N>::BitSetArray(uint64_t value)
{
reset();
initFromValue<priv::kDefaultBitSetSize>(value);
}
template <std::size_t N>
constexpr BitSetArray<N>::BitSetArray(std::initializer_list<param_type> init)
{
reset();
for (param_type element : init)
{
size_t index = element >> kShiftForDivision;
size_t offset = element & kDefaultBitSetSizeMinusOne;
mBaseBitSetArray[index].set(offset, true);
}
}
template <size_t N>
BitSetArray<N>::Iterator::Iterator(const BitSetArray<N> &bitSetArray, std::size_t index)
: mIndex(index),
mParent(bitSetArray),
mCurrentParent(&mParent),
mCurrentIterator(mParent.mBaseBitSetArray[0].begin())
{
while (mIndex < mCurrentParent->kArraySize)
{
if (mCurrentParent->mBaseBitSetArray[mIndex].any())
{
break;
}
mIndex++;
}
if (mIndex < mCurrentParent->kArraySize)
{
mCurrentIterator = mCurrentParent->mBaseBitSetArray[mIndex].begin();
}
else
{
mCurrentIterator = mCurrentParent->mBaseBitSetArray[mCurrentParent->kArraySize - 1].end();
}
}
template <std::size_t N>
typename BitSetArray<N>::Iterator &BitSetArray<N>::Iterator::operator++()
{
++mCurrentIterator;
while (mCurrentIterator == mCurrentParent->mBaseBitSetArray[mIndex].end())
{
mIndex++;
if (mIndex >= mCurrentParent->kArraySize)
{
break;
}
mCurrentIterator = mCurrentParent->mBaseBitSetArray[mIndex].begin();
}
return *this;
}
template <std::size_t N>
bool BitSetArray<N>::Iterator::operator==(const BitSetArray<N>::Iterator &other) const
{
return mCurrentIterator == other.mCurrentIterator;
}
template <std::size_t N>
bool BitSetArray<N>::Iterator::operator!=(const BitSetArray<N>::Iterator &other) const
{
return mCurrentIterator != other.mCurrentIterator;
}
template <std::size_t N>
std::size_t BitSetArray<N>::Iterator::operator*() const
{
return (mIndex * priv::kDefaultBitSetSize) + *mCurrentIterator;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::operator&=(const BitSetArray<N> &other)
{
for (std::size_t index = 0; index < kArraySize; index++)
{
mBaseBitSetArray[index] &= other.mBaseBitSetArray[index];
}
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::operator|=(const BitSetArray<N> &other)
{
for (std::size_t index = 0; index < kArraySize; index++)
{
mBaseBitSetArray[index] |= other.mBaseBitSetArray[index];
}
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::operator^=(const BitSetArray<N> &other)
{
for (std::size_t index = 0; index < kArraySize; index++)
{
mBaseBitSetArray[index] ^= other.mBaseBitSetArray[index];
}
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> BitSetArray<N>::operator&(const angle::BitSetArray<N> &other) const
{
angle::BitSetArray<N> result(other);
result &= *this;
return result;
}
template <std::size_t N>
constexpr BitSetArray<N> BitSetArray<N>::operator|(const angle::BitSetArray<N> &other) const
{
angle::BitSetArray<N> result(other);
result |= *this;
return result;
}
template <std::size_t N>
constexpr BitSetArray<N> BitSetArray<N>::operator^(const angle::BitSetArray<N> &other) const
{
angle::BitSetArray<N> result(other);
result ^= *this;
return result;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::operator==(const angle::BitSetArray<N> &other) const
{
for (std::size_t index = 0; index < kArraySize; index++)
{
if (mBaseBitSetArray[index] != other.mBaseBitSetArray[index])
{
return false;
}
}
return true;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::operator!=(const angle::BitSetArray<N> &other) const
{
return !(*this == other);
}
template <std::size_t N>
constexpr BitSetArray<N> BitSetArray<N>::operator~() const
{
angle::BitSetArray<N> result;
for (std::size_t index = 0; index < kArraySize; index++)
{
result.mBaseBitSetArray[index] |= ~mBaseBitSetArray[index];
}
result.mBaseBitSetArray[kArraySize - 1] &= kLastElementMask;
return result;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::operator[](std::size_t pos) const
{
ASSERT(pos < size());
return test(pos);
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::set()
{
for (BaseBitSet &baseBitSet : mBaseBitSetArray)
{
baseBitSet.set();
}
mBaseBitSetArray[kArraySize - 1] &= kLastElementMask;
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::set(std::size_t pos, bool value)
{
ASSERT(pos < size());
size_t index = pos >> kShiftForDivision;
size_t offset = pos & kDefaultBitSetSizeMinusOne;
mBaseBitSetArray[index].set(offset, value);
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::reset()
{
for (BaseBitSet &baseBitSet : mBaseBitSetArray)
{
baseBitSet.reset();
}
return *this;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::reset(std::size_t pos)
{
ASSERT(pos < size());
return set(pos, false);
}
template <std::size_t N>
constexpr bool BitSetArray<N>::test(std::size_t pos) const
{
ASSERT(pos < size());
size_t index = pos >> kShiftForDivision;
size_t offset = pos & kDefaultBitSetSizeMinusOne;
return mBaseBitSetArray[index].test(offset);
}
template <std::size_t N>
constexpr bool BitSetArray<N>::all() const
{
constexpr priv::BaseBitSetType kLastElementBitSet = priv::BaseBitSetType(kLastElementMask);
for (std::size_t index = 0; index < kArraySize - 1; index++)
{
if (!mBaseBitSetArray[index].all())
{
return false;
}
}
return mBaseBitSetArray[kArraySize - 1] == kLastElementBitSet;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::any() const
{
for (const BaseBitSet &baseBitSet : mBaseBitSetArray)
{
if (baseBitSet.any())
{
return true;
}
}
return false;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::none() const
{
for (const BaseBitSet &baseBitSet : mBaseBitSetArray)
{
if (!baseBitSet.none())
{
return false;
}
}
return true;
}
template <std::size_t N>
constexpr std::size_t BitSetArray<N>::count() const
{
size_t count = 0;
for (const BaseBitSet &baseBitSet : mBaseBitSetArray)
{
count += baseBitSet.count();
}
return count;
}
template <std::size_t N>
constexpr bool BitSetArray<N>::intersects(const BitSetArray<N> &other) const
{
for (std::size_t index = 0; index < kArraySize; index++)
{
if ((mBaseBitSetArray[index].bits() & other.mBaseBitSetArray[index].bits()) != 0)
{
return true;
}
}
return false;
}
template <std::size_t N>
constexpr BitSetArray<N> &BitSetArray<N>::flip()
{
for (BaseBitSet &baseBitSet : mBaseBitSetArray)
{
baseBitSet.flip();
}
mBaseBitSetArray[kArraySize - 1] &= kLastElementMask;
return *this;
}
template <std::size_t N>
constexpr typename BitSetArray<N>::param_type BitSetArray<N>::first() const
{
ASSERT(any());
for (size_t arrayIndex = 0; arrayIndex < kArraySize; ++arrayIndex)
{
const BaseBitSet &baseBitSet = mBaseBitSetArray[arrayIndex];
if (baseBitSet.any())
{
return baseBitSet.first() + arrayIndex * priv::kDefaultBitSetSize;
}
}
UNREACHABLE();
return 0;
}
template <std::size_t N>
constexpr typename BitSetArray<N>::param_type BitSetArray<N>::last() const
{
ASSERT(any());
for (size_t arrayIndex = kArraySize; arrayIndex > 0; --arrayIndex)
{
const BaseBitSet &baseBitSet = mBaseBitSetArray[arrayIndex - 1];
if (baseBitSet.any())
{
return baseBitSet.last() + (arrayIndex - 1) * priv::kDefaultBitSetSize;
}
}
UNREACHABLE();
return 0;
}
template <std::size_t N>
constexpr typename BitSetArray<N>::value_type BitSetArray<N>::bits(size_t index) const
{
return mBaseBitSetArray[index].bits();
}
template <std::size_t N>
constexpr BitSetArray<N> BitSetArray<N>::Mask(std::size_t x)
{
BitSetArray result;
for (size_t arrayIndex = 0; arrayIndex < kArraySize; ++arrayIndex)
{
const size_t bitOffset = arrayIndex * priv::kDefaultBitSetSize;
if (x <= bitOffset)
{
break;
}
const size_t bitsInThisIndex = std::min(x - bitOffset, priv::kDefaultBitSetSize);
result.mBaseBitSetArray[arrayIndex] = BaseBitSet::Mask(bitsInThisIndex);
}
return result;
}
template <std::size_t N>
template <std::size_t BitSetSize, std::enable_if_t<(BitSetSize < 64), int>>
constexpr void BitSetArray<N>::initFromValue(uint64_t value)
{
static_assert(BitSetSize == 32, "Expected 32 bit size");
size_t i = 0;
for (; i < kArraySize - 1; ++i)
{
value_type elemValue = value & priv::BaseBitSetType::Mask(BitSetSize).bits();
mBaseBitSetArray[i] = priv::BaseBitSetType(elemValue);
value >>= BitSetSize;
}
value_type elemValue = value & kLastElementMask;
mBaseBitSetArray[i] = priv::BaseBitSetType(elemValue);
}
template <std::size_t N>
template <std::size_t BitSetSize, std::enable_if_t<(BitSetSize >= 64), int>>
constexpr void BitSetArray<N>::initFromValue(uint64_t value)
{
static_assert(BitSetSize == 64, "Expected 64 bit size");
value_type elemValue = value & priv::BaseBitSetType::Mask(BitSetSize).bits();
mBaseBitSetArray[0] = priv::BaseBitSetType(elemValue);
}
}
template <size_t N, typename BitsT, typename ParamT>
inline constexpr angle::BitSetT<N, BitsT, ParamT> operator&(
const angle::BitSetT<N, BitsT, ParamT> &lhs,
const angle::BitSetT<N, BitsT, ParamT> &rhs)
{
angle::BitSetT<N, BitsT, ParamT> result(lhs);
result &= rhs.bits();
return result;
}
template <size_t N, typename BitsT, typename ParamT>
inline constexpr angle::BitSetT<N, BitsT, ParamT> operator|(
const angle::BitSetT<N, BitsT, ParamT> &lhs,
const angle::BitSetT<N, BitsT, ParamT> &rhs)
{
angle::BitSetT<N, BitsT, ParamT> result(lhs);
result |= rhs.bits();
return result;
}
template <size_t N, typename BitsT, typename ParamT>
inline constexpr angle::BitSetT<N, BitsT, ParamT> operator^(
const angle::BitSetT<N, BitsT, ParamT> &lhs,
const angle::BitSetT<N, BitsT, ParamT> &rhs)
{
angle::BitSetT<N, BitsT, ParamT> result(lhs);
result ^= rhs.bits();
return result;
}
template <size_t N, typename BitsT, typename ParamT>
inline bool operator==(angle::BitSetT<N, BitsT, ParamT> &lhs, angle::BitSetT<N, BitsT, ParamT> &rhs)
{
return lhs.bits() == rhs.bits();
}
template <size_t N, typename BitsT, typename ParamT>
inline bool operator!=(angle::BitSetT<N, BitsT, ParamT> &lhs, angle::BitSetT<N, BitsT, ParamT> &rhs)
{
return !(lhs == rhs);
}
#endif