Jamie Madill | 6b2a0b0 | 2015-08-03 14:15:08 -0400 | [diff] [blame] | 1 | // |
| 2 | // Copyright 2015 The ANGLE Project Authors. All rights reserved. |
| 3 | // Use of this source code is governed by a BSD-style license that can be |
| 4 | // found in the LICENSE file. |
| 5 | // |
| 6 | // BitSetIterator: |
| 7 | // A helper class to quickly bitscan bitsets for set bits. |
| 8 | // |
| 9 | |
| 10 | #ifndef COMMON_BITSETITERATOR_H_ |
| 11 | #define COMMON_BITSETITERATOR_H_ |
| 12 | |
| 13 | #include <stdint.h> |
| 14 | |
| 15 | #include <bitset> |
| 16 | |
| 17 | #include "common/angleutils.h" |
| 18 | #include "common/debug.h" |
| 19 | #include "common/mathutil.h" |
| 20 | #include "common/platform.h" |
| 21 | |
| 22 | namespace angle |
| 23 | { |
| 24 | template <size_t N> |
| 25 | class BitSetIterator final |
| 26 | { |
| 27 | public: |
| 28 | BitSetIterator(const std::bitset<N> &bitset); |
| 29 | BitSetIterator(const BitSetIterator &other); |
| 30 | BitSetIterator &operator=(const BitSetIterator &other); |
| 31 | |
| 32 | class Iterator final |
| 33 | { |
| 34 | public: |
| 35 | Iterator(const std::bitset<N> &bits); |
| 36 | Iterator &operator++(); |
| 37 | |
| 38 | bool operator==(const Iterator &other) const; |
| 39 | bool operator!=(const Iterator &other) const; |
| 40 | unsigned long operator*() const { return mCurrentBit; } |
| 41 | |
| 42 | private: |
| 43 | unsigned long getNextBit(); |
| 44 | |
| 45 | static const size_t BitsPerWord = sizeof(unsigned long) * 8; |
| 46 | std::bitset<N> mBits; |
| 47 | unsigned long mCurrentBit; |
| 48 | unsigned long mOffset; |
| 49 | }; |
| 50 | |
| 51 | Iterator begin() const { return Iterator(mBits); } |
| 52 | Iterator end() const { return Iterator(std::bitset<N>(0)); } |
| 53 | |
| 54 | private: |
| 55 | const std::bitset<N> &mBits; |
| 56 | }; |
| 57 | |
| 58 | template <size_t N> |
| 59 | BitSetIterator<N>::BitSetIterator(const std::bitset<N> &bitset) |
| 60 | : mBits(bitset) |
| 61 | { |
| 62 | } |
| 63 | |
| 64 | template <size_t N> |
| 65 | BitSetIterator<N>::BitSetIterator(const BitSetIterator &other) |
| 66 | : mBits(other.mBits) |
| 67 | { |
| 68 | } |
| 69 | |
| 70 | template <size_t N> |
| 71 | BitSetIterator<N> &BitSetIterator<N>::operator=(const BitSetIterator &other) |
| 72 | { |
| 73 | mBits = other.mBits; |
| 74 | return *this; |
| 75 | } |
| 76 | |
| 77 | template <size_t N> |
| 78 | BitSetIterator<N>::Iterator::Iterator(const std::bitset<N> &bits) |
| 79 | : mBits(bits), mCurrentBit(0), mOffset(0) |
| 80 | { |
| 81 | if (bits.any()) |
| 82 | { |
| 83 | mCurrentBit = getNextBit(); |
| 84 | } |
| 85 | else |
| 86 | { |
| 87 | mOffset = rx::roundUp(N, BitsPerWord); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | template <size_t N> |
| 92 | typename BitSetIterator<N>::Iterator &BitSetIterator<N>::Iterator::operator++() |
| 93 | { |
| 94 | ASSERT(mBits.any()); |
| 95 | mBits.set(mCurrentBit - mOffset, 0); |
| 96 | mCurrentBit = getNextBit(); |
| 97 | return *this; |
| 98 | } |
| 99 | |
| 100 | inline unsigned long ScanForward(unsigned long bits) |
| 101 | { |
| 102 | ASSERT(bits != 0); |
| 103 | #if defined(ANGLE_PLATFORM_WINDOWS) |
| 104 | unsigned long firstBitIndex = 0ul; |
| 105 | unsigned char ret = _BitScanForward(&firstBitIndex, bits); |
| 106 | ASSERT(ret != 0); |
| 107 | UNUSED_ASSERTION_VARIABLE(ret); |
| 108 | return firstBitIndex; |
| 109 | #elif defined(ANGLE_PLATFORM_POSIX) |
| 110 | return static_cast<unsigned long>(__builtin_ctzl(bits)); |
| 111 | #else |
| 112 | #error Please implement bit-scan-forward for your platform! |
| 113 | #endif |
| 114 | } |
| 115 | |
| 116 | template <size_t N> |
| 117 | bool BitSetIterator<N>::Iterator::operator==(const Iterator &other) const |
| 118 | { |
| 119 | return mOffset == other.mOffset && mBits == other.mBits; |
| 120 | } |
| 121 | |
| 122 | template <size_t N> |
| 123 | bool BitSetIterator<N>::Iterator::operator!=(const Iterator &other) const |
| 124 | { |
| 125 | return !(*this == other); |
| 126 | } |
| 127 | |
| 128 | template <size_t N> |
| 129 | unsigned long BitSetIterator<N>::Iterator::getNextBit() |
| 130 | { |
| 131 | static std::bitset<N> wordMask(std::numeric_limits<unsigned long>::max()); |
| 132 | |
| 133 | while (mOffset < N) |
| 134 | { |
| 135 | unsigned long wordBits = (mBits & wordMask).to_ulong(); |
| 136 | if (wordBits != 0ul) |
| 137 | { |
| 138 | return ScanForward(wordBits) + mOffset; |
| 139 | } |
| 140 | |
| 141 | mBits >>= BitsPerWord; |
| 142 | mOffset += BitsPerWord; |
| 143 | } |
| 144 | return 0; |
| 145 | } |
| 146 | |
| 147 | // Helper to avoid needing to specify the template parameter size |
| 148 | template <size_t N> |
| 149 | BitSetIterator<N> IterateBitSet(const std::bitset<N> &bitset) |
| 150 | { |
| 151 | return BitSetIterator<N>(bitset); |
| 152 | } |
| 153 | |
| 154 | } // angle |
| 155 | |
| 156 | #endif // COMMON_BITSETITERATOR_H_ |