P4C
The P4 Compiler
Loading...
Searching...
No Matches
bitvec.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef LIB_BITVEC_H_
18#define LIB_BITVEC_H_
19
20#include <assert.h>
21#include <limits.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <iostream>
27#include <type_traits>
28#include <utility>
29
30#include "config.h"
31
32#if HAVE_LIBGC
33#include <gc_cpp.h>
34#define IF_HAVE_LIBGC(X) X
35#else
36#define IF_HAVE_LIBGC(X)
37#endif /* HAVE_LIBGC */
38
39#ifdef setbit
40/* some broken systems define a `setbit' macro in their system header files! */
41#undef setbit
42#endif
43#ifdef clrbit
44/* some broken systems define a `clrbit' macro in their system header files! */
45#undef clrbit
46#endif
47
48namespace bv {
49#if defined(__GNUC__) || defined(__clang__)
50/* use builtin count leading/trailing bits of type-approprite size */
51static inline int builtin_ctz(unsigned x) { return __builtin_ctz(x); }
52static inline int builtin_ctz(unsigned long x) { return __builtin_ctzl(x); }
53static inline int builtin_ctz(unsigned long long x) { return __builtin_ctzll(x); }
54static inline int builtin_clz(unsigned x) { return __builtin_clz(x); }
55static inline int builtin_clz(unsigned long x) { return __builtin_clzl(x); }
56static inline int builtin_clz(unsigned long long x) { return __builtin_clzll(x); }
57static inline int builtin_popcount(unsigned x) { return __builtin_popcount(x); }
58static inline int builtin_popcount(unsigned long x) { return __builtin_popcountl(x); }
59static inline int builtin_popcount(unsigned long long x) { return __builtin_popcountll(x); }
60#endif
61
62template <typename I>
63void _check_bit_op_type_valid() {
64 static_assert(
65 std::is_integral<I>::value && std::is_unsigned<I>::value &&
66 sizeof(I) <= sizeof(unsigned long long) && sizeof(unsigned) <= sizeof(I),
67 "'I' has to be unsigned integral type of size between unsigned and unsigned long long");
68}
69
70template <typename I>
71int count_trailing_zeroes(I x) {
72 _check_bit_op_type_valid<I>();
73 assert(x != 0);
74#if defined(__GNUC__) || defined(__clang__)
75 return bv::builtin_ctz(x);
76#else
77 int cnt = 0;
78 while ((x & 0xff) == 0) {
79 cnt += 8;
80 val >>= 8;
81 }
82 while ((x & 1) == 0) {
83 cnt++;
84 val >>= 1;
85 }
86 return cnt;
87#endif
88}
89
90template <typename I>
91int count_leading_zeroes(I x) {
92 _check_bit_op_type_valid<I>();
93 assert(x != 0);
94#if defined(__GNUC__) || defined(__clang__)
95 return bv::builtin_clz(x);
96#else
97 int cnt = 0;
98 while (!(x >> (CHAR_BIT * sizeof(I) - 1))) {
99 --cnt;
100 x <<= 1;
101 }
102 return cnt;
103#endif
104}
105
106template <typename I>
107int popcount(I x) {
108 _check_bit_op_type_valid<I>();
109#if defined(__GNUC__) || defined(__clang__)
110 return builtin_popcount(x);
111#else
112 int rv = 0;
113 for (auto v = x; v; v &= v - 1) ++rv;
114 return rv;
115#endif
116}
117} // namespace bv
118
119class bitvec {
120 size_t size;
121 union {
122 uintptr_t data;
123 uintptr_t *ptr;
124 };
125 uintptr_t word(size_t i) const { return i < size ? size > 1 ? ptr[i] : data : 0; }
126
127 public:
128 static constexpr size_t bits_per_unit = CHAR_BIT * sizeof(uintptr_t);
129
130 private:
131 template <class T>
132 class bitref {
133 friend class bitvec;
134 T self;
135 int idx;
136 bitref(T s, int i) : self(s), idx(i) {}
137
138 public:
139 bitref(const bitref &a) = default;
140 bitref(bitref &&a) = default;
141 operator bool() const { return self.getbit(idx); }
142 bool operator==(const bitref &a) const { return &self == &a.self && idx == a.idx; }
143 bool operator!=(const bitref &a) const { return &self != &a.self || idx != a.idx; }
144 int index() const { return idx; }
145 int operator*() const { return idx; }
146 bitref &operator++() {
147 while ((size_t)++idx < self.size * bitvec::bits_per_unit) {
148 if (auto w =
149 self.word(idx / bitvec::bits_per_unit) >> (idx % bitvec::bits_per_unit)) {
150 idx += bv::count_trailing_zeroes(w);
151 return *this;
152 }
153 idx = (idx / bitvec::bits_per_unit) * bitvec::bits_per_unit +
154 bitvec::bits_per_unit - 1;
155 }
156 idx = -1;
157 return *this;
158 }
159 bitref &operator--() {
160 if (idx < 0) idx = self.size * bitvec::bits_per_unit;
161 while (--idx >= 0) {
162 if (auto w = self.word(idx / bitvec::bits_per_unit)
163 << (bitvec::bits_per_unit - 1 - idx % bitvec::bits_per_unit)) {
164 idx -= bv::count_leading_zeroes(w);
165 return *this;
166 }
167 idx = (idx / bitvec::bits_per_unit) * bitvec::bits_per_unit;
168 }
169 return *this;
170 }
171 };
172
173 public:
174 class nonconst_bitref : public bitref<bitvec &> {
175 friend class bitvec;
176 nonconst_bitref(bitvec &s, int i) : bitref(s, i) {}
177
178 public:
179 nonconst_bitref(const bitref<bitvec &> &a) : bitref(a) {} // NOLINT(runtime/explicit)
180 nonconst_bitref(const nonconst_bitref &a) = default;
181 nonconst_bitref(nonconst_bitref &&a) = default;
182 bool operator=(bool b) const {
183 assert(idx >= 0);
184 return b ? self.setbit(idx) : self.clrbit(idx);
185 }
186 bool set(bool b = true) {
187 assert(idx >= 0);
188 bool rv = self.getbit(idx);
189 b ? self.setbit(idx) : self.clrbit(idx);
190 return rv;
191 }
192 using difference_type = std::ptrdiff_t;
193 using value_type = const bitvec;
194 using pointer = const bitvec *;
195 using reference = const bool &;
196 using iterator_category = std::bidirectional_iterator_tag;
197 };
199
200 class const_bitref : public bitref<const bitvec &> {
201 friend class bitvec;
202 const_bitref(const bitvec &s, int i) : bitref(s, i) {}
203
204 public:
205 const_bitref(const bitref<const bitvec &> &a) : bitref(a) {} // NOLINT(runtime/explicit)
206 const_bitref(const const_bitref &a) = default;
207 const_bitref(const_bitref &&a) = default;
208 using difference_type = std::ptrdiff_t;
209 using value_type = const bitvec;
210 using pointer = const bitvec *;
211 using reference = const bool &;
212 using iterator_category = std::bidirectional_iterator_tag;
213 };
215
216 // when we take a bitref from an unnamed temp, we need to make a copy of it; if we kept
217 // a reference it would dangle. That needs to be after the bitvec class def to avoid
218 // incomplete type errors
219 class copy_bitref;
220
221 bitvec() : size(1), data(0) {}
222 explicit bitvec(uintptr_t v) : size(1), data(v) {}
223 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value &&
224 (sizeof(T) > sizeof(uintptr_t))>::type>
225 explicit bitvec(T v) : size(1), data(v) {
226 if (v != data) {
227 size = sizeof(v) / sizeof(data);
228 ptr = new IF_HAVE_LIBGC((PointerFreeGC)) uintptr_t[size];
229 for (unsigned i = 0; i < size; ++i) {
230 ptr[i] = v;
231 v >>= bits_per_unit;
232 }
233 }
234 }
235 bitvec(size_t lo, size_t cnt) : size(1), data(0) { setrange(lo, cnt); }
236 bitvec(const bitvec &a) : size(a.size) {
237 if (size > 1) {
238 ptr = new IF_HAVE_LIBGC((PointerFreeGC)) uintptr_t[size];
239 memcpy(ptr, a.ptr, size * sizeof(*ptr));
240 } else {
241 data = a.data;
242 }
243 }
244 bitvec(bitvec &&a) : size(a.size), data(a.data) { a.size = 1; }
245 bitvec &operator=(const bitvec &a) {
246 if (this == &a) return *this;
247 if (size > 1) delete[] ptr;
248 if ((size = a.size) > 1) {
249 ptr = new IF_HAVE_LIBGC((PointerFreeGC)) uintptr_t[size];
250 memcpy(ptr, a.ptr, size * sizeof(*ptr));
251 } else {
252 data = a.data;
253 }
254 return *this;
255 }
256 bitvec &operator=(bitvec &&a) {
257 std::swap(size, a.size);
258 std::swap(data, a.data);
259 return *this;
260 }
261 ~bitvec() {
262 if (size > 1) delete[] ptr;
263 }
264
265 void clear() {
266 if (size > 1)
267 memset(ptr, 0, size * sizeof(*ptr));
268 else
269 data = 0;
270 } // NOLINT(whitespace/newline)
271 bool setbit(size_t idx) {
272 if (idx >= size * bits_per_unit) expand(1 + idx / bits_per_unit);
273 if (size > 1)
274 ptr[idx / bits_per_unit] |= (uintptr_t)1 << (idx % bits_per_unit);
275 else
276 data |= (uintptr_t)1 << idx;
277 return true;
278 }
279 void setrange(size_t idx, size_t sz) {
280 if (sz == 0) return;
281 if (idx + sz > size * bits_per_unit) expand(1 + (idx + sz - 1) / bits_per_unit);
282 if (size == 1) {
283 data |= ~(~(uintptr_t)1 << (sz - 1)) << idx;
284 } else if (idx / bits_per_unit == (idx + sz - 1) / bits_per_unit) {
285 ptr[idx / bits_per_unit] |= ~(~(uintptr_t)1 << (sz - 1)) << (idx % bits_per_unit);
286 } else {
287 size_t i = idx / bits_per_unit;
288 ptr[i] |= ~(uintptr_t)0 << (idx % bits_per_unit);
289 idx += sz;
290 while (++i < idx / bits_per_unit) {
291 ptr[i] = ~(uintptr_t)0;
292 }
293 if (i < size) ptr[i] |= (((uintptr_t)1 << (idx % bits_per_unit)) - 1);
294 }
295 }
296 void setraw(uintptr_t raw) {
297 if (size == 1) {
298 data = raw;
299 } else {
300 ptr[0] = raw;
301 for (size_t i = 1; i < size; i++) ptr[i] = 0;
302 }
303 }
304 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value &&
305 (sizeof(T) > sizeof(uintptr_t))>::type>
306 void setraw(T raw) {
307 if (sizeof(T) / sizeof(uintptr_t) > size) expand(sizeof(T) / sizeof(uintptr_t));
308 for (size_t i = 0; i < size; i++) {
309 ptr[i] = raw;
310 raw >>= bits_per_unit;
311 }
312 }
313 void setraw(uintptr_t *raw, size_t sz) {
314 if (sz > size) expand(sz);
315 if (size == 1) {
316 data = raw[0];
317 } else {
318 for (size_t i = 0; i < sz; i++) ptr[i] = raw[i];
319 for (size_t i = sz; i < size; i++) ptr[i] = 0;
320 }
321 }
322 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value &&
323 (sizeof(T) > sizeof(uintptr_t))>::type>
324 void setraw(T *raw, size_t sz) {
325 constexpr size_t m = sizeof(T) / sizeof(uintptr_t);
326 if (m * sz > size) expand(m * sz);
327 size_t i = 0;
328 for (; i < sz * m; ++i) ptr[i] = raw[i / m] >> ((i % m) * bits_per_unit);
329 for (; i < size; ++i) ptr[i] = 0;
330 }
331 bool clrbit(size_t idx) {
332 if (idx >= size * bits_per_unit) return false;
333 if (size > 1)
334 ptr[idx / bits_per_unit] &= ~((uintptr_t)1 << (idx % bits_per_unit));
335 else
336 data &= ~((uintptr_t)1 << idx);
337 return false;
338 }
339 void clrrange(size_t idx, size_t sz) {
340 if (sz == 0) return;
341 if (size < sz / bits_per_unit) // To avoid sz + idx overflow
342 sz = size * bits_per_unit;
343 if (idx >= size * bits_per_unit) return;
344 if (size == 1) {
345 if (idx + sz < bits_per_unit)
346 data &= ~(~(~(uintptr_t)1 << (sz - 1)) << idx);
347 else
348 data &= ~(~(uintptr_t)0 << idx);
349 } else if (idx / bits_per_unit == (idx + sz - 1) / bits_per_unit) {
350 ptr[idx / bits_per_unit] &= ~(~(~(uintptr_t)1 << (sz - 1)) << (idx % bits_per_unit));
351 } else {
352 size_t i = idx / bits_per_unit;
353 ptr[i] &= ~(~(uintptr_t)0 << (idx % bits_per_unit));
354 idx += sz;
355 while (++i < idx / bits_per_unit && i < size) {
356 ptr[i] = 0;
357 }
358 if (i < size) ptr[i] &= ~(((uintptr_t)1 << (idx % bits_per_unit)) - 1);
359 }
360 }
361 bool getbit(size_t idx) const {
362 return (word(idx / bits_per_unit) >> (idx % bits_per_unit)) & 1;
363 }
364 uintmax_t getrange(size_t idx, size_t sz) const {
365 assert(sz > 0 && sz <= CHAR_BIT * sizeof(uintmax_t));
366 if (idx >= size * bits_per_unit) return 0;
367 if (size > 1) {
368 unsigned shift = idx % bits_per_unit;
369 idx /= bits_per_unit;
370 uintmax_t rv = ptr[idx] >> shift;
371 shift = bits_per_unit - shift;
372 while (shift < sz) {
373 if (++idx >= size) break;
374 rv |= (uintmax_t)ptr[idx] << shift;
375 shift += bits_per_unit;
376 }
377 return rv & ~(~(uintmax_t)1 << (sz - 1));
378 } else {
379 return (data >> idx) & ~(~(uintmax_t)1 << (sz - 1));
380 }
381 }
382 void putrange(size_t idx, size_t sz, uintmax_t v) {
383 assert(sz > 0 && sz <= CHAR_BIT * sizeof(uintmax_t));
384 uintptr_t mask = ~(uintmax_t)0 >> (CHAR_BIT * sizeof(uintmax_t) - sz);
385 v &= mask;
386 if (idx + sz > size * bits_per_unit) expand(1 + (idx + sz - 1) / bits_per_unit);
387 if (size == 1) {
388 data &= ~(mask << idx);
389 data |= v << idx;
390 } else {
391 unsigned shift = idx % bits_per_unit;
392 idx /= bits_per_unit;
393 ptr[idx] &= ~(mask << shift);
394 ptr[idx] |= v << shift;
395 shift = bits_per_unit - shift;
396 while (shift < sz) {
397 assert(idx + 1 < size);
398 ptr[++idx] &= ~(mask >> shift);
399 ptr[idx] |= v >> shift;
400 shift += bits_per_unit;
401 }
402 }
403 }
404 bitvec getslice(size_t idx, size_t sz) const;
405 nonconst_bitref operator[](int idx) { return nonconst_bitref(*this, idx); }
406 bool operator[](int idx) const { return getbit(idx); }
407 int ffs(unsigned start = 0) const;
408 unsigned ffz(unsigned start = 0) const;
409 const_bitref min() const & { return const_bitref(*this, ffs()); }
410 const_bitref max() const & { return --const_bitref(*this, size * bits_per_unit); }
411 const_bitref begin() const & { return min(); }
412 const_bitref end() const & { return const_bitref(*this, -1); }
413 // not safe to keep a ref to a temp bitvec -- need to make a copy.
414 copy_bitref min() &&;
415 copy_bitref max() &&;
416 copy_bitref begin() &&;
417 copy_bitref end() &&;
418 nonconst_bitref min() & { return nonconst_bitref(*this, ffs()); }
419 nonconst_bitref max() & { return --nonconst_bitref(*this, size * bits_per_unit); }
420 nonconst_bitref begin() & { return min(); }
421 nonconst_bitref end() & { return nonconst_bitref(*this, -1); }
422 bool empty() const {
423 for (size_t i = 0; i < size; i++)
424 if (word(i) != 0) return false;
425 return true;
426 }
427 explicit operator bool() const { return !empty(); }
428 bool operator&=(const bitvec &a) {
429 bool rv = false;
430 if (size > 1) {
431 if (a.size > 1) {
432 for (size_t i = 0; i < size && i < a.size; i++) {
433 rv |= ((ptr[i] & a.ptr[i]) != ptr[i]);
434 ptr[i] &= a.ptr[i];
435 }
436 } else {
437 rv |= ((*ptr & a.data) != *ptr);
438 *ptr &= a.data;
439 }
440 if (size > a.size) {
441 if (!rv) {
442 for (size_t i = a.size; i < size; i++)
443 if (ptr[i]) {
444 rv = true;
445 break;
446 }
447 }
448 memset(ptr + a.size, 0, (size - a.size) * sizeof(*ptr));
449 }
450 } else if (a.size > 1) {
451 rv |= ((data & a.ptr[0]) != data);
452 data &= a.ptr[0];
453 } else {
454 rv |= ((data & a.data) != data);
455 data &= a.data;
456 }
457 return rv;
458 }
459 bitvec operator&(const bitvec &a) const {
460 if (size <= a.size) {
461 bitvec rv(*this);
462 rv &= a;
463 return rv;
464 } else {
465 bitvec rv(a);
466 rv &= *this;
467 return rv;
468 }
469 }
470 bool operator|=(const bitvec &a) {
471 bool rv = false;
472 if (size < a.size) expand(a.size);
473 if (size > 1) {
474 if (a.size > 1) {
475 for (size_t i = 0; i < a.size; i++) {
476 rv |= ((ptr[i] | a.ptr[i]) != ptr[i]);
477 ptr[i] |= a.ptr[i];
478 }
479 } else {
480 rv |= ((*ptr | a.data) != *ptr);
481 *ptr |= a.data;
482 }
483 } else {
484 rv |= ((data | a.data) != data);
485 data |= a.data;
486 }
487 return rv;
488 }
489 bool operator|=(uintptr_t a) {
490 bool rv = false;
491 auto t = size > 1 ? ptr : &data;
492 rv |= ((*t | a) != *t);
493 *t |= a;
494 return rv;
495 }
496 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value &&
497 (sizeof(T) > sizeof(uintptr_t))>::type>
498 bool operator|=(T a) {
499 return (*this) |= bitvec(a);
500 }
501 bitvec operator|(const bitvec &a) const {
502 bitvec rv(*this);
503 rv |= a;
504 return rv;
505 }
506 bitvec operator|(uintptr_t a) const {
507 bitvec rv(*this);
508 rv |= a;
509 return rv;
510 }
511 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value &&
512 (sizeof(T) > sizeof(uintptr_t))>::type>
513 bitvec operator|(T a) {
514 bitvec rv(*this);
515 rv |= bitvec(a);
516 return rv;
517 }
518 bitvec &operator^=(const bitvec &a) {
519 if (size < a.size) expand(a.size);
520 if (size > 1) {
521 if (a.size > 1) {
522 for (size_t i = 0; i < a.size; i++) ptr[i] ^= a.ptr[i];
523 } else {
524 *ptr ^= a.data;
525 }
526 } else {
527 data ^= a.data;
528 }
529 return *this;
530 }
531 bitvec operator^(const bitvec &a) const {
532 bitvec rv(*this);
533 rv ^= a;
534 return rv;
535 }
536 bool operator-=(const bitvec &a) {
537 bool rv = false;
538 if (size > 1) {
539 if (a.size > 1) {
540 for (size_t i = 0; i < size && i < a.size; i++) {
541 rv |= ((ptr[i] & ~a.ptr[i]) != ptr[i]);
542 ptr[i] &= ~a.ptr[i];
543 }
544 } else {
545 rv |= ((*ptr & ~a.data) != *ptr);
546 *ptr &= ~a.data;
547 }
548 } else if (a.size > 1) {
549 rv |= ((data & ~a.ptr[0]) != data);
550 data &= ~a.ptr[0];
551 } else {
552 rv |= ((data & ~a.data) != data);
553 data &= ~a.data;
554 }
555 return rv;
556 }
557 bitvec operator-(const bitvec &a) const {
558 bitvec rv(*this);
559 rv -= a;
560 return rv;
561 }
562 bool operator==(const bitvec &a) const {
563 for (size_t i = 0; i < size || i < a.size; i++)
564 if (word(i) != a.word(i)) return false;
565 return true;
566 }
567 bool operator!=(const bitvec &a) const { return !(*this == a); }
568 bool operator<(const bitvec &a) const {
569 size_t i = std::max(size, a.size);
570 while (i--) {
571 if (word(i) < a.word(i)) return true;
572 if (word(i) > a.word(i)) return false;
573 }
574 return false;
575 }
576 bool operator>(const bitvec &a) const { return a < *this; }
577 bool operator>=(const bitvec &a) const { return !(*this < a); }
578 bool operator<=(const bitvec &a) const { return !(a < *this); }
579 bool intersects(const bitvec &a) const {
580 for (size_t i = 0; i < size && i < a.size; i++)
581 if (word(i) & a.word(i)) return true;
582 return false;
583 }
584 bool contains(const bitvec &a) const { // is 'a' a subset or equal to 'this'?
585 for (size_t i = 0; i < size && i < a.size; i++)
586 if ((word(i) & a.word(i)) != a.word(i)) return false;
587 for (size_t i = size; i < a.size; i++)
588 if (a.word(i)) return false;
589 return true;
590 }
591 bitvec &operator>>=(size_t count);
592 bitvec &operator<<=(size_t count);
593 bitvec operator>>(size_t count) const {
594 bitvec rv(*this);
595 rv >>= count;
596 return rv;
597 }
598 bitvec operator<<(size_t count) const {
599 bitvec rv(*this);
600 rv <<= count;
601 return rv;
602 }
603 void rotate_right(size_t start_bit, size_t rotation_idx, size_t end_bit);
604 bitvec rotate_right_copy(size_t start_bit, size_t rotation_idx, size_t end_bit) const;
605 int popcount() const {
606 int rv = 0;
607 for (size_t i = 0; i < size; i++) rv += bv::popcount(word(i));
608 return rv;
609 }
610 bool is_contiguous() const;
611
612 private:
613 void expand(size_t newsize) {
614 assert(newsize > size);
615 if (size_t m = newsize >> 3) {
616 /* round up newsize to be at most 7*2**k, to avoid reallocing too much */
617 m |= m >> 1;
618 m |= m >> 2;
619 m |= m >> 4;
620 m |= m >> 8;
621 m |= m >> 16;
622 newsize = (newsize + m) & ~m;
623 }
624 if (size > 1) {
625 uintptr_t *old = ptr;
626 ptr = new IF_HAVE_LIBGC((PointerFreeGC)) uintptr_t[newsize];
627 memcpy(ptr, old, size * sizeof(*ptr));
628 memset(ptr + size, 0, (newsize - size) * sizeof(*ptr));
629 delete[] old;
630 } else {
631 uintptr_t d = data;
632 ptr = new IF_HAVE_LIBGC((PointerFreeGC)) uintptr_t[newsize];
633 *ptr = d;
634 memset(ptr + size, 0, (newsize - size) * sizeof(*ptr));
635 }
636 size = newsize;
637 }
638
639 bitvec rotate_right_helper(size_t start_bit, size_t rotation_idx, size_t end_bit) const;
640
641 public:
642 friend std::ostream &operator<<(std::ostream &, const bitvec &);
643 friend std::istream &operator>>(std::istream &, bitvec &);
644 friend bool operator>>(const char *, bitvec &);
645};
646
647class bitvec::copy_bitref : public bitvec::bitref<const bitvec> {
648 friend class bitvec;
649 copy_bitref(const bitvec &s, int i) : bitref(s, i) {}
650
651 public:
652 copy_bitref(const bitref<const bitvec> &a) : bitref(a) {} // NOLINT(runtime/explicit)
653 copy_bitref(const copy_bitref &a) = default;
654 copy_bitref(copy_bitref &&a) = default;
655 bool operator==(const bitref &a) const { return idx == a.idx && self == a.self; }
656 bool operator==(const copy_bitref &a) const { return idx == a.idx && self == a.self; }
657 bool operator!=(const bitref &a) const { return idx != a.idx || self != a.self; }
658 bool operator!=(const copy_bitref &a) const { return idx != a.idx || self != a.self; }
659};
660inline bitvec::copy_bitref bitvec::min() && { return copy_bitref(*this, ffs()); }
661inline bitvec::copy_bitref bitvec::max() && { return --copy_bitref(*this, size * bits_per_unit); }
662inline bitvec::copy_bitref bitvec::begin() && { return copy_bitref(*this, ffs()); }
663inline bitvec::copy_bitref bitvec::end() && { return copy_bitref(*this, -1); }
664
665inline bitvec operator|(bitvec &&a, const bitvec &b) {
666 bitvec rv(std::move(a));
667 rv |= b;
668 return rv;
669}
670inline bitvec operator&(bitvec &&a, const bitvec &b) {
671 bitvec rv(std::move(a));
672 rv &= b;
673 return rv;
674}
675inline bitvec operator^(bitvec &&a, const bitvec &b) {
676 bitvec rv(std::move(a));
677 rv ^= b;
678 return rv;
679}
680inline bitvec operator-(bitvec &&a, const bitvec &b) {
681 bitvec rv(std::move(a));
682 rv -= b;
683 return rv;
684}
685
686#endif /* LIB_BITVEC_H_ */
Definition bitvec.h:200
Definition bitvec.h:647
Definition bitvec.h:174
Definition bitvec.h:119
void rotate_right(size_t start_bit, size_t rotation_idx, size_t end_bit)
Definition bitvec.cpp:199