17#include "absl/numeric/bits.h"
20#include "exceptions.h"
32 std::pair<int, int> range;
36 range.first = range.second = ptr.index();
37 while (++ptr && range.second + 1 == ptr.index()) ++range.second;
43 std::pair<int, int> operator*() {
return range; }
44 bool operator==(iter &a)
const {
return valid == a.valid && ptr == a.ptr; }
45 bool operator!=(iter &a)
const {
return !(*
this == a); }
50 explicit bitranges(
const bitvec &b) : bits(b) {}
51 explicit bitranges(
bitvec &&b) : tmp(b), bits(tmp) {}
52 explicit bitranges(uintptr_t b) : tmp(b), bits(tmp) {}
53 iter begin()
const {
return iter(bits.begin()); }
54 iter end()
const {
return iter(bits.end()); }
69constexpr inline int divideFloor(
int dividend,
int divisor) {
70#if defined(__GNUC__) || defined(__clang__)
74 unsigned u_divisor =
static_cast<unsigned>(divisor);
75 if (__builtin_constant_p(u_divisor) && absl::has_single_bit(u_divisor))
76 return dividend >> (absl::bit_width(u_divisor) - 1);
79 const int quotient = dividend / divisor;
80 const int remainder = dividend % divisor;
81 if ((remainder != 0) && ((remainder < 0) != (divisor < 0)))
return quotient - 1;
92constexpr int modulo(
int dividend,
int divisor) {
93 return (dividend % divisor) * ((dividend < 0) != (divisor < 0) ? -1 : 1);
109constexpr inline int moduloFloor(
const int dividend,
const int divisor) {
110#if defined(__GNUC__) || defined(__clang__)
114 if (__builtin_constant_p(divisor) && absl::has_single_bit(
static_cast<unsigned>(divisor)))
115 return dividend & (divisor - 1);
118 const int remainder = modulo(dividend, divisor);
119 if (remainder == 0 || dividend >= 0)
return remainder;
120 return divisor - remainder;
134 FromTo(
int from,
int to) : from(from), to(to) {}
135 FromTo(
const FromTo &) =
delete;
136 FromTo &operator=(
const FromTo &) =
delete;
151 StartLen(
int start,
int len) : start(start), len(len) {}
152 StartLen(
const StartLen &) =
delete;
153 StartLen &operator=(
const StartLen &) =
delete;
204void rangeToJSON(JSONGenerator &
json,
int lo,
int hi);
205std::pair<int, int> rangeFromJSON(JSONLoader &
json);
244template <RangeUnit Unit, Endian Order>
245struct HalfOpenRange {
247 static constexpr Endian order = Order;
254 HalfOpenRange() :
lo(0),
hi(0) {}
256 HalfOpenRange(FromTo &&fromTo)
257 :
lo(fromTo.from),
hi(fromTo.to + 1) {}
258 HalfOpenRange(StartLen &&startLen)
259 :
lo(startLen.start),
hi(startLen.start + startLen.len) {}
260 HalfOpenRange(ZeroToMax &&)
261 :
lo(0),
hi(std::numeric_limits<int>::max()) {}
262 HalfOpenRange(MinToMax &&)
263 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max()) {}
264 explicit HalfOpenRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
267 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo); }
272 if (
empty())
return HalfOpenRange(0, 0);
280 if (
empty())
return HalfOpenRange<RangeUnit::Bit, Order>(0,
size);
282 return {asBits.lo, asBits.lo +
size};
288 const int resizedLo =
empty() ? 0 :
lo;
289 if (Unit == RangeUnit::Byte)
return {resizedLo, resizedLo +
size};
290 return {resizedLo, resizedLo +
size * 8};
297 if (
empty())
return HalfOpenRange<RangeUnit::Bit, Order>();
299 return {asBits.lo + offset, asBits.hi + offset};
306 if (
empty())
return HalfOpenRange();
307 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
308 return {
lo + offset * 8,
hi + offset * 8};
313 if (
empty())
return 0;
314 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
319 if (
empty())
return 0;
320 return Unit == RangeUnit::Byte ?
hi - 1 : BitRange::Detail::divideFloor(
hi - 1, 8);
331 return (
empty() || Unit == RangeUnit::Byte) ? true
332 : BitRange::Detail::moduloFloor(
lo, 8) == 0;
339 return (
empty() || Unit == RangeUnit::Byte) ? true
340 : BitRange::Detail::moduloFloor(
hi, 8) == 0;
345 return other.
lo ==
lo && other.
hi ==
hi;
347 bool operator!=(HalfOpenRange other)
const {
return !(*
this == other); }
371 if (rv.
hi <= rv.
lo)
return {0, 0};
374 HalfOpenRange operator&(HalfOpenRange a)
const {
return intersectWith(a); }
375 HalfOpenRange operator&=(HalfOpenRange a) {
386 if (
empty())
return {l, h};
387 if (l == h)
return *
this;
388 return HalfOpenRange(std::min(
lo, l), std::max(
hi, h));
390 HalfOpenRange operator|(HalfOpenRange a)
const {
return unionWith(a); }
391 HalfOpenRange operator|=(HalfOpenRange a) {
418 template <Endian DestOrder>
419 HalfOpenRange<Unit, DestOrder>
toOrder(
int spaceSize)
const {
420 if (DestOrder == Order)
return HalfOpenRange<Unit, DestOrder>(
lo,
hi);
422 case Endian::Network:
424 return HalfOpenRange<Unit, DestOrder>(spaceSize -
hi, spaceSize -
lo);
426 BUG(
"Unexpected ordering");
444 template <RangeUnit DestUnit>
445 HalfOpenRange<DestUnit, Order>
toUnit()
const {
446 if (DestUnit == Unit)
return HalfOpenRange<DestUnit, Order>(
lo,
hi);
447 if (
empty())
return HalfOpenRange<DestUnit, Order>();
450 return HalfOpenRange<DestUnit, Order>(
lo * 8,
hi * 8);
451 case RangeUnit::Byte:
454 BUG(
"Unexpected unit");
465 if (
lo != other.
lo)
return lo < other.
lo;
466 return hi < other.
hi;
504template <RangeUnit Unit, Endian Order>
507 static constexpr Endian order = Order;
514 ClosedRange() :
lo(0),
hi(0) {}
515 constexpr ClosedRange(
int lo,
int hi) :
lo(
lo),
hi(
hi) {}
516 ClosedRange(FromTo &&fromTo)
517 :
lo(fromTo.from),
hi(fromTo.to) {}
518 ClosedRange(StartLen &&startLen)
519 :
lo(startLen.start),
hi(startLen.start + startLen.len - 1) {}
520 ClosedRange(ZeroToMax &&)
521 :
lo(0),
hi(std::numeric_limits<int>::max() - 1) {}
522 ClosedRange(MinToMax &&)
523 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max() - 1) {}
524 explicit ClosedRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
527 BUG_CHECK(!r.
empty(),
"can't convert empty range to Closed");
531 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo) + 1; }
535 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
537 return {asBits.lo, asBits.lo +
size - 1};
542 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
543 if (Unit == RangeUnit::Byte)
return {
lo,
lo +
size - 1};
550 return {asBits.lo + offset, asBits.hi + offset};
555 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
556 return {
lo + offset * 8,
hi + offset * 8};
561 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
566 return Unit == RangeUnit::Byte ?
hi : BitRange::Detail::divideFloor(
hi, 8);
574 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
lo, 8) == 0;
579 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
hi + 1, 8) == 0;
583 bool operator!=(ClosedRange other)
const {
return !(*
this == other); }
586 bool contains(
int index)
const {
return (index >=
lo) && (index <=
hi); }
591 return intersection.lo == other.
lo && intersection.size() == other.
size();
609 HalfOpenRange<Unit, Order> operator&(ClosedRange a)
const {
return intersectWith(a); }
610 HalfOpenRange<Unit, Order> operator&=(ClosedRange a) {
620 ClosedRange operator|(ClosedRange a)
const {
return unionWith(a); }
621 ClosedRange operator|=(ClosedRange a) {
627 template <Endian DestOrder>
628 ClosedRange<Unit, DestOrder>
toOrder(
int spaceSize)
const {
629 BUG_CHECK(spaceSize > 0,
"Can't represent an empty range");
630 if (DestOrder == Order)
return ClosedRange<Unit, DestOrder>(
lo,
hi);
632 case Endian::Network:
634 return ClosedRange<Unit, DestOrder>((spaceSize - 1) -
hi, (spaceSize - 1) -
lo);
636 BUG(
"Unexpected ordering");
640 template <RangeUnit DestUnit>
641 ClosedRange<DestUnit, Order>
toUnit()
const {
642 if (DestUnit == Unit)
return ClosedRange<DestUnit, Order>(
lo,
hi);
645 return ClosedRange<DestUnit, Order>(
lo * 8,
hi * 8 + 7);
646 case RangeUnit::Byte:
647 return ClosedRange<DestUnit, Order>(
loByte(),
hiByte());
649 BUG(
"Unexpected unit");
660 if (
lo != other.
lo)
return lo < other.
lo;
661 return hi < other.
hi;
672 if (Unit == RangeUnit::Byte) {
676 BUG_CHECK(Unit == RangeUnit::Bit,
"mismatch range units");
678 std::stringstream out;
679 out <<
"[" <<
hi <<
":" <<
lo <<
"]";
707template <RangeUnit Unit, Endian Order>
712 if (intersect.
empty())
713 return left.
lo < right.
lo ? std::make_pair(left, empty) : std::make_pair(empty, left);
720 return {lower, upper};
725template <RangeUnit Unit, Endian Order>
733template <RangeUnit Unit, Endian Order>
740template <RangeUnit Unit, Endian Order>
742 if (halfOpenRange.
empty())
return std::nullopt;
762std::ostream &toStream(std::ostream &out,
RangeUnit unit,
Endian order,
int lo,
int hi,
765template <RangeUnit Unit, Endian Order>
767 return toStream(out, Unit, Order, range.
lo, range.
hi,
false);
770template <RangeUnit Unit, Endian Order>
771std::ostream &operator<<(std::ostream &out,
const ClosedRange<Unit, Order> &range) {
772 return toStream(out, Unit, Order, range.lo, range.hi,
true);
779template <P4::RangeUnit Unit, P4::Endian Order>
780struct hash<
P4::HalfOpenRange<Unit, Order>> {
786template <P4::RangeUnit Unit, P4::Endian Order>
787struct hash<
P4::ClosedRange<Unit, Order>> {
795template <RangeUnit Unit, Endian Order>
802template <RangeUnit Unit, Endian Order>
Definition json_generator.h:30
Definition json_loader.h:34
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:759
ClosedRange< RangeUnit::Bit, Endian::Network > nw_bitrange
Convenience typedefs for closed ranges in bits.
Definition lib/bitrange.h:747
Endian
An ordering for bits or bytes.
Definition lib/bitrange.h:216
@ Little
Most significant bit/byte first.
Definition lib/bitrange.h:218
std::optional< ClosedRange< Unit, Order > > toClosedRange(HalfOpenRange< Unit, Order > halfOpenRange)
Definition lib/bitrange.h:741
ClosedRange< RangeUnit::Byte, Endian::Network > nw_byterange
Convenience typedefs for closed ranges in bytes.
Definition lib/bitrange.h:751
HalfOpenRange< RangeUnit::Bit, Endian::Network > nw_bitinterval
Convenience typedefs for half-open ranges in bits.
Definition lib/bitrange.h:755
RangeUnit
Units in which a range can be specified.
Definition lib/bitrange.h:210
std::pair< HalfOpenRange< Unit, Order >, HalfOpenRange< Unit, Order > > operator-(HalfOpenRange< Unit, Order > left, HalfOpenRange< Unit, Order > right)
Definition lib/bitrange.h:708
HalfOpenRange< Unit, Order > toHalfOpenRange(ClosedRange< Unit, Order > closedRange)
Definition lib/bitrange.h:734
Definition lib/bitrange.h:133
Definition lib/bitrange.h:201
Definition lib/bitrange.h:150
Definition lib/bitrange.h:182
Definition lib/bitrange.h:505
bool isHiAligned() const
Definition lib/bitrange.h:578
bool contains(ClosedRange other) const
Definition lib/bitrange.h:589
ClosedRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:641
bool overlaps(ClosedRange a) const
Definition lib/bitrange.h:595
ClosedRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:628
int loByte() const
Definition lib/bitrange.h:560
ClosedRange resizedToBytes(int size) const
Definition lib/bitrange.h:541
bool isLoAligned() const
Definition lib/bitrange.h:573
int hiByte() const
Definition lib/bitrange.h:565
HalfOpenRange< Unit, Order > intersectWith(ClosedRange a) const
Definition lib/bitrange.h:602
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:653
ClosedRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:548
ClosedRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:534
cstring formatAsSlice(int spaceSize) const
Definition lib/bitrange.h:668
ClosedRange shiftedByBytes(int offset) const
Definition lib/bitrange.h:554
int lo
Definition lib/bitrange.h:686
ssize_t size() const
Definition lib/bitrange.h:531
bool operator<(const ClosedRange &other) const
Definition lib/bitrange.h:659
int hi
Definition lib/bitrange.h:692
bool contains(int index) const
Definition lib/bitrange.h:586
ClosedRange unionWith(ClosedRange a) const
Definition lib/bitrange.h:616
int nextByte() const
Definition lib/bitrange.h:570
Definition lib/bitrange.h:245
bool contains(int index) const
Definition lib/bitrange.h:353
int hi
Definition lib/bitrange.h:480
bool operator<(const HalfOpenRange &other) const
Total ordering, first by lo, then by hi.
Definition lib/bitrange.h:464
int hiByte() const
Definition lib/bitrange.h:318
HalfOpenRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:419
bool isHiAligned() const
Definition lib/bitrange.h:338
bool overlaps(HalfOpenRange a) const
Definition lib/bitrange.h:362
int nextByte() const
Definition lib/bitrange.h:326
HalfOpenRange< Unit, Order > shiftedByBytes(int offset) const
Definition lib/bitrange.h:305
bool contains(HalfOpenRange other) const
Definition lib/bitrange.h:357
bool isLoAligned() const
Definition lib/bitrange.h:330
HalfOpenRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:445
int loByte() const
Definition lib/bitrange.h:312
ssize_t size() const
Definition lib/bitrange.h:267
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:458
HalfOpenRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:279
bool empty() const
Definition lib/bitrange.h:350
HalfOpenRange unionWith(HalfOpenRange a) const
Definition lib/bitrange.h:384
HalfOpenRange canonicalize() const
Definition lib/bitrange.h:271
int lo
Definition lib/bitrange.h:474
HalfOpenRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:296
HalfOpenRange resizedToBytes(int size) const
Definition lib/bitrange.h:287
HalfOpenRange intersectWith(HalfOpenRange a) const
Definition lib/bitrange.h:368