17#ifndef LIB_BITRANGE_H_
18#define LIB_BITRANGE_H_
26#include "absl/numeric/bits.h"
28#include "exceptions.h"
40 std::pair<int, int> range;
44 range.first = range.second = ptr.index();
45 while (++ptr && range.second + 1 == ptr.index()) ++range.second;
51 std::pair<int, int> operator*() {
return range; }
52 bool operator==(iter &a)
const {
return valid == a.valid && ptr == a.ptr; }
53 bool operator!=(iter &a)
const {
return !(*
this == a); }
60 explicit bitranges(uintptr_t b) : tmp(b), bits(tmp) {}
61 iter begin()
const {
return iter(bits.begin()); }
62 iter end()
const {
return iter(bits.end()); }
77constexpr inline int divideFloor(
int dividend,
int divisor) {
78#if defined(__GNUC__) || defined(__clang__)
82 unsigned u_divisor =
static_cast<unsigned>(divisor);
83 if (__builtin_constant_p(u_divisor) && absl::has_single_bit(u_divisor))
84 return dividend >> (absl::bit_width(u_divisor) - 1);
87 const int quotient = dividend / divisor;
88 const int remainder = dividend % divisor;
89 if ((remainder != 0) && ((remainder < 0) != (divisor < 0)))
return quotient - 1;
100constexpr int modulo(
int dividend,
int divisor) {
101 return (dividend % divisor) * ((dividend < 0) != (divisor < 0) ? -1 : 1);
117constexpr inline int moduloFloor(
const int dividend,
const int divisor) {
118#if defined(__GNUC__) || defined(__clang__)
122 if (__builtin_constant_p(divisor) && absl::has_single_bit(
static_cast<unsigned>(divisor)))
123 return dividend & (divisor - 1);
126 const int remainder = modulo(dividend, divisor);
127 if (remainder == 0 || dividend >= 0)
return remainder;
128 return divisor - remainder;
142 FromTo(
int from,
int to) : from(from), to(to) {}
159 StartLen(
int start,
int len) : start(start), len(len) {}
213std::pair<int, int> rangeFromJSON(
JSONLoader &json);
252template <RangeUnit Unit, Endian Order>
255 static constexpr Endian order = Order;
265 :
lo(fromTo.from),
hi(fromTo.to + 1) {}
267 :
lo(startLen.start),
hi(startLen.start + startLen.len) {}
269 :
lo(0),
hi(std::numeric_limits<int>::max()) {}
271 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max()) {}
272 explicit HalfOpenRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
275 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo); }
290 return {asBits.lo, asBits.lo +
size};
296 const int resizedLo =
empty() ? 0 :
lo;
297 if (Unit == RangeUnit::Byte)
return {resizedLo, resizedLo +
size};
298 return {resizedLo, resizedLo +
size * 8};
307 return {asBits.lo + offset, asBits.hi + offset};
315 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
316 return {
lo + offset * 8,
hi + offset * 8};
321 if (
empty())
return 0;
322 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
327 if (
empty())
return 0;
328 return Unit == RangeUnit::Byte ?
hi - 1 : BitRange::Detail::divideFloor(
hi - 1, 8);
339 return (
empty() || Unit == RangeUnit::Byte) ? true
340 : BitRange::Detail::moduloFloor(
lo, 8) == 0;
347 return (
empty() || Unit == RangeUnit::Byte) ? true
348 : BitRange::Detail::moduloFloor(
hi, 8) == 0;
353 return other.
lo ==
lo && other.
hi ==
hi;
355 bool operator!=(HalfOpenRange other)
const {
return !(*
this == other); }
379 if (rv.
hi <= rv.
lo)
return {0, 0};
382 HalfOpenRange operator&(HalfOpenRange a)
const {
return intersectWith(a); }
383 HalfOpenRange operator&=(HalfOpenRange a) {
394 if (
empty())
return {l, h};
395 if (l == h)
return *
this;
396 return HalfOpenRange(std::min(
lo, l), std::max(
hi, h));
398 HalfOpenRange operator|(HalfOpenRange a)
const {
return unionWith(a); }
399 HalfOpenRange operator|=(HalfOpenRange a) {
426 template <Endian DestOrder>
430 case Endian::Network:
434 BUG(
"Unexpected ordering");
452 template <RangeUnit DestUnit>
459 case RangeUnit::Byte:
462 BUG(
"Unexpected unit");
473 if (
lo != other.
lo)
return lo < other.
lo;
474 return hi < other.
hi;
512template <RangeUnit Unit, Endian Order>
515 static constexpr Endian order = Order;
525 :
lo(fromTo.from),
hi(fromTo.to) {}
527 :
lo(startLen.start),
hi(startLen.start + startLen.len - 1) {}
529 :
lo(0),
hi(std::numeric_limits<int>::max() - 1) {}
531 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max() - 1) {}
532 explicit ClosedRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
535 BUG_CHECK(!r.
empty(),
"can't convert empty range to Closed");
539 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo) + 1; }
543 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
545 return {asBits.lo, asBits.lo +
size - 1};
550 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
551 if (Unit == RangeUnit::Byte)
return {
lo,
lo +
size - 1};
558 return {asBits.lo + offset, asBits.hi + offset};
563 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
564 return {
lo + offset * 8,
hi + offset * 8};
569 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
574 return Unit == RangeUnit::Byte ?
hi : BitRange::Detail::divideFloor(
hi, 8);
582 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
lo, 8) == 0;
587 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
hi + 1, 8) == 0;
591 bool operator!=(ClosedRange other)
const {
return !(*
this == other); }
594 bool contains(
int index)
const {
return (index >=
lo) && (index <=
hi); }
599 return intersection.lo == other.
lo && intersection.size() == other.
size();
617 HalfOpenRange<Unit, Order> operator&(ClosedRange a)
const {
return intersectWith(a); }
618 HalfOpenRange<Unit, Order> operator&=(ClosedRange a) {
628 ClosedRange operator|(ClosedRange a)
const {
return unionWith(a); }
629 ClosedRange operator|=(ClosedRange a) {
635 template <Endian DestOrder>
637 BUG_CHECK(spaceSize > 0,
"Can't represent an empty range");
640 case Endian::Network:
644 BUG(
"Unexpected ordering");
648 template <RangeUnit DestUnit>
654 case RangeUnit::Byte:
657 BUG(
"Unexpected unit");
668 if (
lo != other.
lo)
return lo < other.
lo;
669 return hi < other.
hi;
680 if (Unit == RangeUnit::Byte) {
684 BUG_CHECK(Unit == RangeUnit::Bit,
"mismatch range units");
686 std::stringstream out;
687 out <<
"[" <<
hi <<
":" <<
lo <<
"]";
715template <RangeUnit Unit, Endian Order>
720 if (intersect.
empty())
721 return left.
lo < right.
lo ? std::make_pair(left, empty) : std::make_pair(empty, left);
728 return {lower, upper};
733template <RangeUnit Unit, Endian Order>
741template <RangeUnit Unit, Endian Order>
748template <RangeUnit Unit, Endian Order>
750 if (halfOpenRange.
empty())
return std::nullopt;
770std::ostream &toStream(std::ostream &out,
RangeUnit unit,
Endian order,
int lo,
int hi,
773template <RangeUnit Unit, Endian Order>
775 return toStream(out, Unit, Order, range.
lo, range.
hi,
false);
778template <RangeUnit Unit, Endian Order>
779std::ostream &operator<<(std::ostream &out,
const ClosedRange<Unit, Order> &range) {
780 return toStream(out, Unit, Order, range.lo, range.hi,
true);
787template <P4::RangeUnit Unit, P4::Endian Order>
788struct hash<
P4::HalfOpenRange<Unit, Order>> {
794template <P4::RangeUnit Unit, P4::Endian Order>
795struct hash<
P4::ClosedRange<Unit, Order>> {
803template <RangeUnit Unit, Endian Order>
810template <RangeUnit Unit, Endian Order>
Definition json_generator.h:37
Definition json_loader.h:39
Definition lib/bitrange.h:34
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Endian
An ordering for bits or bytes.
Definition lib/bitrange.h:224
@ Little
Most significant bit/byte first.
std::optional< ClosedRange< Unit, Order > > toClosedRange(HalfOpenRange< Unit, Order > halfOpenRange)
Definition lib/bitrange.h:749
RangeUnit
Units in which a range can be specified.
Definition lib/bitrange.h:218
std::pair< HalfOpenRange< Unit, Order >, HalfOpenRange< Unit, Order > > operator-(HalfOpenRange< Unit, Order > left, HalfOpenRange< Unit, Order > right)
Definition lib/bitrange.h:716
HalfOpenRange< Unit, Order > toHalfOpenRange(ClosedRange< Unit, Order > closedRange)
Definition lib/bitrange.h:742
Definition lib/bitrange.h:141
Definition lib/bitrange.h:209
Definition lib/bitrange.h:158
Definition lib/bitrange.h:190
Definition lib/bitrange.h:513
bool isHiAligned() const
Definition lib/bitrange.h:586
bool contains(ClosedRange other) const
Definition lib/bitrange.h:597
ClosedRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:649
bool overlaps(ClosedRange a) const
Definition lib/bitrange.h:603
ClosedRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:636
int loByte() const
Definition lib/bitrange.h:568
ClosedRange resizedToBytes(int size) const
Definition lib/bitrange.h:549
bool isLoAligned() const
Definition lib/bitrange.h:581
int hiByte() const
Definition lib/bitrange.h:573
HalfOpenRange< Unit, Order > intersectWith(ClosedRange a) const
Definition lib/bitrange.h:610
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:661
ClosedRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:556
ClosedRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:542
cstring formatAsSlice(int spaceSize) const
Definition lib/bitrange.h:676
ClosedRange shiftedByBytes(int offset) const
Definition lib/bitrange.h:562
int lo
Definition lib/bitrange.h:694
ssize_t size() const
Definition lib/bitrange.h:539
bool operator<(const ClosedRange &other) const
Definition lib/bitrange.h:667
int hi
Definition lib/bitrange.h:700
bool contains(int index) const
Definition lib/bitrange.h:594
ClosedRange unionWith(ClosedRange a) const
Definition lib/bitrange.h:624
int nextByte() const
Definition lib/bitrange.h:578
Definition lib/bitrange.h:253
bool contains(int index) const
Definition lib/bitrange.h:361
int hi
Definition lib/bitrange.h:488
bool operator<(const HalfOpenRange &other) const
Total ordering, first by lo, then by hi.
Definition lib/bitrange.h:472
int hiByte() const
Definition lib/bitrange.h:326
HalfOpenRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition lib/bitrange.h:427
bool isHiAligned() const
Definition lib/bitrange.h:346
bool overlaps(HalfOpenRange a) const
Definition lib/bitrange.h:370
int nextByte() const
Definition lib/bitrange.h:334
HalfOpenRange< Unit, Order > shiftedByBytes(int offset) const
Definition lib/bitrange.h:313
bool contains(HalfOpenRange other) const
Definition lib/bitrange.h:365
bool isLoAligned() const
Definition lib/bitrange.h:338
HalfOpenRange< DestUnit, Order > toUnit() const
Definition lib/bitrange.h:453
int loByte() const
Definition lib/bitrange.h:320
ssize_t size() const
Definition lib/bitrange.h:275
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition lib/bitrange.h:466
HalfOpenRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition lib/bitrange.h:287
bool empty() const
Definition lib/bitrange.h:358
HalfOpenRange unionWith(HalfOpenRange a) const
Definition lib/bitrange.h:392
HalfOpenRange canonicalize() const
Definition lib/bitrange.h:279
int lo
Definition lib/bitrange.h:482
HalfOpenRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition lib/bitrange.h:304
HalfOpenRange resizedToBytes(int size) const
Definition lib/bitrange.h:295
HalfOpenRange intersectWith(HalfOpenRange a) const
Definition lib/bitrange.h:376