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