blob: 15d1ab279f4bdd2468cb4269d3d8d50088d0bfa2 [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() {}
Shao37219c82017-04-26 10:59:48 +080033 Reference &operator=(bool x)
34 {
35 mParent->set(mBit, x);
36 return *this;
37 }
Jamie Madill6de51852017-04-12 09:53:01 -040038 operator bool() const { return mParent->test(mBit); }
39
40 private:
41 friend class BitSetT;
42
43 Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {}
44
45 BitSetT *mParent;
46 std::size_t mBit;
47 };
48
49 class Iterator final
50 {
51 public:
52 Iterator(const BitSetT &bits);
53 Iterator &operator++();
54
55 bool operator==(const Iterator &other) const;
56 bool operator!=(const Iterator &other) const;
57 std::size_t operator*() const;
58
59 private:
60 std::size_t getNextBit();
61
62 BitSetT mBitsCopy;
63 std::size_t mCurrentBit;
64 };
65
66 BitSetT();
67 BitSetT(BitsT value);
68 ~BitSetT();
69
70 BitSetT(const BitSetT &other);
71 BitSetT &operator=(const BitSetT &other);
72
73 bool operator==(const BitSetT &other) const;
74 bool operator!=(const BitSetT &other) const;
75
76 constexpr bool operator[](std::size_t pos) const;
77 Reference operator[](std::size_t pos) { return Reference(this, pos); }
78
79 bool test(std::size_t pos) const;
80
81 bool all() const;
82 bool any() const;
83 bool none() const;
84 std::size_t count() const;
85
86 constexpr std::size_t size() const { return N; }
87
88 BitSetT &operator&=(const BitSetT &other);
89 BitSetT &operator|=(const BitSetT &other);
90 BitSetT &operator^=(const BitSetT &other);
91 BitSetT operator~() const;
92
93 BitSetT operator<<(std::size_t pos) const;
94 BitSetT &operator<<=(std::size_t pos);
95 BitSetT operator>>(std::size_t pos) const;
96 BitSetT &operator>>=(std::size_t pos);
97
98 BitSetT &set();
99 BitSetT &set(std::size_t pos, bool value = true);
100
101 BitSetT &reset();
102 BitSetT &reset(std::size_t pos);
103
104 BitSetT &flip();
105 BitSetT &flip(std::size_t pos);
106
107 unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
108 BitsT bits() const { return mBits; }
109
110 Iterator begin() const { return Iterator(*this); }
111 Iterator end() const { return Iterator(BitSetT()); }
112
113 private:
114 constexpr static BitsT Bit(std::size_t x) { return (static_cast<BitsT>(1) << x); }
115 constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
116
117 BitsT mBits;
118};
119
120template <size_t N>
121class IterableBitSet : public std::bitset<N>
122{
123 public:
124 IterableBitSet() {}
125 IterableBitSet(const std::bitset<N> &implicitBitSet) : std::bitset<N>(implicitBitSet) {}
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400126
127 class Iterator final
128 {
129 public:
130 Iterator(const std::bitset<N> &bits);
131 Iterator &operator++();
132
133 bool operator==(const Iterator &other) const;
134 bool operator!=(const Iterator &other) const;
135 unsigned long operator*() const { return mCurrentBit; }
136
137 private:
138 unsigned long getNextBit();
139
Jamie Madill6de51852017-04-12 09:53:01 -0400140 static constexpr size_t BitsPerWord = sizeof(uint32_t) * 8;
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400141 std::bitset<N> mBits;
142 unsigned long mCurrentBit;
143 unsigned long mOffset;
144 };
145
Jamie Madill6de51852017-04-12 09:53:01 -0400146 Iterator begin() const { return Iterator(*this); }
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400147 Iterator end() const { return Iterator(std::bitset<N>(0)); }
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400148};
149
150template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400151IterableBitSet<N>::Iterator::Iterator(const std::bitset<N> &bitset)
152 : mBits(bitset), mCurrentBit(0), mOffset(0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400153{
Jamie Madill6de51852017-04-12 09:53:01 -0400154 if (mBits.any())
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400155 {
156 mCurrentBit = getNextBit();
157 }
158 else
159 {
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700160 mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400161 }
162}
163
164template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400165typename IterableBitSet<N>::Iterator &IterableBitSet<N>::Iterator::operator++()
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400166{
167 ASSERT(mBits.any());
168 mBits.set(mCurrentBit - mOffset, 0);
169 mCurrentBit = getNextBit();
170 return *this;
171}
172
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400173template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400174bool IterableBitSet<N>::Iterator::operator==(const Iterator &other) const
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400175{
176 return mOffset == other.mOffset && mBits == other.mBits;
177}
178
179template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400180bool IterableBitSet<N>::Iterator::operator!=(const Iterator &other) const
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400181{
182 return !(*this == other);
183}
184
185template <size_t N>
Jamie Madill6de51852017-04-12 09:53:01 -0400186unsigned long IterableBitSet<N>::Iterator::getNextBit()
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400187{
Jamie Madill6de51852017-04-12 09:53:01 -0400188 // TODO(jmadill): Use 64-bit scan when possible.
189 static constexpr std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400190
191 while (mOffset < N)
192 {
Jamie Madill6de51852017-04-12 09:53:01 -0400193 uint32_t wordBits = static_cast<uint32_t>((mBits & wordMask).to_ulong());
194 if (wordBits != 0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400195 {
Olli Etuaho9250cb22017-01-21 10:51:27 +0000196 return gl::ScanForward(wordBits) + mOffset;
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400197 }
198
199 mBits >>= BitsPerWord;
200 mOffset += BitsPerWord;
201 }
202 return 0;
203}
204
Jamie Madill6de51852017-04-12 09:53:01 -0400205template <size_t N, typename BitsT>
206BitSetT<N, BitsT>::BitSetT() : mBits(0)
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400207{
Jamie Madill6de51852017-04-12 09:53:01 -0400208 static_assert(N > 0, "Bitset type cannot support zero bits.");
209 static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400210}
211
Jamie Madill6de51852017-04-12 09:53:01 -0400212template <size_t N, typename BitsT>
213BitSetT<N, BitsT>::BitSetT(BitsT value) : mBits(value & Mask(N))
214{
215}
216
217template <size_t N, typename BitsT>
218BitSetT<N, BitsT>::~BitSetT()
219{
220}
221
222template <size_t N, typename BitsT>
223BitSetT<N, BitsT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
224{
225}
226
227template <size_t N, typename BitsT>
228BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator=(const BitSetT &other)
229{
230 mBits = other.mBits;
231 return *this;
232}
233
234template <size_t N, typename BitsT>
235bool BitSetT<N, BitsT>::operator==(const BitSetT &other) const
236{
237 return mBits == other.mBits;
238}
239
240template <size_t N, typename BitsT>
241bool BitSetT<N, BitsT>::operator!=(const BitSetT &other) const
242{
243 return mBits != other.mBits;
244}
245
246template <size_t N, typename BitsT>
247constexpr bool BitSetT<N, BitsT>::operator[](std::size_t pos) const
248{
249 return test(pos);
250}
251
252template <size_t N, typename BitsT>
253bool BitSetT<N, BitsT>::test(std::size_t pos) const
254{
255 return (mBits & Bit(pos)) != 0;
256}
257
258template <size_t N, typename BitsT>
259bool BitSetT<N, BitsT>::all() const
260{
261 ASSERT(mBits == (mBits & Mask(N)));
262 return mBits == Mask(N);
263}
264
265template <size_t N, typename BitsT>
266bool BitSetT<N, BitsT>::any() const
267{
268 ASSERT(mBits == (mBits & Mask(N)));
269 return (mBits != 0);
270}
271
272template <size_t N, typename BitsT>
273bool BitSetT<N, BitsT>::none() const
274{
275 ASSERT(mBits == (mBits & Mask(N)));
276 return (mBits == 0);
277}
278
279template <size_t N, typename BitsT>
280std::size_t BitSetT<N, BitsT>::count() const
281{
282 return gl::BitCount(mBits);
283}
284
285template <size_t N, typename BitsT>
286BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator&=(const BitSetT &other)
287{
288 mBits &= other.mBits;
289 return *this;
290}
291
292template <size_t N, typename BitsT>
293BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator|=(const BitSetT &other)
294{
295 mBits |= other.mBits;
296 return *this;
297}
298
299template <size_t N, typename BitsT>
300BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator^=(const BitSetT &other)
301{
302 mBits = (mBits ^ other.mBits) & Mask(N);
303 return *this;
304}
305
306template <size_t N, typename BitsT>
307BitSetT<N, BitsT> BitSetT<N, BitsT>::operator~() const
308{
309 return BitSetT<N, BitsT>(~mBits & Mask(N));
310}
311
312template <size_t N, typename BitsT>
313BitSetT<N, BitsT> BitSetT<N, BitsT>::operator<<(std::size_t pos) const
314{
315 return BitSetT<N, BitsT>((mBits << pos) & Mask(N));
316}
317
318template <size_t N, typename BitsT>
319BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator<<=(std::size_t pos)
320{
321 mBits = (mBits << pos & Mask(N));
322 return *this;
323}
324
325template <size_t N, typename BitsT>
326BitSetT<N, BitsT> BitSetT<N, BitsT>::operator>>(std::size_t pos) const
327{
328 return BitSetT<N, BitsT>(mBits >> pos);
329}
330
331template <size_t N, typename BitsT>
332BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator>>=(std::size_t pos)
333{
334 mBits = ((mBits >> pos) & Mask(N));
335 return *this;
336}
337
338template <size_t N, typename BitsT>
339BitSetT<N, BitsT> &BitSetT<N, BitsT>::set()
340{
341 mBits = Mask(N);
342 return *this;
343}
344
345template <size_t N, typename BitsT>
346BitSetT<N, BitsT> &BitSetT<N, BitsT>::set(std::size_t pos, bool value)
347{
348 if (value)
349 {
350 mBits |= Bit(pos);
351 }
352 else
353 {
354 reset(pos);
355 }
356 return *this;
357}
358
359template <size_t N, typename BitsT>
360BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset()
361{
362 mBits = 0;
363 return *this;
364}
365
366template <size_t N, typename BitsT>
367BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset(std::size_t pos)
368{
369 mBits &= ~Bit(pos);
370 return *this;
371}
372
373template <size_t N, typename BitsT>
374BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip()
375{
376 mBits ^= Mask(N);
377 return *this;
378}
379
380template <size_t N, typename BitsT>
381BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip(std::size_t pos)
382{
383 mBits ^= Bit(pos);
384 return *this;
385}
386
387template <size_t N, typename BitsT>
388BitSetT<N, BitsT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
389{
390 if (bits.any())
391 {
392 mCurrentBit = getNextBit();
393 }
394}
395
396template <size_t N, typename BitsT>
397typename BitSetT<N, BitsT>::Iterator &BitSetT<N, BitsT>::Iterator::operator++()
398{
399 ASSERT(mBitsCopy.any());
400 mBitsCopy.reset(mCurrentBit);
401 mCurrentBit = getNextBit();
402 return *this;
403}
404
405template <size_t N, typename BitsT>
406bool BitSetT<N, BitsT>::Iterator::operator==(const Iterator &other) const
407{
408 return mBitsCopy == other.mBitsCopy;
409}
410
411template <size_t N, typename BitsT>
412bool BitSetT<N, BitsT>::Iterator::operator!=(const Iterator &other) const
413{
414 return !(*this == other);
415}
416
417template <size_t N, typename BitsT>
418std::size_t BitSetT<N, BitsT>::Iterator::operator*() const
419{
420 return mCurrentBit;
421}
422
423template <size_t N, typename BitsT>
424std::size_t BitSetT<N, BitsT>::Iterator::getNextBit()
425{
426 if (mBitsCopy.none())
427 {
428 return 0;
429 }
430
431 return gl::ScanForward(mBitsCopy.mBits);
432}
433
434template <size_t N>
435using BitSet32 = BitSetT<N, uint32_t>;
436
437// ScanForward for 64-bits requires a 64-bit implementation.
Yuly Novikovc4f1dd82017-10-25 17:02:29 -0400438#if defined(ANGLE_IS_64_BIT_CPU)
Jamie Madill6de51852017-04-12 09:53:01 -0400439template <size_t N>
440using BitSet64 = BitSetT<N, uint64_t>;
Yuly Novikovc4f1dd82017-10-25 17:02:29 -0400441#endif // defined(ANGLE_IS_64_BIT_CPU)
Jamie Madill6de51852017-04-12 09:53:01 -0400442
443namespace priv
444{
445
446template <size_t N, typename T>
447using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
448
449template <size_t N, typename Enable = void>
450struct GetBitSet
451{
452 using Type = IterableBitSet<N>;
453};
454
455// Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit.
Yuly Novikovc4f1dd82017-10-25 17:02:29 -0400456#if defined(ANGLE_IS_64_BIT_CPU)
Jamie Madill6de51852017-04-12 09:53:01 -0400457template <size_t N>
458struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
459{
460 using Type = BitSet64<N>;
461};
462#else
463template <size_t N>
464struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
465{
466 using Type = BitSet32<N>;
467};
Yuly Novikovc4f1dd82017-10-25 17:02:29 -0400468#endif // defined(ANGLE_IS_64_BIT_CPU)
Jamie Madill6de51852017-04-12 09:53:01 -0400469
470} // namespace priv
471
472template <size_t N>
473using BitSet = typename priv::GetBitSet<N>::Type;
474
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400475} // angle
476
Jamie Madill6de51852017-04-12 09:53:01 -0400477template <size_t N, typename BitsT>
478inline angle::BitSetT<N, BitsT> operator&(const angle::BitSetT<N, BitsT> &lhs,
479 const angle::BitSetT<N, BitsT> &rhs)
480{
481 return angle::BitSetT<N, BitsT>(lhs.bits() & rhs.bits());
482}
483
484template <size_t N, typename BitsT>
485inline angle::BitSetT<N, BitsT> operator|(const angle::BitSetT<N, BitsT> &lhs,
486 const angle::BitSetT<N, BitsT> &rhs)
487{
488 return angle::BitSetT<N, BitsT>(lhs.bits() | rhs.bits());
489}
490
491template <size_t N, typename BitsT>
492inline angle::BitSetT<N, BitsT> operator^(const angle::BitSetT<N, BitsT> &lhs,
493 const angle::BitSetT<N, BitsT> &rhs)
494{
495 return angle::BitSetT<N, BitsT>(lhs.bits() ^ rhs.bits());
496}
497
Jamie Madill6b2a0b02015-08-03 14:15:08 -0400498#endif // COMMON_BITSETITERATOR_H_