Branch data Line data Source code
1 : : // Copyright (c) The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_UTIL_BITSET_H
6 : : #define BITCOIN_UTIL_BITSET_H
7 : :
8 : : #include <util/check.h>
9 : :
10 : : #include <array>
11 : : #include <bit>
12 : : #include <cstdint>
13 : : #include <limits>
14 : : #include <type_traits>
15 : :
16 : : /* This file provides data types similar to std::bitset, but adds the following functionality:
17 : : *
18 : : * - Efficient iteration over all set bits (compatible with range-based for loops).
19 : : * - Efficient search for the first and last set bit (First() and Last()).
20 : : * - Efficient set subtraction: (a - b) implements "a and not b".
21 : : * - Efficient non-strict subset/superset testing: IsSubsetOf() and IsSupersetOf().
22 : : * - Efficient set overlap testing: a.Overlaps(b)
23 : : * - Efficient construction of set containing 0..N-1 (S::Fill).
24 : : * - Efficient construction of a single set (S::Singleton).
25 : : * - Construction from initializer lists.
26 : : *
27 : : * Other differences:
28 : : * - BitSet<N> is a bitset that supports at least N elements, but may support more (Size() reports
29 : : * the actual number). Because the actual number is unpredictable, there are no operations that
30 : : * affect all positions (like std::bitset's operator~, flip(), or all()).
31 : : * - Various other unimplemented features.
32 : : */
33 : :
34 : : namespace bitset_detail {
35 : :
36 : : /** Count the number of bits set in an unsigned integer type. */
37 : : template<typename I>
38 : 119 : unsigned inline constexpr PopCount(I v)
39 : : {
40 : : static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2);
41 : 119 : constexpr auto BITS = std::numeric_limits<I>::digits;
42 : : // Algorithms from https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation.
43 : : // These seem to be faster than std::popcount when compiling for non-SSE4 on x86_64.
44 : : if constexpr (BITS <= 32) {
45 : 119 : v -= (v >> 1) & 0x55555555;
46 : 119 : v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
47 : 119 : v = (v + (v >> 4)) & 0x0f0f0f0f;
48 : 119 : if constexpr (BITS > 8) v += v >> 8;
49 : 119 : if constexpr (BITS > 16) v += v >> 16;
50 : 119 : return v & 0x3f;
51 : : } else {
52 : : static_assert(BITS <= 64);
53 : : v -= (v >> 1) & 0x5555555555555555;
54 : : v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333);
55 : : v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f;
56 : : return (v * uint64_t{0x0101010101010101}) >> 56;
57 : : }
58 : : }
59 : :
60 : : /** A bitset implementation backed by a single integer of type I. */
61 : : template<typename I>
62 : : class IntBitSet
63 : : {
64 : : // Only binary, unsigned, integer, types allowed.
65 : : static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2);
66 : : /** The maximum number of bits this bitset supports. */
67 : : static constexpr unsigned MAX_SIZE = std::numeric_limits<I>::digits;
68 : : /** Integer whose bits represent this bitset. */
69 : 56 : I m_val;
70 : : /** Internal constructor with a given integer as contents. */
71 : 293 : IntBitSet(I val) noexcept : m_val{val} {}
72 : : /** Dummy type to return using end(). Only used for comparing with Iterator. */
73 : : class IteratorEnd
74 : : {
75 : : friend class IntBitSet;
76 : : constexpr IteratorEnd() = default;
77 : : public:
78 : : constexpr IteratorEnd(const IteratorEnd&) = default;
79 : : };
80 : : /** Iterator type returned by begin(), which efficiently iterates all 1 positions. */
81 : : class Iterator
82 : : {
83 : : friend class IntBitSet;
84 : : I m_val; /**< The original integer's remaining bits. */
85 : : unsigned m_pos; /** Last reported 1 position (if m_pos != 0). */
86 : 203 : constexpr Iterator(I val) noexcept : m_val(val), m_pos(0)
87 : : {
88 : 112 : if (m_val != 0) m_pos = std::countr_zero(m_val);
89 : : }
90 : : public:
91 : : /** Do not allow external code to construct an Iterator. */
92 : : Iterator() = delete;
93 : : // Copying is allowed.
94 : : constexpr Iterator(const Iterator&) noexcept = default;
95 : : constexpr Iterator& operator=(const Iterator&) noexcept = default;
96 : : /** Test whether we are done (can only compare with IteratorEnd). */
97 : 453 : constexpr friend bool operator==(const Iterator& a, const IteratorEnd&) noexcept
98 : : {
99 [ + + + + : 453 : return a.m_val == 0;
+ + + + -
- + + + +
+ + + + +
+ ]
100 : : }
101 : : /** Progress to the next 1 bit (only if != IteratorEnd). */
102 : 250 : constexpr Iterator& operator++() noexcept
103 : : {
104 : 250 : Assume(m_val != 0);
105 : 250 : m_val &= m_val - I{1U};
106 [ + + ]: 250 : if (m_val != 0) m_pos = std::countr_zero(m_val);
107 : 250 : return *this;
108 : : }
109 : : /** Get the current bit position (only if != IteratorEnd). */
110 : 250 : constexpr unsigned operator*() const noexcept
111 : : {
112 : 250 : Assume(m_val != 0);
113 : 250 : return m_pos;
114 : : }
115 : : };
116 : :
117 : : public:
118 : : /** Construct an all-zero bitset. */
119 : 36 : constexpr IntBitSet() noexcept : m_val{0} {}
120 : : /** Copy construct a bitset. */
121 : : constexpr IntBitSet(const IntBitSet&) noexcept = default;
122 : : /** Construct from a list of values. */
123 : 11 : constexpr IntBitSet(std::initializer_list<unsigned> ilist) noexcept : m_val(0)
124 : : {
125 [ + + ]: 25 : for (auto pos : ilist) Set(pos);
126 : 11 : }
127 : : /** Copy assign a bitset. */
128 : : constexpr IntBitSet& operator=(const IntBitSet&) noexcept = default;
129 : : /** Assign from a list of positions (which will be made true, all others false). */
130 : : constexpr IntBitSet& operator=(std::initializer_list<unsigned> ilist) noexcept
131 : : {
132 : : m_val = 0;
133 : : for (auto pos : ilist) Set(pos);
134 : : return *this;
135 : : }
136 : : /** Construct a bitset with the singleton i. */
137 : 138 : static constexpr IntBitSet Singleton(unsigned i) noexcept
138 : : {
139 : 138 : Assume(i < MAX_SIZE);
140 : 138 : return IntBitSet(I(1U) << i);
141 : : }
142 : : /** Construct a bitset with bits 0..count-1 (inclusive) set to 1. */
143 : 37 : static constexpr IntBitSet Fill(unsigned count) noexcept
144 : : {
145 : 37 : IntBitSet ret;
146 : 37 : Assume(count <= MAX_SIZE);
147 [ + + ]: 37 : if (count) ret.m_val = I(~I{0}) >> (MAX_SIZE - count);
148 : 37 : return ret;
149 : : }
150 : : /** Set a bit to 1. */
151 : 159 : constexpr void Set(unsigned pos) noexcept
152 : : {
153 : 159 : Assume(pos < MAX_SIZE);
154 : 159 : m_val |= I{1U} << pos;
155 : 159 : }
156 : : /** Set a bit to the specified value. */
157 : : constexpr void Set(unsigned pos, bool val) noexcept
158 : : {
159 : : Assume(pos < MAX_SIZE);
160 : : m_val = (m_val & ~I(I{1U} << pos)) | (I(val) << pos);
161 : : }
162 : : /** Set a bit to 0. */
163 : 20 : constexpr void Reset(unsigned pos) noexcept
164 : : {
165 : 20 : Assume(pos < MAX_SIZE);
166 : 20 : m_val &= ~I(I{1U} << pos);
167 : 20 : }
168 : : /** Retrieve a bit at the given position. */
169 : 149 : constexpr bool operator[](unsigned pos) const noexcept
170 : : {
171 : 149 : Assume(pos < MAX_SIZE);
172 : 149 : return (m_val >> pos) & 1U;
173 : : }
174 : : /** Compute the number of 1 bits in the bitset. */
175 [ + - + - : 68 : constexpr unsigned Count() const noexcept { return PopCount(m_val); }
+ - + + ]
176 : : /** Return the number of bits that this object holds. */
177 : : static constexpr unsigned Size() noexcept { return MAX_SIZE; }
178 : : /** Check if all bits are 0. */
179 [ + + ]: 7 : constexpr bool None() const noexcept { return m_val == 0; }
180 : : /** Check if any bits are 1. */
181 : 49 : constexpr bool Any() const noexcept { return !None(); }
182 : : /** Return an object that iterates over all 1 bits (++ and * only allowed when != end()). */
183 [ + + + + : 351 : constexpr Iterator begin() const noexcept { return Iterator(m_val); }
+ + + + -
- + + + +
+ - ]
184 : : /** Return a dummy object to compare Iterators with. */
185 : : constexpr IteratorEnd end() const noexcept { return IteratorEnd(); }
186 : : /** Find the first element (requires Any()). */
187 : 49 : constexpr unsigned First() const noexcept
188 : : {
189 : 49 : Assume(m_val != 0);
190 [ + - ]: 49 : return std::countr_zero(m_val);
191 : : }
192 : : /** Find the last element (requires Any()). */
193 : 6 : constexpr unsigned Last() const noexcept
194 : : {
195 : 6 : Assume(m_val != 0);
196 [ + - ]: 6 : return std::bit_width(m_val) - 1;
197 : : }
198 : : /** Set this object's bits to be the binary AND between respective bits from this and a. */
199 [ + - ]: 154 : constexpr IntBitSet& operator|=(const IntBitSet& a) noexcept { m_val |= a.m_val; return *this; }
200 : : /** Set this object's bits to be the binary OR between respective bits from this and a. */
201 : 29 : constexpr IntBitSet& operator&=(const IntBitSet& a) noexcept { m_val &= a.m_val; return *this; }
202 : : /** Set this object's bits to be the binary AND NOT between respective bits from this and a. */
203 [ + + ]: 95 : constexpr IntBitSet& operator-=(const IntBitSet& a) noexcept { m_val &= ~a.m_val; return *this; }
204 : : /** Set this object's bits to be the binary XOR between respective bits from this as a. */
205 : : constexpr IntBitSet& operator^=(const IntBitSet& a) noexcept { m_val ^= a.m_val; return *this; }
206 : : /** Check if the intersection between two sets is non-empty. */
207 [ + + ]: 30 : constexpr bool Overlaps(const IntBitSet& a) const noexcept { return m_val & a.m_val; }
208 : : /** Return an object with the binary AND between respective bits from a and b. */
209 : : friend constexpr IntBitSet operator&(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val & b.m_val); }
210 : : /** Return an object with the binary OR between respective bits from a and b. */
211 : : friend constexpr IntBitSet operator|(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val | b.m_val); }
212 : : /** Return an object with the binary AND NOT between respective bits from a and b. */
213 [ + + + - : 155 : friend constexpr IntBitSet operator-(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val & ~b.m_val); }
+ + ]
214 : : /** Return an object with the binary XOR between respective bits from a and b. */
215 : : friend constexpr IntBitSet operator^(const IntBitSet& a, const IntBitSet& b) noexcept { return I(a.m_val ^ b.m_val); }
216 : : /** Check if bitset a and bitset b are identical. */
217 [ + - + - : 36 : friend constexpr bool operator==(const IntBitSet& a, const IntBitSet& b) noexcept = default;
- + + - ]
218 : : /** Check if bitset a is a superset of bitset b (= every 1 bit in b is also in a). */
219 : : constexpr bool IsSupersetOf(const IntBitSet& a) const noexcept { return (a.m_val & ~m_val) == 0; }
220 : : /** Check if bitset a is a subset of bitset b (= every 1 bit in a is also in b). */
221 : 69 : constexpr bool IsSubsetOf(const IntBitSet& a) const noexcept { return (m_val & ~a.m_val) == 0; }
222 : : /** Swap two bitsets. */
223 : : friend constexpr void swap(IntBitSet& a, IntBitSet& b) noexcept { std::swap(a.m_val, b.m_val); }
224 : : };
225 : :
226 : : /** A bitset implementation backed by N integers of type I. */
227 : : template<typename I, unsigned N>
228 : : class MultiIntBitSet
229 : : {
230 : : // Only binary, unsigned, integer, types allowed.
231 : : static_assert(std::is_integral_v<I> && std::is_unsigned_v<I> && std::numeric_limits<I>::radix == 2);
232 : : // Cannot be empty.
233 : : static_assert(N > 0);
234 : : /** The number of bits per integer. */
235 : : static constexpr unsigned LIMB_BITS = std::numeric_limits<I>::digits;
236 : : /** Number of elements this set type supports. */
237 : : static constexpr unsigned MAX_SIZE = LIMB_BITS * N;
238 : : // No overflow allowed here.
239 : : static_assert(MAX_SIZE / LIMB_BITS == N);
240 : : /** Array whose member integers store the bits of the set. */
241 : : std::array<I, N> m_val;
242 : : /** Dummy type to return using end(). Only used for comparing with Iterator. */
243 : : class IteratorEnd
244 : : {
245 : : friend class MultiIntBitSet;
246 : : constexpr IteratorEnd() = default;
247 : : public:
248 : : constexpr IteratorEnd(const IteratorEnd&) = default;
249 : : };
250 : : /** Iterator type returned by begin(), which efficiently iterates all 1 positions. */
251 : : class Iterator
252 : : {
253 : : friend class MultiIntBitSet;
254 : : const std::array<I, N>* m_ptr; /**< Pointer to array to fetch bits from. */
255 : : I m_val; /**< The remaining bits of (*m_ptr)[m_idx]. */
256 : : unsigned m_pos; /**< The last reported position. */
257 : : unsigned m_idx; /**< The index in *m_ptr currently being iterated over. */
258 : : constexpr Iterator(const std::array<I, N>& ref) noexcept : m_ptr(&ref), m_idx(0)
259 : : {
260 : : do {
261 : : m_val = (*m_ptr)[m_idx];
262 : : if (m_val) {
263 : : m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS;
264 : : break;
265 : : }
266 : : ++m_idx;
267 : : } while(m_idx < N);
268 : : }
269 : :
270 : : public:
271 : : /** Do not allow external code to construct an Iterator. */
272 : : Iterator() = delete;
273 : : // Copying is allowed.
274 : : constexpr Iterator(const Iterator&) noexcept = default;
275 : : constexpr Iterator& operator=(const Iterator&) noexcept = default;
276 : : /** Test whether we are done (can only compare with IteratorEnd). */
277 : : friend constexpr bool operator==(const Iterator& a, const IteratorEnd&) noexcept
278 : : {
279 : : return a.m_idx == N;
280 : : }
281 : : /** Progress to the next 1 bit (only if != IteratorEnd). */
282 : : constexpr Iterator& operator++() noexcept
283 : : {
284 : : Assume(m_idx < N);
285 : : m_val &= m_val - I{1U};
286 : : if (m_val == 0) {
287 : : while (true) {
288 : : ++m_idx;
289 : : if (m_idx == N) break;
290 : : m_val = (*m_ptr)[m_idx];
291 : : if (m_val) {
292 : : m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS;
293 : : break;
294 : : }
295 : : }
296 : : } else {
297 : : m_pos = std::countr_zero(m_val) + m_idx * LIMB_BITS;
298 : : }
299 : : return *this;
300 : : }
301 : : /** Get the current bit position (only if != IteratorEnd). */
302 : : constexpr unsigned operator*() const noexcept
303 : : {
304 : : Assume(m_idx < N);
305 : : return m_pos;
306 : : }
307 : : };
308 : :
309 : : public:
310 : : /** Construct an all-zero bitset. */
311 : : constexpr MultiIntBitSet() noexcept : m_val{} {}
312 : : /** Copy construct a bitset. */
313 : : constexpr MultiIntBitSet(const MultiIntBitSet&) noexcept = default;
314 : : /** Copy assign a bitset. */
315 : : constexpr MultiIntBitSet& operator=(const MultiIntBitSet&) noexcept = default;
316 : : /** Set a bit to 1. */
317 : : void constexpr Set(unsigned pos) noexcept
318 : : {
319 : : Assume(pos < MAX_SIZE);
320 : : m_val[pos / LIMB_BITS] |= I{1U} << (pos % LIMB_BITS);
321 : : }
322 : : /** Set a bit to the specified value. */
323 : : void constexpr Set(unsigned pos, bool val) noexcept
324 : : {
325 : : Assume(pos < MAX_SIZE);
326 : : m_val[pos / LIMB_BITS] = (m_val[pos / LIMB_BITS] & ~I(I{1U} << (pos % LIMB_BITS))) |
327 : : (I{val} << (pos % LIMB_BITS));
328 : : }
329 : : /** Construct a bitset from a list of values. */
330 : : constexpr MultiIntBitSet(std::initializer_list<unsigned> ilist) noexcept : m_val{}
331 : : {
332 : : for (auto pos : ilist) Set(pos);
333 : : }
334 : : /** Set a bitset to a list of values. */
335 : : constexpr MultiIntBitSet& operator=(std::initializer_list<unsigned> ilist) noexcept
336 : : {
337 : : m_val.fill(0);
338 : : for (auto pos : ilist) Set(pos);
339 : : return *this;
340 : : }
341 : : /** Set a bit to 0. */
342 : : void constexpr Reset(unsigned pos) noexcept
343 : : {
344 : : Assume(pos < MAX_SIZE);
345 : : m_val[pos / LIMB_BITS] &= ~I(I{1U} << (pos % LIMB_BITS));
346 : : }
347 : : /** Retrieve a bit at the given position. */
348 : : bool constexpr operator[](unsigned pos) const noexcept
349 : : {
350 : : Assume(pos < MAX_SIZE);
351 : : return (m_val[pos / LIMB_BITS] >> (pos % LIMB_BITS)) & 1U;
352 : : }
353 : : /** Construct a bitset with the singleton pos. */
354 : : static constexpr MultiIntBitSet Singleton(unsigned pos) noexcept
355 : : {
356 : : Assume(pos < MAX_SIZE);
357 : : MultiIntBitSet ret;
358 : : ret.m_val[pos / LIMB_BITS] = I{1U} << (pos % LIMB_BITS);
359 : : return ret;
360 : : }
361 : : /** Construct a bitset with bits 0..count-1 (inclusive) set to 1. */
362 : : static constexpr MultiIntBitSet Fill(unsigned count) noexcept
363 : : {
364 : : Assume(count <= MAX_SIZE);
365 : : MultiIntBitSet ret;
366 : : if (count) {
367 : : unsigned i = 0;
368 : : while (count > LIMB_BITS) {
369 : : ret.m_val[i++] = ~I{0};
370 : : count -= LIMB_BITS;
371 : : }
372 : : ret.m_val[i] = I(~I{0}) >> (LIMB_BITS - count);
373 : : }
374 : : return ret;
375 : : }
376 : : /** Return the number of bits that this object holds. */
377 : : static constexpr unsigned Size() noexcept { return MAX_SIZE; }
378 : : /** Compute the number of 1 bits in the bitset. */
379 : : unsigned constexpr Count() const noexcept
380 : : {
381 : : unsigned ret{0};
382 : : for (I v : m_val) ret += PopCount(v);
383 : : return ret;
384 : : }
385 : : /** Check if all bits are 0. */
386 : : bool constexpr None() const noexcept
387 : : {
388 : : for (auto v : m_val) {
389 : : if (v != 0) return false;
390 : : }
391 : : return true;
392 : : }
393 : : /** Check if any bits are 1. */
394 : : bool constexpr Any() const noexcept { return !None(); }
395 : : /** Return an object that iterates over all 1 bits (++ and * only allowed when != end()). */
396 : : Iterator constexpr begin() const noexcept { return Iterator(m_val); }
397 : : /** Return a dummy object to compare Iterators with. */
398 : : IteratorEnd constexpr end() const noexcept { return IteratorEnd(); }
399 : : /** Find the first element (requires Any()). */
400 : : unsigned constexpr First() const noexcept
401 : : {
402 : : unsigned p = 0;
403 : : while (m_val[p] == 0) {
404 : : ++p;
405 : : Assume(p < N);
406 : : }
407 : : return std::countr_zero(m_val[p]) + p * LIMB_BITS;
408 : : }
409 : : /** Find the last element (requires Any()). */
410 : : unsigned constexpr Last() const noexcept
411 : : {
412 : : unsigned p = N - 1;
413 : : while (m_val[p] == 0) {
414 : : Assume(p > 0);
415 : : --p;
416 : : }
417 : : return std::bit_width(m_val[p]) - 1 + p * LIMB_BITS;
418 : : }
419 : : /** Set this object's bits to be the binary OR between respective bits from this and a. */
420 : : constexpr MultiIntBitSet& operator|=(const MultiIntBitSet& a) noexcept
421 : : {
422 : : for (unsigned i = 0; i < N; ++i) {
423 : : m_val[i] |= a.m_val[i];
424 : : }
425 : : return *this;
426 : : }
427 : : /** Set this object's bits to be the binary AND between respective bits from this and a. */
428 : : constexpr MultiIntBitSet& operator&=(const MultiIntBitSet& a) noexcept
429 : : {
430 : : for (unsigned i = 0; i < N; ++i) {
431 : : m_val[i] &= a.m_val[i];
432 : : }
433 : : return *this;
434 : : }
435 : : /** Set this object's bits to be the binary AND NOT between respective bits from this and a. */
436 : : constexpr MultiIntBitSet& operator-=(const MultiIntBitSet& a) noexcept
437 : : {
438 : : for (unsigned i = 0; i < N; ++i) {
439 : : m_val[i] &= ~a.m_val[i];
440 : : }
441 : : return *this;
442 : : }
443 : : /** Set this object's bits to be the binary XOR between respective bits from this and a. */
444 : : constexpr MultiIntBitSet& operator^=(const MultiIntBitSet& a) noexcept
445 : : {
446 : : for (unsigned i = 0; i < N; ++i) {
447 : : m_val[i] ^= a.m_val[i];
448 : : }
449 : : return *this;
450 : : }
451 : : /** Check whether the intersection between two sets is non-empty. */
452 : : constexpr bool Overlaps(const MultiIntBitSet& a) const noexcept
453 : : {
454 : : for (unsigned i = 0; i < N; ++i) {
455 : : if (m_val[i] & a.m_val[i]) return true;
456 : : }
457 : : return false;
458 : : }
459 : : /** Return an object with the binary AND between respective bits from a and b. */
460 : : friend constexpr MultiIntBitSet operator&(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept
461 : : {
462 : : MultiIntBitSet r;
463 : : for (unsigned i = 0; i < N; ++i) {
464 : : r.m_val[i] = a.m_val[i] & b.m_val[i];
465 : : }
466 : : return r;
467 : : }
468 : : /** Return an object with the binary OR between respective bits from a and b. */
469 : : friend constexpr MultiIntBitSet operator|(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept
470 : : {
471 : : MultiIntBitSet r;
472 : : for (unsigned i = 0; i < N; ++i) {
473 : : r.m_val[i] = a.m_val[i] | b.m_val[i];
474 : : }
475 : : return r;
476 : : }
477 : : /** Return an object with the binary AND NOT between respective bits from a and b. */
478 : : friend constexpr MultiIntBitSet operator-(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept
479 : : {
480 : : MultiIntBitSet r;
481 : : for (unsigned i = 0; i < N; ++i) {
482 : : r.m_val[i] = a.m_val[i] & ~b.m_val[i];
483 : : }
484 : : return r;
485 : : }
486 : : /** Return an object with the binary XOR between respective bits from a and b. */
487 : : friend constexpr MultiIntBitSet operator^(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept
488 : : {
489 : : MultiIntBitSet r;
490 : : for (unsigned i = 0; i < N; ++i) {
491 : : r.m_val[i] = a.m_val[i] ^ b.m_val[i];
492 : : }
493 : : return r;
494 : : }
495 : : /** Check if bitset a is a superset of bitset b (= every 1 bit in b is also in a). */
496 : : constexpr bool IsSupersetOf(const MultiIntBitSet& a) const noexcept
497 : : {
498 : : for (unsigned i = 0; i < N; ++i) {
499 : : if (a.m_val[i] & ~m_val[i]) return false;
500 : : }
501 : : return true;
502 : : }
503 : : /** Check if bitset a is a subset of bitset b (= every 1 bit in a is also in b). */
504 : : constexpr bool IsSubsetOf(const MultiIntBitSet& a) const noexcept
505 : : {
506 : : for (unsigned i = 0; i < N; ++i) {
507 : : if (m_val[i] & ~a.m_val[i]) return false;
508 : : }
509 : : return true;
510 : : }
511 : : /** Check if bitset a and bitset b are identical. */
512 : : friend constexpr bool operator==(const MultiIntBitSet& a, const MultiIntBitSet& b) noexcept = default;
513 : : /** Swap two bitsets. */
514 : : friend constexpr void swap(MultiIntBitSet& a, MultiIntBitSet& b) noexcept { std::swap(a.m_val, b.m_val); }
515 : : };
516 : :
517 : : } // namespace bitset_detail
518 : :
519 : : // BitSet dispatches to IntBitSet or MultiIntBitSet as appropriate for the requested minimum number
520 : : // of bits. Use IntBitSet up to 32-bit, or up to 64-bit on 64-bit platforms; above that, use a
521 : : // MultiIntBitSet of size_t.
522 : : template<unsigned BITS>
523 : : using BitSet = std::conditional_t<(BITS <= 32), bitset_detail::IntBitSet<uint32_t>,
524 : : std::conditional_t<(BITS <= std::numeric_limits<size_t>::digits), bitset_detail::IntBitSet<size_t>,
525 : : bitset_detail::MultiIntBitSet<size_t, (BITS + std::numeric_limits<size_t>::digits - 1) / std::numeric_limits<size_t>::digits>>>;
526 : :
527 : : #endif // BITCOIN_UTIL_BITSET_H
|