blob: 14b050d836d120ac1861b97463ddec9b83c2c018 [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//
Jamie Madill20e005b2017-04-07 14:19:22 -04006// bitset_utils:
7// Bitset-related helper classes, such as a fast iterator to scan for set bits.
Jamie Madill6b2a0b02015-08-03 14:15:08 -04008//
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{
Jamie Madill6de51852017-04-12 09:53:01 -040024
25template <size_t N, typename BitsT>
26class BitSetT final
Jamie Madill6b2a0b02015-08-03 14:15:08 -040027{
28 public:
Jamie Madill6de51852017-04-12 09:53:01 -040029 class Reference final
30 {
31 public:
32 ~Reference() {}
33 Reference &operator=(bool x) { mParent->set(mBit, x); }
34 operator bool() const { return mParent->test(mBit); }
35
36 private:
37 friend class BitSetT;
38
39 Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {}
40
41 BitSetT *mParent;
42 std::size_t mBit;
43 };
44
45 class Iterator final
46 {
47 public:
48 Iterator(const BitSetT &bits);
49 Iterator &operator++();
50
51 bool operator==(const Iterator &other) const;
52 bool operator!=(const Iterator &other) const;
53 std::size_t operator*() const;
54
55 private:
56 std::size_t getNextBit();
57
58 BitSetT mBitsCopy;
59 std::size_t mCurrentBit;
60 };
61
62 BitSetT();
63 BitSetT(BitsT value);
64 ~BitSetT();
65
66 BitSetT(const BitSetT &other);
67 BitSetT &operator=(const BitSetT &other);
68
69 bool operator==(const BitSetT &other) const;
70 bool operator!=(const BitSetT &other) const;
71
72 constexpr bool operator[](std::size_t pos) const;
73 Reference operator[](std::size_t pos) { return Reference(this, pos); }
74
75 bool test(std::size_t pos) const;
76
77 bool all() const;
78 bool any() const;
79 bool none() const;
80 std::size_t count() const;
81
82 constexpr std::size_t size() const { return N; }
83
84 BitSetT &operator&=(const BitSetT &other);
85 BitSetT &operator|=(const BitSetT &other);
86 BitSetT &operator^=(const BitSetT &other);
87 BitSetT operator~() const;
88
89 BitSetT operator<<(std::size_t pos) const;
90 BitSetT &operator<<=(std::size_t pos);
91 BitSetT operator>>(std::size_t pos) const;
92 BitSetT &operator>>=(std::size_t pos);
93
94 BitSetT &set();
95 BitSetT &set(std::size_t pos, bool value = true);
96
97 BitSetT &reset();
98 BitSetT &reset(std::size_t pos);
99
100 BitSetT &flip();
101 BitSetT &flip(std::size_t pos);
102
103 unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
104 BitsT bits() const { return mBits; }
105
106 Iterator begin() const { return Iterator(*this); }
107 Iterator end() const { return Iterator(BitSetT()); }
108
109 private:
110 constexpr static BitsT Bit(std::size_t x) { return (static_cast<BitsT>(1) << x); }
111 constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
112
113 BitsT mBits;
114};
115
116template <size_t N>
117class IterableBitSet : public std::bitset<N>
118{
119 public:
120 IterableBitSet() {}
121 IterableBitSet(const std::bitset<N> &implicitBitSet) : std::bitset<N>(implicitBitSet) {}
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400122
123 class Iterator final
124 {
125 public:
126 Iterator(const std::bitset<N> &bits);
127 Iterator &operator++();
128
129 bool operator==(const Iterator &other) const;
130 bool operator!=(const Iterator &other) const;
131 unsigned long operator*() const { return mCurrentBit; }
132
133 private:
134 unsigned long getNextBit();
135
Jamie Madill6de51852017-04-12 09:53:01 -0400136 static constexpr size_t BitsPerWord = sizeof(uint32_t) * 8;
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400137 std::bitset<N> mBits;
138 unsigned long mCurrentBit;
139 unsigned long mOffset;
140 };
141
Jamie Madill6de51852017-04-12 09:53:01 -0400142 Iterator begin() const { return Iterator(*this); }
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400143 Iterator end() const { return Iterator(std::bitset<N>(0)); }
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400144};
145
146template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400147IterableBitSet<N>::Iterator::Iterator(const std::bitset<N> &bitset)
148 : mBits(bitset), mCurrentBit(0), mOffset(0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400149{
Jamie Madill6de51852017-04-12 09:53:01 -0400150 if (mBits.any())
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400151 {
152 mCurrentBit = getNextBit();
153 }
154 else
155 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700156 mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400157 }
158}
159
160template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400161typename IterableBitSet<N>::Iterator &IterableBitSet<N>::Iterator::operator++()
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400162{
163 ASSERT(mBits.any());
164 mBits.set(mCurrentBit - mOffset, 0);
165 mCurrentBit = getNextBit();
166 return *this;
167}
168
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400169template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400170bool IterableBitSet<N>::Iterator::operator==(const Iterator &other) const
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400171{
172 return mOffset == other.mOffset && mBits == other.mBits;
173}
174
175template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400176bool IterableBitSet<N>::Iterator::operator!=(const Iterator &other) const
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400177{
178 return !(*this == other);
179}
180
181template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400182unsigned long IterableBitSet<N>::Iterator::getNextBit()
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400183{
Jamie Madill6de51852017-04-12 09:53:01 -0400184 // TODO(jmadill): Use 64-bit scan when possible.
185 static constexpr std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400186
187 while (mOffset < N)
188 {
Jamie Madill6de51852017-04-12 09:53:01 -0400189 uint32_t wordBits = static_cast<uint32_t>((mBits & wordMask).to_ulong());
190 if (wordBits != 0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400191 {
Olli Etuaho9250cb22017-01-21 10:51:27 +0000192 return gl::ScanForward(wordBits) + mOffset;
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400193 }
194
195 mBits >>= BitsPerWord;
196 mOffset += BitsPerWord;
197 }
198 return 0;
199}
200
Jamie Madill6de51852017-04-12 09:53:01 -0400201template <size_t N, typename BitsT>
202BitSetT<N, BitsT>::BitSetT() : mBits(0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400203{
Jamie Madill6de51852017-04-12 09:53:01 -0400204 static_assert(N > 0, "Bitset type cannot support zero bits.");
205 static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400206}
207
Jamie Madill6de51852017-04-12 09:53:01 -0400208template <size_t N, typename BitsT>
209BitSetT<N, BitsT>::BitSetT(BitsT value) : mBits(value & Mask(N))
210{
211}
212
213template <size_t N, typename BitsT>
214BitSetT<N, BitsT>::~BitSetT()
215{
216}
217
218template <size_t N, typename BitsT>
219BitSetT<N, BitsT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
220{
221}
222
223template <size_t N, typename BitsT>
224BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator=(const BitSetT &other)
225{
226 mBits = other.mBits;
227 return *this;
228}
229
230template <size_t N, typename BitsT>
231bool BitSetT<N, BitsT>::operator==(const BitSetT &other) const
232{
233 return mBits == other.mBits;
234}
235
236template <size_t N, typename BitsT>
237bool BitSetT<N, BitsT>::operator!=(const BitSetT &other) const
238{
239 return mBits != other.mBits;
240}
241
242template <size_t N, typename BitsT>
243constexpr bool BitSetT<N, BitsT>::operator[](std::size_t pos) const
244{
245 return test(pos);
246}
247
248template <size_t N, typename BitsT>
249bool BitSetT<N, BitsT>::test(std::size_t pos) const
250{
251 return (mBits & Bit(pos)) != 0;
252}
253
254template <size_t N, typename BitsT>
255bool BitSetT<N, BitsT>::all() const
256{
257 ASSERT(mBits == (mBits & Mask(N)));
258 return mBits == Mask(N);
259}
260
261template <size_t N, typename BitsT>
262bool BitSetT<N, BitsT>::any() const
263{
264 ASSERT(mBits == (mBits & Mask(N)));
265 return (mBits != 0);
266}
267
268template <size_t N, typename BitsT>
269bool BitSetT<N, BitsT>::none() const
270{
271 ASSERT(mBits == (mBits & Mask(N)));
272 return (mBits == 0);
273}
274
275template <size_t N, typename BitsT>
276std::size_t BitSetT<N, BitsT>::count() const
277{
278 return gl::BitCount(mBits);
279}
280
281template <size_t N, typename BitsT>
282BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator&=(const BitSetT &other)
283{
284 mBits &= other.mBits;
285 return *this;
286}
287
288template <size_t N, typename BitsT>
289BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator|=(const BitSetT &other)
290{
291 mBits |= other.mBits;
292 return *this;
293}
294
295template <size_t N, typename BitsT>
296BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator^=(const BitSetT &other)
297{
298 mBits = (mBits ^ other.mBits) & Mask(N);
299 return *this;
300}
301
302template <size_t N, typename BitsT>
303BitSetT<N, BitsT> BitSetT<N, BitsT>::operator~() const
304{
305 return BitSetT<N, BitsT>(~mBits & Mask(N));
306}
307
308template <size_t N, typename BitsT>
309BitSetT<N, BitsT> BitSetT<N, BitsT>::operator<<(std::size_t pos) const
310{
311 return BitSetT<N, BitsT>((mBits << pos) & Mask(N));
312}
313
314template <size_t N, typename BitsT>
315BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator<<=(std::size_t pos)
316{
317 mBits = (mBits << pos & Mask(N));
318 return *this;
319}
320
321template <size_t N, typename BitsT>
322BitSetT<N, BitsT> BitSetT<N, BitsT>::operator>>(std::size_t pos) const
323{
324 return BitSetT<N, BitsT>(mBits >> pos);
325}
326
327template <size_t N, typename BitsT>
328BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator>>=(std::size_t pos)
329{
330 mBits = ((mBits >> pos) & Mask(N));
331 return *this;
332}
333
334template <size_t N, typename BitsT>
335BitSetT<N, BitsT> &BitSetT<N, BitsT>::set()
336{
337 mBits = Mask(N);
338 return *this;
339}
340
341template <size_t N, typename BitsT>
342BitSetT<N, BitsT> &BitSetT<N, BitsT>::set(std::size_t pos, bool value)
343{
344 if (value)
345 {
346 mBits |= Bit(pos);
347 }
348 else
349 {
350 reset(pos);
351 }
352 return *this;
353}
354
355template <size_t N, typename BitsT>
356BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset()
357{
358 mBits = 0;
359 return *this;
360}
361
362template <size_t N, typename BitsT>
363BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset(std::size_t pos)
364{
365 mBits &= ~Bit(pos);
366 return *this;
367}
368
369template <size_t N, typename BitsT>
370BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip()
371{
372 mBits ^= Mask(N);
373 return *this;
374}
375
376template <size_t N, typename BitsT>
377BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip(std::size_t pos)
378{
379 mBits ^= Bit(pos);
380 return *this;
381}
382
383template <size_t N, typename BitsT>
384BitSetT<N, BitsT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
385{
386 if (bits.any())
387 {
388 mCurrentBit = getNextBit();
389 }
390}
391
392template <size_t N, typename BitsT>
393typename BitSetT<N, BitsT>::Iterator &BitSetT<N, BitsT>::Iterator::operator++()
394{
395 ASSERT(mBitsCopy.any());
396 mBitsCopy.reset(mCurrentBit);
397 mCurrentBit = getNextBit();
398 return *this;
399}
400
401template <size_t N, typename BitsT>
402bool BitSetT<N, BitsT>::Iterator::operator==(const Iterator &other) const
403{
404 return mBitsCopy == other.mBitsCopy;
405}
406
407template <size_t N, typename BitsT>
408bool BitSetT<N, BitsT>::Iterator::operator!=(const Iterator &other) const
409{
410 return !(*this == other);
411}
412
413template <size_t N, typename BitsT>
414std::size_t BitSetT<N, BitsT>::Iterator::operator*() const
415{
416 return mCurrentBit;
417}
418
419template <size_t N, typename BitsT>
420std::size_t BitSetT<N, BitsT>::Iterator::getNextBit()
421{
422 if (mBitsCopy.none())
423 {
424 return 0;
425 }
426
427 return gl::ScanForward(mBitsCopy.mBits);
428}
429
430template <size_t N>
431using BitSet32 = BitSetT<N, uint32_t>;
432
433// ScanForward for 64-bits requires a 64-bit implementation.
434#if defined(ANGLE_X64_CPU)
435template <size_t N>
436using BitSet64 = BitSetT<N, uint64_t>;
437#endif // defined(ANGLE_X64_CPU)
438
439namespace priv
440{
441
442template <size_t N, typename T>
443using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
444
445template <size_t N, typename Enable = void>
446struct GetBitSet
447{
448 using Type = IterableBitSet<N>;
449};
450
451// Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit.
452#if defined(ANGLE_X64_CPU)
453template <size_t N>
454struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
455{
456 using Type = BitSet64<N>;
457};
458#else
459template <size_t N>
460struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
461{
462 using Type = BitSet32<N>;
463};
464#endif // defined(ANGLE_X64_CPU)
465
466} // namespace priv
467
468template <size_t N>
469using BitSet = typename priv::GetBitSet<N>::Type;
470
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400471} // angle
472
Jamie Madill6de51852017-04-12 09:53:01 -0400473template <size_t N, typename BitsT>
474inline angle::BitSetT<N, BitsT> operator&(const angle::BitSetT<N, BitsT> &lhs,
475 const angle::BitSetT<N, BitsT> &rhs)
476{
477 return angle::BitSetT<N, BitsT>(lhs.bits() & rhs.bits());
478}
479
480template <size_t N, typename BitsT>
481inline angle::BitSetT<N, BitsT> operator|(const angle::BitSetT<N, BitsT> &lhs,
482 const angle::BitSetT<N, BitsT> &rhs)
483{
484 return angle::BitSetT<N, BitsT>(lhs.bits() | rhs.bits());
485}
486
487template <size_t N, typename BitsT>
488inline angle::BitSetT<N, BitsT> operator^(const angle::BitSetT<N, BitsT> &lhs,
489 const angle::BitSetT<N, BitsT> &rhs)
490{
491 return angle::BitSetT<N, BitsT>(lhs.bits() ^ rhs.bits());
492}
493
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400494#endif // COMMON_BITSETITERATOR_H_