17#include "absl/numeric/bits.h"
19#include "exceptions.h"
31 std::pair<int, int> range;
35 range.first = range.second = ptr.index();
36 while (++ptr && range.second + 1 == ptr.index()) ++range.second;
42 std::pair<int, int> operator*() {
return range; }
43 bool operator==(iter &a)
const {
return valid == a.valid && ptr == a.ptr; }
44 bool operator!=(iter &a)
const {
return !(*
this == a); }
49 explicit bitranges(
const bitvec &b) : bits(b) {}
50 explicit bitranges(
bitvec &&b) : tmp(b), bits(tmp) {}
51 explicit bitranges(uintptr_t b) : tmp(b), bits(tmp) {}
52 iter begin()
const {
return iter(bits.begin()); }
53 iter end()
const {
return iter(bits.end()); }
68constexpr inline int divideFloor(
int dividend,
int divisor) {
69#if defined(__GNUC__) || defined(__clang__)
73 unsigned u_divisor =
static_cast<unsigned>(divisor);
74 if (__builtin_constant_p(u_divisor) && absl::has_single_bit(u_divisor))
75 return dividend >> (absl::bit_width(u_divisor) - 1);
78 const int quotient = dividend / divisor;
79 const int remainder = dividend % divisor;
80 if ((remainder != 0) && ((remainder < 0) != (divisor < 0)))
return quotient - 1;
91constexpr int modulo(
int dividend,
int divisor) {
92 return (dividend % divisor) * ((dividend < 0) != (divisor < 0) ? -1 : 1);
108constexpr inline int moduloFloor(
const int dividend,
const int divisor) {
109#if defined(__GNUC__) || defined(__clang__)
113 if (__builtin_constant_p(divisor) && absl::has_single_bit(
static_cast<unsigned>(divisor)))
114 return dividend & (divisor - 1);
117 const int remainder = modulo(dividend, divisor);
118 if (remainder == 0 || dividend >= 0)
return remainder;
119 return divisor - remainder;
133 FromTo(
int from,
int to) : from(from), to(to) {}
134 FromTo(
const FromTo &) =
delete;
135 FromTo &operator=(
const FromTo &) =
delete;
150 StartLen(
int start,
int len) : start(start), len(len) {}
151 StartLen(
const StartLen &) =
delete;
152 StartLen &operator=(
const StartLen &) =
delete;
203void rangeToJSON(JSONGenerator &
json,
int lo,
int hi);
204std::pair<int, int> rangeFromJSON(JSONLoader &
json);
243template <RangeUnit Unit, Endian Order>
244struct HalfOpenRange {
246 static constexpr Endian order = Order;
253 HalfOpenRange() :
lo(0),
hi(0) {}
255 HalfOpenRange(FromTo &&fromTo)
256 :
lo(fromTo.from),
hi(fromTo.to + 1) {}
257 HalfOpenRange(StartLen &&startLen)
258 :
lo(startLen.start),
hi(startLen.start + startLen.len) {}
259 HalfOpenRange(ZeroToMax &&)
260 :
lo(0),
hi(std::numeric_limits<int>::max()) {}
261 HalfOpenRange(MinToMax &&)
262 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max()) {}
263 explicit HalfOpenRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
266 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo); }
271 if (
empty())
return HalfOpenRange(0, 0);
279 if (
empty())
return HalfOpenRange<RangeUnit::Bit, Order>(0,
size);
281 return {asBits.lo, asBits.lo +
size};
287 const int resizedLo =
empty() ? 0 :
lo;
288 if (Unit == RangeUnit::Byte)
return {resizedLo, resizedLo +
size};
289 return {resizedLo, resizedLo +
size * 8};
296 if (
empty())
return HalfOpenRange<RangeUnit::Bit, Order>();
298 return {asBits.lo + offset, asBits.hi + offset};
305 if (
empty())
return HalfOpenRange();
306 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
307 return {
lo + offset * 8,
hi + offset * 8};
312 if (
empty())
return 0;
313 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
318 if (
empty())
return 0;
319 return Unit == RangeUnit::Byte ?
hi - 1 : BitRange::Detail::divideFloor(
hi - 1, 8);
330 return (
empty() || Unit == RangeUnit::Byte) ? true
331 : BitRange::Detail::moduloFloor(
lo, 8) == 0;
338 return (
empty() || Unit == RangeUnit::Byte) ? true
339 : BitRange::Detail::moduloFloor(
hi, 8) == 0;
344 return other.
lo ==
lo && other.
hi ==
hi;
346 bool operator!=(HalfOpenRange other)
const {
return !(*
this == other); }
370 if (rv.
hi <= rv.
lo)
return {0, 0};
373 HalfOpenRange operator&(HalfOpenRange a)
const {
return intersectWith(a); }
374 HalfOpenRange operator&=(HalfOpenRange a) {
385 if (
empty())
return {l, h};
386 if (l == h)
return *
this;
387 return HalfOpenRange(std::min(
lo, l), std::max(
hi, h));
389 HalfOpenRange operator|(HalfOpenRange a)
const {
return unionWith(a); }
390 HalfOpenRange operator|=(HalfOpenRange a) {
417 template <Endian DestOrder>
418 HalfOpenRange<Unit, DestOrder>
toOrder(
int spaceSize)
const {
419 if (DestOrder == Order)
return HalfOpenRange<Unit, DestOrder>(
lo,
hi);
421 case Endian::Network:
423 return HalfOpenRange<Unit, DestOrder>(spaceSize -
hi, spaceSize -
lo);
425 BUG(
"Unexpected ordering");
443 template <RangeUnit DestUnit>
444 HalfOpenRange<DestUnit, Order>
toUnit()
const {
445 if (DestUnit == Unit)
return HalfOpenRange<DestUnit, Order>(
lo,
hi);
446 if (
empty())
return HalfOpenRange<DestUnit, Order>();
449 return HalfOpenRange<DestUnit, Order>(
lo * 8,
hi * 8);
450 case RangeUnit::Byte:
453 BUG(
"Unexpected unit");
464 if (
lo != other.
lo)
return lo < other.
lo;
465 return hi < other.
hi;
503template <RangeUnit Unit, Endian Order>
506 static constexpr Endian order = Order;
513 ClosedRange() :
lo(0),
hi(0) {}
514 constexpr ClosedRange(
int lo,
int hi) :
lo(
lo),
hi(
hi) {}
515 ClosedRange(FromTo &&fromTo)
516 :
lo(fromTo.from),
hi(fromTo.to) {}
517 ClosedRange(StartLen &&startLen)
518 :
lo(startLen.start),
hi(startLen.start + startLen.len - 1) {}
519 ClosedRange(ZeroToMax &&)
520 :
lo(0),
hi(std::numeric_limits<int>::max() - 1) {}
521 ClosedRange(MinToMax &&)
522 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max() - 1) {}
523 explicit ClosedRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
526 BUG_CHECK(!r.
empty(),
"can't convert empty range to Closed");
530 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo) + 1; }
534 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
536 return {asBits.lo, asBits.lo +
size - 1};
541 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
542 if (Unit == RangeUnit::Byte)
return {
lo,
lo +
size - 1};
549 return {asBits.lo + offset, asBits.hi + offset};
554 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
555 return {
lo + offset * 8,
hi + offset * 8};
560 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
565 return Unit == RangeUnit::Byte ?
hi : BitRange::Detail::divideFloor(
hi, 8);
573 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
lo, 8) == 0;
578 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
hi + 1, 8) == 0;
582 bool operator!=(ClosedRange other)
const {
return !(*
this == other); }
585 bool contains(
int index)
const {
return (index >=
lo) && (index <=
hi); }
590 return intersection.lo == other.
lo && intersection.size() == other.
size();
608 HalfOpenRange<Unit, Order> operator&(ClosedRange a)
const {
return intersectWith(a); }
609 HalfOpenRange<Unit, Order> operator&=(ClosedRange a) {
619 ClosedRange operator|(ClosedRange a)
const {
return unionWith(a); }
620 ClosedRange operator|=(ClosedRange a) {
626 template <Endian DestOrder>
627 ClosedRange<Unit, DestOrder>
toOrder(
int spaceSize)
const {
628 BUG_CHECK(spaceSize > 0,
"Can't represent an empty range");
629 if (DestOrder == Order)
return ClosedRange<Unit, DestOrder>(
lo,
hi);
631 case Endian::Network:
633 return ClosedRange<Unit, DestOrder>((spaceSize - 1) -
hi, (spaceSize - 1) -
lo);
635 BUG(
"Unexpected ordering");
639 template <RangeUnit DestUnit>
640 ClosedRange<DestUnit, Order>
toUnit()
const {
641 if (DestUnit == Unit)
return ClosedRange<DestUnit, Order>(
lo,
hi);
644 return ClosedRange<DestUnit, Order>(
lo * 8,
hi * 8 + 7);
645 case RangeUnit::Byte:
646 return ClosedRange<DestUnit, Order>(
loByte(),
hiByte());
648 BUG(
"Unexpected unit");
659 if (
lo != other.
lo)
return lo < other.
lo;
660 return hi < other.
hi;
671 if (Unit == RangeUnit::Byte) {
675 BUG_CHECK(Unit == RangeUnit::Bit,
"mismatch range units");
677 std::stringstream out;
678 out <<
"[" <<
hi <<
":" <<
lo <<
"]";
706template <RangeUnit Unit, Endian Order>
711 if (intersect.
empty())
712 return left.
lo < right.
lo ? std::make_pair(left, empty) : std::make_pair(empty, left);
719 return {lower, upper};
724template <RangeUnit Unit, Endian Order>
732template <RangeUnit Unit, Endian Order>
739template <RangeUnit Unit, Endian Order>
741 if (halfOpenRange.
empty())
return std::nullopt;
761std::ostream &toStream(std::ostream &out,
RangeUnit unit,
Endian order,
int lo,
int hi,
764template <RangeUnit Unit, Endian Order>
766 return toStream(out, Unit, Order, range.
lo, range.
hi,
false);
769template <RangeUnit Unit, Endian Order>
770std::ostream &operator<<(std::ostream &out,
const ClosedRange<Unit, Order> &range) {
771 return toStream(out, Unit, Order, range.lo, range.hi,
true);
778template <P4::RangeUnit Unit, P4::Endian Order>
779struct hash<
P4::HalfOpenRange<Unit, Order>> {
785template <P4::RangeUnit Unit, P4::Endian Order>
786struct hash<
P4::ClosedRange<Unit, Order>> {
794template <RangeUnit Unit, Endian Order>
801template <RangeUnit Unit, Endian Order>
Definition json_generator.h:30
Definition json_loader.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
HalfOpenRange< RangeUnit::Byte, Endian::Network > nw_byteinterval
Convenience typedefs for half-open ranges in bytes.
Definition lib/bitrange.h:758
ClosedRange< RangeUnit::Bit, Endian::Network > nw_bitrange
Convenience typedefs for closed ranges in bits.
Definition lib/bitrange.h:746
Endian
An ordering for bits or bytes.
Definition lib/bitrange.h:215
@ Little
Most significant bit/byte first.
Definition lib/bitrange.h:217
std::optional< ClosedRange< Unit, Order > > toClosedRange(HalfOpenRange< Unit, Order > halfOpenRange)
Definition lib/bitrange.h:740
ClosedRange< RangeUnit::Byte, Endian::Network > nw_byterange
Convenience typedefs for closed ranges in bytes.
Definition lib/bitrange.h:750
HalfOpenRange< RangeUnit::Bit, Endian::Network > nw_bitinterval
Convenience typedefs for half-open ranges in bits.
Definition lib/bitrange.h:754
RangeUnit
Units in which a range can be specified.
Definition lib/bitrange.h:209
std::pair< HalfOpenRange< Unit, Order >, HalfOpenRange< Unit, Order > > operator-(HalfOpenRange< Unit, Order > left, HalfOpenRange< Unit, Order > right)
Definition lib/bitrange.h:707
HalfOpenRange< Unit, Order > toHalfOpenRange(ClosedRange< Unit, Order > closedRange)
Definition lib/bitrange.h:733
Definition lib/bitrange.h:132
Definition lib/bitrange.h:200
Definition lib/bitrange.h:149
Definition lib/bitrange.h:181
Definition lib/bitrange.h:504
bool isHiAligned() const
Definition lib/bitrange.h:577
bool contains(ClosedRange other) const
Definition lib/bitrange.h:588
ClosedRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:640
bool overlaps(ClosedRange a) const
Definition lib/bitrange.h:594
ClosedRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:627
int loByte() const
Definition lib/bitrange.h:559
ClosedRange resizedToBytes(int size) const
Definition lib/bitrange.h:540
bool isLoAligned() const
Definition lib/bitrange.h:572
int hiByte() const
Definition lib/bitrange.h:564
HalfOpenRange< Unit, Order > intersectWith(ClosedRange a) const
Definition lib/bitrange.h:601
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:652
ClosedRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:547
ClosedRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:533
cstring formatAsSlice(int spaceSize) const
Definition lib/bitrange.h:667
ClosedRange shiftedByBytes(int offset) const
Definition lib/bitrange.h:553
int lo
Definition lib/bitrange.h:685
ssize_t size() const
Definition lib/bitrange.h:530
bool operator<(const ClosedRange &other) const
Definition lib/bitrange.h:658
int hi
Definition lib/bitrange.h:691
bool contains(int index) const
Definition lib/bitrange.h:585
ClosedRange unionWith(ClosedRange a) const
Definition lib/bitrange.h:615
int nextByte() const
Definition lib/bitrange.h:569
Definition lib/bitrange.h:244
bool contains(int index) const
Definition lib/bitrange.h:352
int hi
Definition lib/bitrange.h:479
bool operator<(const HalfOpenRange &other) const
Total ordering, first by lo, then by hi.
Definition lib/bitrange.h:463
int hiByte() const
Definition lib/bitrange.h:317
HalfOpenRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:418
bool isHiAligned() const
Definition lib/bitrange.h:337
bool overlaps(HalfOpenRange a) const
Definition lib/bitrange.h:361
int nextByte() const
Definition lib/bitrange.h:325
HalfOpenRange< Unit, Order > shiftedByBytes(int offset) const
Definition lib/bitrange.h:304
bool contains(HalfOpenRange other) const
Definition lib/bitrange.h:356
bool isLoAligned() const
Definition lib/bitrange.h:329
HalfOpenRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:444
int loByte() const
Definition lib/bitrange.h:311
ssize_t size() const
Definition lib/bitrange.h:266
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:457
HalfOpenRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:278
bool empty() const
Definition lib/bitrange.h:349
HalfOpenRange unionWith(HalfOpenRange a) const
Definition lib/bitrange.h:383
HalfOpenRange canonicalize() const
Definition lib/bitrange.h:270
int lo
Definition lib/bitrange.h:473
HalfOpenRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:295
HalfOpenRange resizedToBytes(int size) const
Definition lib/bitrange.h:286
HalfOpenRange intersectWith(HalfOpenRange a) const
Definition lib/bitrange.h:367