blob: d0cc7c0732bc0fadee2b204dbaf5b579a0c66573 [file] [log] [blame]
Jamie Madill6b2a0b02015-08-03 14:15:08 -04001//
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
22namespace angle
23{
24template <size_t N>
25class 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
58template <size_t N>
59BitSetIterator<N>::BitSetIterator(const std::bitset<N> &bitset)
60 : mBits(bitset)
61{
62}
63
64template <size_t N>
65BitSetIterator<N>::BitSetIterator(const BitSetIterator &other)
66 : mBits(other.mBits)
67{
68}
69
70template <size_t N>
71BitSetIterator<N> &BitSetIterator<N>::operator=(const BitSetIterator &other)
72{
73 mBits = other.mBits;
74 return *this;
75}
76
77template <size_t N>
78BitSetIterator<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 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -070087 mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
Jamie Madill6b2a0b02015-08-03 14:15:08 -040088 }
89}
90
91template <size_t N>
92typename 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
100inline 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
116template <size_t N>
117bool BitSetIterator<N>::Iterator::operator==(const Iterator &other) const
118{
119 return mOffset == other.mOffset && mBits == other.mBits;
120}
121
122template <size_t N>
123bool BitSetIterator<N>::Iterator::operator!=(const Iterator &other) const
124{
125 return !(*this == other);
126}
127
128template <size_t N>
129unsigned 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
148template <size_t N>
149BitSetIterator<N> IterateBitSet(const std::bitset<N> &bitset)
150{
151 return BitSetIterator<N>(bitset);
152}
153
154} // angle
155
156#endif // COMMON_BITSETITERATOR_H_