17#ifndef LIB_BITRANGE_H_ 
   18#define LIB_BITRANGE_H_ 
   26#include "absl/numeric/bits.h" 
   28#include "exceptions.h" 
   38        std::pair<int, int> range;
 
   42                range.first = range.second = ptr.index();
 
   43                while (++ptr && range.second + 1 == ptr.index()) ++range.second;
 
   49        std::pair<int, int> operator*() { 
return range; }
 
   50        bool operator==(iter &a)
 const { 
return valid == a.valid && ptr == a.ptr; }
 
   51        bool operator!=(iter &a)
 const { 
return !(*
this == a); }
 
   58    explicit bitranges(uintptr_t b) : tmp(b), bits(tmp) {}
 
   59    iter begin()
 const { 
return iter(bits.begin()); }
 
   60    iter end()
 const { 
return iter(bits.end()); }
 
 
   75constexpr inline int divideFloor(
int dividend, 
int divisor) {
 
   76#if defined(__GNUC__) || defined(__clang__) 
   80    unsigned u_divisor = 
static_cast<unsigned>(divisor);
 
   81    if (__builtin_constant_p(u_divisor) && absl::has_single_bit(u_divisor))
 
   82        return dividend >> (absl::bit_width(u_divisor) - 1);
 
   85    const int quotient = dividend / divisor;
 
   86    const int remainder = dividend % divisor;
 
   87    if ((remainder != 0) && ((remainder < 0) != (divisor < 0))) 
return quotient - 1;
 
   98constexpr int modulo(
int dividend, 
int divisor) {
 
   99    return (dividend % divisor) * ((dividend < 0) != (divisor < 0) ? -1 : 1);
 
  115constexpr inline int moduloFloor(
const int dividend, 
const int divisor) {
 
  116#if defined(__GNUC__) || defined(__clang__) 
  120    if (__builtin_constant_p(divisor) && absl::has_single_bit(
static_cast<unsigned>(divisor)))
 
  121        return dividend & (divisor - 1);
 
  124    const int remainder = modulo(dividend, divisor);
 
  125    if (remainder == 0 || dividend >= 0) 
return remainder;
 
  126    return divisor - remainder;
 
  140    FromTo(
int from, 
int to) : from(from), to(to) {}
 
 
  157    StartLen(
int start, 
int len) : start(start), len(len) {}
 
 
  211std::pair<int, int> rangeFromJSON(
JSONLoader &json);
 
  216enum class RangeUnit : uint8_t {
 
  222enum class Endian : uint8_t {
 
  250template <RangeUnit Unit, Endian Order>
 
  252    static constexpr RangeUnit unit = Unit;
 
  253    static constexpr Endian order = Order;
 
  263        : 
lo(fromTo.from), 
hi(fromTo.to + 1) {}
 
  265        : 
lo(startLen.start), 
hi(startLen.start + startLen.len) {}
 
  267        : 
lo(0), 
hi(std::numeric_limits<int>::max()) {}
 
  269        : 
lo(std::numeric_limits<int>::min()), 
hi(std::numeric_limits<int>::max()) {}
 
  270    explicit HalfOpenRange(std::pair<int, int> range) : 
lo(range.first), 
hi(range.second) {}
 
  273    ssize_t 
size()
 const { 
return ssize_t(
hi) - ssize_t(
lo); }
 
  288        return {asBits.lo, asBits.lo + 
size};
 
 
  294        const int resizedLo = 
empty() ? 0 : 
lo;
 
  295        if (Unit == RangeUnit::Byte) 
return {resizedLo, resizedLo + 
size};
 
  296        return {resizedLo, resizedLo + 
size * 8};
 
 
  305        return {asBits.lo + offset, asBits.hi + offset};
 
 
  313        if (Unit == RangeUnit::Byte) 
return {
lo + offset, 
hi + offset};
 
  314        return {
lo + offset * 8, 
hi + offset * 8};
 
 
  319        if (
empty()) 
return 0;
 
  320        return Unit == RangeUnit::Byte ? 
lo : BitRange::Detail::divideFloor(
lo, 8);
 
 
  325        if (
empty()) 
return 0;
 
  326        return Unit == RangeUnit::Byte ? 
hi - 1 : BitRange::Detail::divideFloor(
hi - 1, 8);
 
 
  337        return (
empty() || Unit == RangeUnit::Byte) ? true
 
  338                                                    : BitRange::Detail::moduloFloor(
lo, 8) == 0;
 
 
  345        return (
empty() || Unit == RangeUnit::Byte) ? true
 
  346                                                    : BitRange::Detail::moduloFloor(
hi, 8) == 0;
 
 
  351        return other.
lo == 
lo && other.
hi == 
hi;
 
  353    bool operator!=(
HalfOpenRange other)
 const { 
return !(*
this == other); }
 
  377        if (rv.
hi <= rv.
lo) 
return {0, 0};
 
  392        if (
empty()) 
return {l, h};
 
  393        if (l == h) 
return *
this;
 
  424    template <Endian DestOrder>
 
  428            case Endian::Network:
 
  432        BUG(
"Unexpected ordering");
 
 
  450    template <RangeUnit DestUnit>
 
  457            case RangeUnit::Byte:
 
  460        BUG(
"Unexpected unit");
 
 
  471        if (
lo != other.
lo) 
return lo < other.
lo;
 
  472        return hi < other.
hi;
 
 
 
  510template <RangeUnit Unit, Endian Order>
 
  512    static constexpr RangeUnit unit = Unit;
 
  513    static constexpr Endian order = Order;
 
  523        : 
lo(fromTo.from), 
hi(fromTo.to) {}
 
  525        : 
lo(startLen.start), 
hi(startLen.start + startLen.len - 1) {}
 
  527        : 
lo(0), 
hi(std::numeric_limits<int>::max() - 1) {}
 
  529        : 
lo(std::numeric_limits<int>::min()), 
hi(std::numeric_limits<int>::max() - 1) {}
 
  530    explicit ClosedRange(std::pair<int, int> range) : 
lo(range.first), 
hi(range.second) {}
 
  533        BUG_CHECK(!r.
empty(), 
"can't convert empty range to Closed");
 
  537    ssize_t 
size()
 const { 
return ssize_t(
hi) - ssize_t(
lo) + 1; }
 
  541        BUG_CHECK(
size != 0, 
"Resizing ClosedRange to zero size");
 
  543        return {asBits.lo, asBits.lo + 
size - 1};
 
 
  548        BUG_CHECK(
size != 0, 
"Resizing ClosedRange to zero size");
 
  549        if (Unit == RangeUnit::Byte) 
return {
lo, 
lo + 
size - 1};
 
 
  556        return {asBits.lo + offset, asBits.hi + offset};
 
 
  561        if (Unit == RangeUnit::Byte) 
return {
lo + offset, 
hi + offset};
 
  562        return {
lo + offset * 8, 
hi + offset * 8};
 
 
  567        return Unit == RangeUnit::Byte ? 
lo : BitRange::Detail::divideFloor(
lo, 8);
 
 
  572        return Unit == RangeUnit::Byte ? 
hi : BitRange::Detail::divideFloor(
hi, 8);
 
 
  580        return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
lo, 8) == 0;
 
 
  585        return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
hi + 1, 8) == 0;
 
 
  589    bool operator!=(
ClosedRange other)
 const { 
return !(*
this == other); }
 
  592    bool contains(
int index)
 const { 
return (index >= 
lo) && (index <= 
hi); }
 
  597        return intersection.lo == other.
lo && intersection.size() == other.
size();
 
 
  633    template <Endian DestOrder>
 
  635        BUG_CHECK(spaceSize > 0, 
"Can't represent an empty range");
 
  638            case Endian::Network:
 
  642        BUG(
"Unexpected ordering");
 
 
  646    template <RangeUnit DestUnit>
 
  652            case RangeUnit::Byte:
 
  655        BUG(
"Unexpected unit");
 
 
  666        if (
lo != other.
lo) 
return lo < other.
lo;
 
  667        return hi < other.
hi;
 
 
  678        if (Unit == RangeUnit::Byte) {
 
  682            BUG_CHECK(Unit == RangeUnit::Bit, 
"mismatch range units");
 
  684        std::stringstream out;
 
  685        out << 
"[" << 
hi << 
":" << 
lo << 
"]";
 
 
 
  713template <RangeUnit Unit, Endian Order>
 
  718    if (intersect.
empty())
 
  719        return left.
lo < right.
lo ? std::make_pair(left, empty) : 
std::make_pair(empty, left);
 
  726    return {lower, upper};
 
  731template <RangeUnit Unit, Endian Order>
 
  734    return toHalfOpenRange(left) - toHalfOpenRange(right);
 
  739template <RangeUnit Unit, Endian Order>
 
  746template <RangeUnit Unit, Endian Order>
 
  748    if (halfOpenRange.
empty()) 
return std::nullopt;
 
  768std::ostream &toStream(std::ostream &out, RangeUnit unit, Endian order, 
int lo, 
int hi,
 
  771template <RangeUnit Unit, Endian Order>
 
  773    return toStream(out, Unit, Order, range.
lo, range.
hi, 
false);
 
  776template <RangeUnit Unit, Endian Order>
 
  778    return toStream(out, Unit, Order, range.
lo, range.
hi, 
true);
 
  783template <RangeUnit Unit, Endian Order>
 
  790template <RangeUnit Unit, Endian Order>
 
  799template <RangeUnit Unit, Endian Order>
 
  806template <RangeUnit Unit, Endian Order>
 
Definition json_generator.h:34
 
Definition json_loader.h:36
 
Definition bitrange.h:139
 
Definition bitrange.h:207
 
Definition bitrange.h:156
 
Definition bitrange.h:188
 
Definition bitrange.h:511
 
HalfOpenRange< Unit, Order > intersectWith(ClosedRange a) const
Definition bitrange.h:608
 
ClosedRange resizedToBytes(int size) const
Definition bitrange.h:547
 
ClosedRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition bitrange.h:634
 
int nextByte() const
Definition bitrange.h:576
 
bool operator<(const ClosedRange &other) const
Definition bitrange.h:665
 
int lo
Definition bitrange.h:692
 
bool isLoAligned() const
Definition bitrange.h:579
 
ClosedRange shiftedByBytes(int offset) const
Definition bitrange.h:560
 
bool contains(int index) const
Definition bitrange.h:592
 
bool isHiAligned() const
Definition bitrange.h:584
 
ssize_t size() const
Definition bitrange.h:537
 
ClosedRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition bitrange.h:554
 
ClosedRange unionWith(ClosedRange a) const
Definition bitrange.h:622
 
int loByte() const
Definition bitrange.h:566
 
bool contains(ClosedRange other) const
Definition bitrange.h:595
 
cstring formatAsSlice(int spaceSize) const
Definition bitrange.h:674
 
ClosedRange< DestUnit, Order > toUnit() const
Definition bitrange.h:647
 
ClosedRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition bitrange.h:540
 
bool overlaps(ClosedRange a) const
Definition bitrange.h:601
 
int hiByte() const
Definition bitrange.h:571
 
int hi
Definition bitrange.h:698
 
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition bitrange.h:659
 
Definition bitrange.h:251
 
ssize_t size() const
Definition bitrange.h:273
 
HalfOpenRange< Unit, Order > shiftedByBytes(int offset) const
Definition bitrange.h:311
 
bool contains(int index) const
Definition bitrange.h:359
 
HalfOpenRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition bitrange.h:302
 
bool operator<(const HalfOpenRange &other) const
Total ordering, first by lo, then by hi.
Definition bitrange.h:470
 
HalfOpenRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition bitrange.h:425
 
bool isLoAligned() const
Definition bitrange.h:336
 
HalfOpenRange resizedToBytes(int size) const
Definition bitrange.h:293
 
int lo
Definition bitrange.h:480
 
bool contains(HalfOpenRange other) const
Definition bitrange.h:363
 
HalfOpenRange< DestUnit, Order > toUnit() const
Definition bitrange.h:451
 
int hi
Definition bitrange.h:486
 
bool isHiAligned() const
Definition bitrange.h:344
 
HalfOpenRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition bitrange.h:285
 
int hiByte() const
Definition bitrange.h:324
 
HalfOpenRange intersectWith(HalfOpenRange a) const
Definition bitrange.h:374
 
int nextByte() const
Definition bitrange.h:332
 
bool overlaps(HalfOpenRange a) const
Definition bitrange.h:368
 
HalfOpenRange canonicalize() const
Definition bitrange.h:277
 
HalfOpenRange unionWith(HalfOpenRange a) const
Definition bitrange.h:390
 
bool empty() const
Definition bitrange.h:356
 
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition bitrange.h:464
 
int loByte() const
Definition bitrange.h:318