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