package bits import ( "math/big" "github.com/lbryio/lbry.go/v2/extras/errors" ) // Range has a start and end type Range struct { Start Bitmap End Bitmap } func MaxRange() Range { return Range{ Start: Bitmap{}, End: MaxP(), } } // IntervalP divides the range into `num` intervals and returns the `n`th one // intervals are approximately the same size, but may not be exact because of rounding issues // the first interval always starts at the beginning of the range, and the last interval always ends at the end func (r Range) IntervalP(n, num int) Range { if num < 1 || n < 1 || n > num { panic(errors.Err("invalid interval %d of %d", n, num)) } start := r.intervalStart(n, num) end := r.End.Big() if n < num { end = r.intervalStart(n+1, num) end.Sub(end, big.NewInt(1)) } return Range{FromBigP(start), FromBigP(end)} } func (r Range) intervalStart(n, num int) *big.Int { // formula: // size = (end - start) / num // rem = (end - start) % num // intervalStart = rangeStart + (size * n-1) + ((rem * n-1) % num) size := new(big.Int) rem := new(big.Int) size.Sub(r.End.Big(), r.Start.Big()).DivMod(size, big.NewInt(int64(num)), rem) size.Mul(size, big.NewInt(int64(n-1))) rem.Mul(rem, big.NewInt(int64(n-1))).Mod(rem, big.NewInt(int64(num))) start := r.Start.Big() start.Add(start, size).Add(start, rem) return start } func (r Range) IntervalSize() *big.Int { return (&big.Int{}).Sub(r.End.Big(), r.Start.Big()) } func (r Range) Contains(b Bitmap) bool { return r.Start.Cmp(b) <= 0 && r.End.Cmp(b) >= 0 }