17#ifndef LIB_BITRANGE_H_
18#define LIB_BITRANGE_H_
20#include <absl/numeric/bits.h>
29#include "exceptions.h"
39 std::pair<int, int> range;
43 range.first = range.second = ptr.index();
44 while (++ptr && range.second + 1 == ptr.index()) ++range.second;
50 std::pair<int, int> operator*() {
return range; }
51 bool operator==(iter &a)
const {
return valid == a.valid && ptr == a.ptr; }
52 bool operator!=(iter &a)
const {
return !(*
this == a); }
59 explicit bitranges(uintptr_t b) : tmp(b), bits(tmp) {}
60 iter begin()
const {
return iter(bits.begin()); }
61 iter end()
const {
return iter(bits.end()); }
76constexpr inline int divideFloor(
int dividend,
int divisor) {
77#if defined(__GNUC__) || defined(__clang__)
81 unsigned u_divisor =
static_cast<unsigned>(divisor);
82 if (__builtin_constant_p(u_divisor) && absl::has_single_bit(u_divisor))
83 return dividend >> (absl::bit_width(u_divisor) - 1);
86 const int quotient = dividend / divisor;
87 const int remainder = dividend % divisor;
88 if ((remainder != 0) && ((remainder < 0) != (divisor < 0)))
return quotient - 1;
99constexpr int modulo(
int dividend,
int divisor) {
100 return (dividend % divisor) * ((dividend < 0) != (divisor < 0) ? -1 : 1);
116constexpr inline int moduloFloor(
const int dividend,
const int divisor) {
117#if defined(__GNUC__) || defined(__clang__)
121 if (__builtin_constant_p(divisor) && absl::has_single_bit(
static_cast<unsigned>(divisor)))
122 return dividend & (divisor - 1);
125 const int remainder = modulo(dividend, divisor);
126 if (remainder == 0 || dividend >= 0)
return remainder;
127 return divisor - remainder;
141 FromTo(
int from,
int to) : from(from), to(to) {}
158 StartLen(
int start,
int len) : start(start), len(len) {}
211void rangeToJSON(JSONGenerator &json,
int lo,
int hi);
212std::pair<int, int> rangeFromJSON(JSONLoader &json);
217enum class RangeUnit : uint8_t {
223enum class Endian : uint8_t {
251template <RangeUnit Unit, Endian Order>
253 static constexpr RangeUnit unit = Unit;
254 static constexpr Endian order = Order;
264 :
lo(fromTo.from),
hi(fromTo.to + 1) {}
266 :
lo(startLen.start),
hi(startLen.start + startLen.len) {}
268 :
lo(0),
hi(std::numeric_limits<int>::max()) {}
270 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max()) {}
271 explicit HalfOpenRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
274 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo); }
288 auto asBits = toUnit<RangeUnit::Bit>();
289 return {asBits.lo, asBits.lo +
size};
295 const int resizedLo =
empty() ? 0 :
lo;
296 if (Unit == RangeUnit::Byte)
return {resizedLo, resizedLo +
size};
297 return {resizedLo, resizedLo +
size * 8};
305 auto asBits = toUnit<RangeUnit::Bit>();
306 return {asBits.lo + offset, asBits.hi + offset};
314 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
315 return {
lo + offset * 8,
hi + offset * 8};
320 if (
empty())
return 0;
321 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
326 if (
empty())
return 0;
327 return Unit == RangeUnit::Byte ?
hi - 1 : BitRange::Detail::divideFloor(
hi - 1, 8);
338 return (
empty() || Unit == RangeUnit::Byte) ? true
339 : BitRange::Detail::moduloFloor(
lo, 8) == 0;
346 return (
empty() || Unit == RangeUnit::Byte) ? true
347 : BitRange::Detail::moduloFloor(
hi, 8) == 0;
352 return other.
lo ==
lo && other.
hi ==
hi;
354 bool operator!=(
HalfOpenRange other)
const {
return !(*
this == other); }
378 if (rv.
hi <= rv.
lo)
return {0, 0};
393 if (
empty())
return {l, h};
394 if (l == h)
return *
this;
425 template <Endian DestOrder>
429 case Endian::Network:
433 BUG(
"Unexpected ordering");
451 template <RangeUnit DestUnit>
458 case RangeUnit::Byte:
461 BUG(
"Unexpected unit");
465 void toJSON(JSONGenerator &json)
const { BitRange::rangeToJSON(json,
lo,
hi); }
472 if (
lo != other.
lo)
return lo < other.
lo;
473 return hi < other.
hi;
511template <RangeUnit Unit, Endian Order>
513 static constexpr RangeUnit unit = Unit;
514 static constexpr Endian order = Order;
524 :
lo(fromTo.from),
hi(fromTo.to) {}
526 :
lo(startLen.start),
hi(startLen.start + startLen.len - 1) {}
528 :
lo(0),
hi(std::numeric_limits<int>::max() - 1) {}
530 :
lo(std::numeric_limits<int>::min()),
hi(std::numeric_limits<int>::max() - 1) {}
531 explicit ClosedRange(std::pair<int, int> range) :
lo(range.first),
hi(range.second) {}
534 BUG_CHECK(!r.
empty(),
"can't convert empty range to Closed");
538 ssize_t
size()
const {
return ssize_t(
hi) - ssize_t(
lo) + 1; }
542 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
543 auto asBits = toUnit<RangeUnit::Bit>();
544 return {asBits.lo, asBits.lo +
size - 1};
549 BUG_CHECK(
size != 0,
"Resizing ClosedRange to zero size");
550 if (Unit == RangeUnit::Byte)
return {
lo,
lo +
size - 1};
556 auto asBits = toUnit<RangeUnit::Bit>();
557 return {asBits.lo + offset, asBits.hi + offset};
562 if (Unit == RangeUnit::Byte)
return {
lo + offset,
hi + offset};
563 return {
lo + offset * 8,
hi + offset * 8};
568 return Unit == RangeUnit::Byte ?
lo : BitRange::Detail::divideFloor(
lo, 8);
573 return Unit == RangeUnit::Byte ?
hi : BitRange::Detail::divideFloor(
hi, 8);
581 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
lo, 8) == 0;
586 return Unit == RangeUnit::Byte ? true : BitRange::Detail::moduloFloor(
hi + 1, 8) == 0;
590 bool operator!=(
ClosedRange other)
const {
return !(*
this == other); }
593 bool contains(
int index)
const {
return (index >=
lo) && (index <=
hi); }
598 return intersection.lo == other.
lo && intersection.size() == other.
size();
634 template <Endian DestOrder>
636 BUG_CHECK(spaceSize > 0,
"Can't represent an empty range");
639 case Endian::Network:
643 BUG(
"Unexpected ordering");
647 template <RangeUnit DestUnit>
653 case RangeUnit::Byte:
656 BUG(
"Unexpected unit");
660 void toJSON(JSONGenerator &json)
const { BitRange::rangeToJSON(json,
lo,
hi); }
667 if (
lo != other.
lo)
return lo < other.
lo;
668 return hi < other.
hi;
676 auto r = toOrder<Endian::Little>(spaceSize);
679 if (Unit == RangeUnit::Byte) {
683 BUG_CHECK(Unit == RangeUnit::Bit,
"mismatch range units");
685 std::stringstream out;
686 out <<
"[" <<
hi <<
":" <<
lo <<
"]";
714template <RangeUnit Unit, Endian Order>
719 if (intersect.
empty())
720 return left.
lo < right.
lo ? std::make_pair(left, empty) :
std::make_pair(empty, left);
727 return {lower, upper};
732template <RangeUnit Unit, Endian Order>
735 return toHalfOpenRange(left) - toHalfOpenRange(right);
740template <RangeUnit Unit, Endian Order>
747template <RangeUnit Unit, Endian Order>
749 if (halfOpenRange.
empty())
return std::nullopt;
769std::ostream &toStream(std::ostream &out, RangeUnit unit, Endian order,
int lo,
int hi,
772template <RangeUnit Unit, Endian Order>
774 return toStream(out, Unit, Order, range.
lo, range.
hi,
false);
777template <RangeUnit Unit, Endian Order>
779 return toStream(out, Unit, Order, range.
lo, range.
hi,
true);
784template <RangeUnit Unit, Endian Order>
791template <RangeUnit Unit, Endian Order>
800template <RangeUnit Unit, Endian Order>
807template <RangeUnit Unit, Endian Order>
Definition bitrange.h:140
Definition bitrange.h:208
Definition bitrange.h:157
Definition bitrange.h:189
Definition bitrange.h:512
HalfOpenRange< Unit, Order > intersectWith(ClosedRange a) const
Definition bitrange.h:609
ClosedRange resizedToBytes(int size) const
Definition bitrange.h:548
ClosedRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition bitrange.h:635
int nextByte() const
Definition bitrange.h:577
bool operator<(const ClosedRange &other) const
Definition bitrange.h:666
int lo
Definition bitrange.h:693
bool isLoAligned() const
Definition bitrange.h:580
ClosedRange shiftedByBytes(int offset) const
Definition bitrange.h:561
bool contains(int index) const
Definition bitrange.h:593
bool isHiAligned() const
Definition bitrange.h:585
ssize_t size() const
Definition bitrange.h:538
ClosedRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition bitrange.h:555
ClosedRange unionWith(ClosedRange a) const
Definition bitrange.h:623
int loByte() const
Definition bitrange.h:567
bool contains(ClosedRange other) const
Definition bitrange.h:596
cstring formatAsSlice(int spaceSize) const
Definition bitrange.h:675
ClosedRange< DestUnit, Order > toUnit() const
Definition bitrange.h:648
ClosedRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition bitrange.h:541
bool overlaps(ClosedRange a) const
Definition bitrange.h:602
int hiByte() const
Definition bitrange.h:572
int hi
Definition bitrange.h:699
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition bitrange.h:660
Definition bitrange.h:252
ssize_t size() const
Definition bitrange.h:274
HalfOpenRange< Unit, Order > shiftedByBytes(int offset) const
Definition bitrange.h:312
bool contains(int index) const
Definition bitrange.h:360
HalfOpenRange< RangeUnit::Bit, Order > shiftedByBits(int offset) const
Definition bitrange.h:303
bool operator<(const HalfOpenRange &other) const
Total ordering, first by lo, then by hi.
Definition bitrange.h:471
HalfOpenRange< Unit, DestOrder > toOrder(int spaceSize) const
Definition bitrange.h:426
bool isLoAligned() const
Definition bitrange.h:337
HalfOpenRange resizedToBytes(int size) const
Definition bitrange.h:294
int lo
Definition bitrange.h:481
bool contains(HalfOpenRange other) const
Definition bitrange.h:364
HalfOpenRange< DestUnit, Order > toUnit() const
Definition bitrange.h:452
int hi
Definition bitrange.h:487
bool isHiAligned() const
Definition bitrange.h:345
HalfOpenRange< RangeUnit::Bit, Order > resizedToBits(int size) const
Definition bitrange.h:286
int hiByte() const
Definition bitrange.h:325
HalfOpenRange intersectWith(HalfOpenRange a) const
Definition bitrange.h:375
int nextByte() const
Definition bitrange.h:333
bool overlaps(HalfOpenRange a) const
Definition bitrange.h:369
HalfOpenRange canonicalize() const
Definition bitrange.h:278
HalfOpenRange unionWith(HalfOpenRange a) const
Definition bitrange.h:391
bool empty() const
Definition bitrange.h:357
void toJSON(JSONGenerator &json) const
JSON serialization/deserialization.
Definition bitrange.h:465
int loByte() const
Definition bitrange.h:319