// Copyright 2017 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef COMMON_BITSETITERATOR_H_ #define COMMON_BITSETITERATOR_H_ #include "common/Assert.h" #include "common/Math.h" #include "common/UnderlyingType.h" #include #include // This is ANGLE's BitSetIterator class with a customizable return type // TODO(crbug.com/dawn/306): it could be optimized, in particular when N <= 64 template T roundUp(const T value, const T alignment) { auto temp = value + alignment - static_cast(1); return temp - temp % alignment; } 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; T operator*() const { using U = UnderlyingType; ASSERT(static_cast(mCurrentBit) <= std::numeric_limits::max()); return static_cast(static_cast(mCurrentBit)); } private: unsigned long getNextBit(); static constexpr size_t kBitsPerWord = sizeof(uint32_t) * 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(roundUp(N, kBitsPerWord)); } } template typename BitSetIterator::Iterator& BitSetIterator::Iterator::operator++() { DAWN_ASSERT(mBits.any()); mBits.set(mCurrentBit - mOffset, 0); mCurrentBit = getNextBit(); return *this; } 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) { uint32_t wordBits = static_cast((mBits & wordMask).to_ulong()); if (wordBits != 0ul) { return ScanForward(wordBits) + mOffset; } mBits >>= kBitsPerWord; mOffset += kBitsPerWord; } return 0; } // Helper to avoid needing to specify the template parameter size template BitSetIterator IterateBitSet(const std::bitset& bitset) { return BitSetIterator(bitset); } #endif // COMMON_BITSETITERATOR_H_