// // Copyright 2015 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // BitSetIterator: // A helper class to quickly bitscan bitsets for set bits. // #ifndef COMMON_BITSETITERATOR_H_ #define COMMON_BITSETITERATOR_H_ #include #include #include "common/angleutils.h" #include "common/debug.h" #include "common/mathutil.h" #include "common/platform.h" namespace angle { template class BitSetIterator final { public: BitSetIterator(const std::bitset &bitset); BitSetIterator(const BitSetIterator &other); BitSetIterator &operator=(const BitSetIterator &other); class Iterator final { public: Iterator(const std::bitset &bits); Iterator &operator++(); bool operator==(const Iterator &other) const; bool operator!=(const Iterator &other) const; unsigned long operator*() const { return mCurrentBit; } private: unsigned long getNextBit(); static const size_t BitsPerWord = sizeof(unsigned long) * 8; std::bitset mBits; unsigned long mCurrentBit; unsigned long mOffset; }; Iterator begin() const { return Iterator(mBits); } Iterator end() const { return Iterator(std::bitset(0)); } private: const std::bitset mBits; }; template BitSetIterator::BitSetIterator(const std::bitset &bitset) : mBits(bitset) { } template BitSetIterator::BitSetIterator(const BitSetIterator &other) : mBits(other.mBits) { } template BitSetIterator &BitSetIterator::operator=(const BitSetIterator &other) { mBits = other.mBits; return *this; } template BitSetIterator::Iterator::Iterator(const std::bitset &bits) : mBits(bits), mCurrentBit(0), mOffset(0) { if (bits.any()) { mCurrentBit = getNextBit(); } else { mOffset = static_cast(rx::roundUp(N, BitsPerWord)); } } template typename BitSetIterator::Iterator &BitSetIterator::Iterator::operator++() { ASSERT(mBits.any()); mBits.set(mCurrentBit - mOffset, 0); mCurrentBit = getNextBit(); return *this; } inline unsigned long ScanForward(unsigned long bits) { ASSERT(bits != 0); #if defined(ANGLE_PLATFORM_WINDOWS) unsigned long firstBitIndex = 0ul; unsigned char ret = _BitScanForward(&firstBitIndex, bits); ASSERT(ret != 0); UNUSED_ASSERTION_VARIABLE(ret); return firstBitIndex; #elif defined(ANGLE_PLATFORM_POSIX) return static_cast(__builtin_ctzl(bits)); #else #error Please implement bit-scan-forward for your platform! #endif } template bool BitSetIterator::Iterator::operator==(const Iterator &other) const { return mOffset == other.mOffset && mBits == other.mBits; } template bool BitSetIterator::Iterator::operator!=(const Iterator &other) const { return !(*this == other); } template unsigned long BitSetIterator::Iterator::getNextBit() { static std::bitset wordMask(std::numeric_limits::max()); while (mOffset < N) { unsigned long wordBits = (mBits & wordMask).to_ulong(); if (wordBits != 0ul) { return ScanForward(wordBits) + mOffset; } mBits >>= BitsPerWord; mOffset += BitsPerWord; } return 0; } // Helper to avoid needing to specify the template parameter size template BitSetIterator IterateBitSet(const std::bitset &bitset) { return BitSetIterator(bitset); } } // angle #endif // COMMON_BITSETITERATOR_H_