libs: Remove rlepluslazy (using specs-actors everywhere)
This commit is contained in:
parent
e51fa5c9ac
commit
79237a9309
@ -1,160 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
type it2b struct {
|
|
||||||
source RunIterator
|
|
||||||
curIdx uint64
|
|
||||||
|
|
||||||
run Run
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2b) HasNext() bool {
|
|
||||||
return it.run.Valid()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2b) Next() (uint64, error) {
|
|
||||||
it.run.Len--
|
|
||||||
res := it.curIdx
|
|
||||||
it.curIdx++
|
|
||||||
return res, it.prep()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2b) prep() error {
|
|
||||||
for !it.run.Valid() && it.source.HasNext() {
|
|
||||||
var err error
|
|
||||||
it.run, err = it.source.NextRun()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !it.run.Val {
|
|
||||||
it.curIdx += it.run.Len
|
|
||||||
it.run.Len = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func BitsFromRuns(source RunIterator) (BitIterator, error) {
|
|
||||||
it := &it2b{source: source}
|
|
||||||
if err := it.prep(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type sliceIt struct {
|
|
||||||
s []uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it sliceIt) HasNext() bool {
|
|
||||||
return len(it.s) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *sliceIt) Next() (uint64, error) {
|
|
||||||
res := it.s[0]
|
|
||||||
it.s = it.s[1:]
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func BitsFromSlice(slice []uint64) BitIterator {
|
|
||||||
sort.Slice(slice, func(i, j int) bool { return slice[i] < slice[j] })
|
|
||||||
return &sliceIt{slice}
|
|
||||||
}
|
|
||||||
|
|
||||||
type it2r struct {
|
|
||||||
source BitIterator
|
|
||||||
|
|
||||||
runIdx uint64
|
|
||||||
run [2]Run
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2r) HasNext() bool {
|
|
||||||
return it.run[0].Valid()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2r) NextRun() (Run, error) {
|
|
||||||
res := it.run[0]
|
|
||||||
it.runIdx = it.runIdx + res.Len
|
|
||||||
it.run[0], it.run[1] = it.run[1], Run{}
|
|
||||||
return res, it.prep()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2r) prep() error {
|
|
||||||
if !it.HasNext() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if it.run[0].Val == false {
|
|
||||||
it.run[1].Val = true
|
|
||||||
it.run[1].Len = 1
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for it.source.HasNext() && !it.run[1].Valid() {
|
|
||||||
nB, err := it.source.Next()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("runIdx: %d, run[0].Len: %d, nB: %d\n", it.runIdx, it.run[0].Len, nB)
|
|
||||||
if it.runIdx+it.run[0].Len == nB {
|
|
||||||
it.run[0].Len++
|
|
||||||
} else {
|
|
||||||
it.run[1].Len = nB - it.runIdx - it.run[0].Len
|
|
||||||
it.run[1].Val = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *it2r) init() error {
|
|
||||||
if it.source.HasNext() {
|
|
||||||
nB, err := it.source.Next()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
it.run[0].Len = nB
|
|
||||||
it.run[0].Val = false
|
|
||||||
it.run[1].Len = 1
|
|
||||||
it.run[1].Val = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !it.run[0].Valid() {
|
|
||||||
it.run[0], it.run[1] = it.run[1], Run{}
|
|
||||||
return it.prep()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SliceFromRuns(source RunIterator) ([]uint64, error) {
|
|
||||||
rit, err := BitsFromRuns(source)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]uint64, 0)
|
|
||||||
for rit.HasNext() {
|
|
||||||
bit, err := rit.Next()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res = append(res, bit)
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunsFromBits(source BitIterator) (RunIterator, error) {
|
|
||||||
it := &it2r{source: source}
|
|
||||||
|
|
||||||
if err := it.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunsFromSlice(slice []uint64) (RunIterator, error) {
|
|
||||||
return RunsFromBits(BitsFromSlice(slice))
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRunsFromBits(t *testing.T) {
|
|
||||||
expected := []Run{Run{Val: false, Len: 0x1},
|
|
||||||
{Val: true, Len: 0x3},
|
|
||||||
{Val: false, Len: 0x2},
|
|
||||||
{Val: true, Len: 0x3},
|
|
||||||
}
|
|
||||||
rit, err := RunsFromBits(BitsFromSlice([]uint64{1, 2, 3, 6, 7, 8}))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
i := 10
|
|
||||||
output := make([]Run, 0, 4)
|
|
||||||
for rit.HasNext() && i > 0 {
|
|
||||||
run, err := rit.NextRun()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
i--
|
|
||||||
output = append(output, run)
|
|
||||||
}
|
|
||||||
assert.NotEqual(t, 0, i, "too many iterations")
|
|
||||||
assert.Equal(t, expected, output)
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
type rbitvec struct {
|
|
||||||
index int
|
|
||||||
|
|
||||||
bits uint16
|
|
||||||
bitCap byte
|
|
||||||
|
|
||||||
vec []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func readBitvec(vec []byte) *rbitvec {
|
|
||||||
bv := &rbitvec{
|
|
||||||
vec: vec,
|
|
||||||
index: 1,
|
|
||||||
bitCap: 8,
|
|
||||||
}
|
|
||||||
if len(vec) > 0 {
|
|
||||||
bv.bits = uint16(bv.vec[0])
|
|
||||||
}
|
|
||||||
return bv
|
|
||||||
}
|
|
||||||
|
|
||||||
// bitMasks is a mask for selecting N first bits out of a byte
|
|
||||||
var bitMasks = [9]byte{
|
|
||||||
0x0,
|
|
||||||
0x1,
|
|
||||||
0x3,
|
|
||||||
0x7,
|
|
||||||
0xF,
|
|
||||||
0x1F,
|
|
||||||
0x3F,
|
|
||||||
0x7F,
|
|
||||||
0xFF,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *rbitvec) Get(count byte) byte {
|
|
||||||
res := byte(bv.bits) & bitMasks[count] // select count bits
|
|
||||||
bv.bits = bv.bits >> count // remove those bits from storage
|
|
||||||
bv.bitCap = bv.bitCap - count // decrease nuber of stored bits
|
|
||||||
|
|
||||||
if bv.index < len(bv.vec) { // if vector allows
|
|
||||||
// add bits onto the end of temporary storage
|
|
||||||
bv.bits = bv.bits | uint16(bv.vec[bv.index])<<bv.bitCap
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here be dragons
|
|
||||||
// This is equivalent to
|
|
||||||
// if bv.bitCap < 8 {
|
|
||||||
// bv.index++
|
|
||||||
// bv.bitCap = bv.bitCap + 8
|
|
||||||
// }
|
|
||||||
// but implemented without branches because the branch here is unpredictable
|
|
||||||
// Why this is without branches and reading has branch?
|
|
||||||
// Because branch above is predictable, in 99.99% of cases it will be true
|
|
||||||
|
|
||||||
// if bitCap < 8 it underflows, then high bits get set to 1s
|
|
||||||
// we shift by 7 so the highest bit is in place of the lowest
|
|
||||||
inc := (bv.bitCap - 8) >> 7 // inc == 1 iff bitcap<8 (+10% perf)
|
|
||||||
bv.index = bv.index + int(inc) // increase index if we need more bits
|
|
||||||
bv.bitCap = bv.bitCap + inc*8 // increase bitCap by 8
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBitvec(buf []byte) *wbitvec {
|
|
||||||
// reslice to 0 length for consistent input but to keep capacity
|
|
||||||
return &wbitvec{buf: buf[:0]}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wbitvec struct {
|
|
||||||
buf []byte // buffer we will be saving to
|
|
||||||
index int // index of at which the next byte will be saved
|
|
||||||
|
|
||||||
bits uint16 // temporary storage for bits
|
|
||||||
bitCap byte // number of bits stored in temporary storage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *wbitvec) Out() []byte {
|
|
||||||
if bv.bitCap != 0 {
|
|
||||||
// if there are some bits in temporary storage we need to save them
|
|
||||||
bv.buf = append(bv.buf, 0)[:bv.index+1]
|
|
||||||
bv.buf[bv.index] = byte(bv.bits)
|
|
||||||
}
|
|
||||||
if bv.bitCap > 8 {
|
|
||||||
// if we store some needed bits in second byte, save them also
|
|
||||||
bv.buf = append(bv.buf, byte(bv.bitCap>>8))
|
|
||||||
bv.index++
|
|
||||||
bv.bits = bv.bits - 8
|
|
||||||
}
|
|
||||||
return bv.buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bv *wbitvec) Put(val byte, count byte) {
|
|
||||||
// put val into its place in bv.bits
|
|
||||||
bv.bits = bv.bits | uint16(val)<<bv.bitCap
|
|
||||||
// increase bitCap by the number of bits
|
|
||||||
bv.bitCap = bv.bitCap + count
|
|
||||||
|
|
||||||
// increase len of the buffer if it is needed
|
|
||||||
if bv.index+1 > cap(bv.buf) {
|
|
||||||
bv.buf = append(bv.buf, 0)
|
|
||||||
}
|
|
||||||
bv.buf = bv.buf[:bv.index+1]
|
|
||||||
// save the bits
|
|
||||||
bv.buf[bv.index] = byte(bv.bits)
|
|
||||||
|
|
||||||
// Warning, dragons again
|
|
||||||
// if bitCap is greater than 7 it underflows, same thing as in Put
|
|
||||||
inc := (7 - bv.bitCap) >> 7 // inc == 1 iff bitcap>=8
|
|
||||||
bv.index = bv.index + int(inc) // increase index for the next save
|
|
||||||
bv.bitCap = bv.bitCap - inc*8 // we store less bits now in temporary buffer
|
|
||||||
bv.bits = bv.bits >> (inc * 8) // we can discard those bits as they were saved
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReadBitVec(t *testing.T) {
|
|
||||||
buf := []byte{0x0, 0xff}
|
|
||||||
bv := readBitvec(buf)
|
|
||||||
|
|
||||||
o := bv.Get(1)
|
|
||||||
assert.EqualValues(t, 0, o)
|
|
||||||
|
|
||||||
o = bv.Get(8)
|
|
||||||
assert.EqualValues(t, 0x80, o)
|
|
||||||
|
|
||||||
o = bv.Get(7)
|
|
||||||
assert.EqualValues(t, 0x7f, o)
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
type Run struct {
|
|
||||||
Val bool
|
|
||||||
Len uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Run) Valid() bool {
|
|
||||||
return r.Len != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type RunIterator interface {
|
|
||||||
NextRun() (Run, error)
|
|
||||||
HasNext() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type RunIterable interface {
|
|
||||||
RunIterator() (RunIterator, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type BitIterator interface {
|
|
||||||
Next() (uint64, error)
|
|
||||||
HasNext() bool
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const Version = 0
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrWrongVersion = errors.New("invalid RLE+ version")
|
|
||||||
ErrDecode = fmt.Errorf("invalid encoding for RLE+ version %d", Version)
|
|
||||||
)
|
|
||||||
|
|
||||||
type RLE struct {
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromBuf(buf []byte) (RLE, error) {
|
|
||||||
rle := RLE{buf: buf}
|
|
||||||
|
|
||||||
if len(buf) > 0 && buf[0]&3 != Version {
|
|
||||||
return RLE{}, xerrors.Errorf("could not create RLE+ for a buffer: %w", ErrWrongVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := rle.Count()
|
|
||||||
if err != nil {
|
|
||||||
return RLE{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return rle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rle *RLE) RunIterator() (RunIterator, error) {
|
|
||||||
source, err := DecodeRLE(rle.buf)
|
|
||||||
return source, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rle *RLE) Count() (uint64, error) {
|
|
||||||
it, err := rle.RunIterator()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return Count(it)
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
@ -1,77 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/multiformats/go-varint"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DecodeRLE(buf []byte) (RunIterator, error) {
|
|
||||||
bv := readBitvec(buf)
|
|
||||||
|
|
||||||
ver := bv.Get(2) // Read version
|
|
||||||
if ver != Version {
|
|
||||||
return nil, ErrWrongVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
it := &rleIterator{bv: bv}
|
|
||||||
|
|
||||||
// next run is previous in relation to prep
|
|
||||||
// so we invert the value
|
|
||||||
it.nextRun.Val = bv.Get(1) != 1
|
|
||||||
if err := it.prep(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type rleIterator struct {
|
|
||||||
bv *rbitvec
|
|
||||||
|
|
||||||
nextRun Run
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *rleIterator) HasNext() bool {
|
|
||||||
return it.nextRun.Valid()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *rleIterator) NextRun() (Run, error) {
|
|
||||||
ret := it.nextRun
|
|
||||||
return ret, it.prep()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *rleIterator) prep() error {
|
|
||||||
x := it.bv.Get(1)
|
|
||||||
|
|
||||||
switch x {
|
|
||||||
case 1:
|
|
||||||
it.nextRun.Len = 1
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
y := it.bv.Get(1)
|
|
||||||
switch y {
|
|
||||||
case 1:
|
|
||||||
it.nextRun.Len = uint64(it.bv.Get(4))
|
|
||||||
case 0:
|
|
||||||
var buf = make([]byte, 0, 10)
|
|
||||||
for {
|
|
||||||
b := it.bv.Get(8)
|
|
||||||
buf = append(buf, b)
|
|
||||||
if b&0x80 == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(buf) > 10 {
|
|
||||||
return xerrors.Errorf("run too long: %w", ErrDecode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
it.nextRun.Len, _, err = varint.FromUvarint(buf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it.nextRun.Val = !it.nextRun.Val
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/extern/rleplus"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDecode(t *testing.T) {
|
|
||||||
// Encoding bitvec![LittleEndian; 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
|
||||||
// in the Rust reference implementation gives an encoding of [223, 145, 136, 0] (without version field)
|
|
||||||
// The bit vector is equivalent to the integer set { 0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }
|
|
||||||
|
|
||||||
// This is the above reference output with a version header "00" manually added
|
|
||||||
referenceEncoding := []byte{124, 71, 34, 2}
|
|
||||||
|
|
||||||
expectedNumbers := []uint64{0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}
|
|
||||||
|
|
||||||
runs, err := RunsFromBits(BitsFromSlice(expectedNumbers))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
encoded, err := EncodeRuns(runs, []byte{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Our encoded bytes are the same as the ref bytes
|
|
||||||
assert.Equal(t, len(referenceEncoding), len(encoded))
|
|
||||||
assert.Equal(t, referenceEncoding, encoded)
|
|
||||||
|
|
||||||
rle, err := FromBuf(encoded)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
decoded := make([]uint64, 0, len(expectedNumbers))
|
|
||||||
|
|
||||||
rit, err := rle.RunIterator()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
it, err := BitsFromRuns(rit)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
for it.HasNext() {
|
|
||||||
bit, err := it.Next()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
decoded = append(decoded, bit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our decoded integers are the same as expected
|
|
||||||
assert.Equal(t, expectedNumbers, decoded)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGoldenGen(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
N := 10000
|
|
||||||
mod := uint32(1) << 20
|
|
||||||
runExProp := float32(0.93)
|
|
||||||
|
|
||||||
bits := make([]uint64, N)
|
|
||||||
|
|
||||||
for i := 0; i < N; i++ {
|
|
||||||
x := rand.Uint32() % mod
|
|
||||||
bits[i] = uint64(x)
|
|
||||||
for rand.Float32() < runExProp && i+1 < N {
|
|
||||||
i++
|
|
||||||
x = (x + 1) % mod
|
|
||||||
bits[i] = uint64(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out, _, err := rleplus.Encode(bits)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
t.Logf("%#v", out)
|
|
||||||
_, runs := rleplus.RunLengths(bits)
|
|
||||||
t.Logf("runs: %v", runs)
|
|
||||||
t.Logf("len: %d", len(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGolden(t *testing.T) {
|
|
||||||
expected, _ := rleplus.Decode(goldenRLE)
|
|
||||||
res := make([]uint64, 0, len(expected))
|
|
||||||
|
|
||||||
rle, err := FromBuf(goldenRLE)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
rit, err := rle.RunIterator()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
it, err := BitsFromRuns(rit)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
for it.HasNext() {
|
|
||||||
bit, err := it.Next()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
res = append(res, bit)
|
|
||||||
}
|
|
||||||
assert.Equal(t, expected, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGoldenLoop(t *testing.T) {
|
|
||||||
rle, err := FromBuf(goldenRLE)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
rit, err := rle.RunIterator()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
buf, err := EncodeRuns(rit, nil)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, goldenRLE, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
var Res uint64 = 0
|
|
||||||
|
|
||||||
func BenchmarkRunIterator(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
var r uint64
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rle, _ := FromBuf(goldenRLE)
|
|
||||||
rit, _ := rle.RunIterator()
|
|
||||||
for rit.HasNext() {
|
|
||||||
run, _ := rit.NextRun()
|
|
||||||
if run.Val {
|
|
||||||
r = r + run.Len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Res = Res + r
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkRunsToBits(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
var r uint64
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rle, _ := FromBuf(goldenRLE)
|
|
||||||
rit, _ := rle.RunIterator()
|
|
||||||
it, _ := BitsFromRuns(rit)
|
|
||||||
for it.HasNext() {
|
|
||||||
bit, _ := it.Next()
|
|
||||||
if bit < 1<<63 {
|
|
||||||
r++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Res = Res + r
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkOldRLE(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
var r uint64
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rle, _ := rleplus.Decode(goldenRLE)
|
|
||||||
r = r + uint64(len(rle))
|
|
||||||
}
|
|
||||||
Res = Res + r
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDecodeEncode(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
var r uint64
|
|
||||||
out := make([]byte, 0, len(goldenRLE))
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rle, _ := FromBuf(goldenRLE)
|
|
||||||
rit, _ := rle.RunIterator()
|
|
||||||
out, _ = EncodeRuns(rit, out)
|
|
||||||
r = r + uint64(len(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
rle, _ := rleplus.Decode(goldenRLE)
|
|
||||||
out, _, _ := rleplus.Encode(rle)
|
|
||||||
r = r + uint64(len(out))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Res = Res + r
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
)
|
|
||||||
|
|
||||||
func EncodeRuns(rit RunIterator, buf []byte) ([]byte, error) {
|
|
||||||
bv := writeBitvec(buf)
|
|
||||||
bv.Put(0, 2)
|
|
||||||
|
|
||||||
first := true
|
|
||||||
varBuf := make([]byte, binary.MaxVarintLen64)
|
|
||||||
|
|
||||||
for rit.HasNext() {
|
|
||||||
run, err := rit.NextRun()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if first {
|
|
||||||
if run.Val {
|
|
||||||
bv.Put(1, 1)
|
|
||||||
} else {
|
|
||||||
bv.Put(0, 1)
|
|
||||||
}
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case run.Len == 1:
|
|
||||||
bv.Put(1, 1)
|
|
||||||
case run.Len < 16:
|
|
||||||
bv.Put(2, 2)
|
|
||||||
bv.Put(byte(run.Len), 4)
|
|
||||||
case run.Len >= 16:
|
|
||||||
bv.Put(0, 2)
|
|
||||||
numBytes := binary.PutUvarint(varBuf, run.Len)
|
|
||||||
for i := 0; i < numBytes; i++ {
|
|
||||||
bv.Put(varBuf[i], 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if first {
|
|
||||||
bv.Put(0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bv.Out(), nil
|
|
||||||
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Sum(a, b RunIterator) (RunIterator, error) {
|
|
||||||
it := addIt{a: a, b: b}
|
|
||||||
it.prep()
|
|
||||||
return &it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type addIt struct {
|
|
||||||
a RunIterator
|
|
||||||
b RunIterator
|
|
||||||
|
|
||||||
next Run
|
|
||||||
|
|
||||||
arun Run
|
|
||||||
brun Run
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *addIt) prep() error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
fetch := func() error {
|
|
||||||
if !it.arun.Valid() && it.a.HasNext() {
|
|
||||||
it.arun, err = it.a.NextRun()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !it.brun.Valid() && it.b.HasNext() {
|
|
||||||
it.brun, err = it.b.NextRun()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fetch(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// one is not valid
|
|
||||||
if !it.arun.Valid() {
|
|
||||||
it.next = it.brun
|
|
||||||
it.brun.Len = 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !it.brun.Valid() {
|
|
||||||
it.next = it.arun
|
|
||||||
it.arun.Len = 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(it.arun.Val || it.brun.Val) {
|
|
||||||
min := it.arun.Len
|
|
||||||
if it.brun.Len < min {
|
|
||||||
min = it.brun.Len
|
|
||||||
}
|
|
||||||
it.next = Run{Val: it.arun.Val, Len: min}
|
|
||||||
it.arun.Len -= it.next.Len
|
|
||||||
it.brun.Len -= it.next.Len
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
it.next = Run{Val: true}
|
|
||||||
// different vals, 'true' wins
|
|
||||||
for (it.arun.Val && it.arun.Valid()) || (it.brun.Val && it.brun.Valid()) {
|
|
||||||
min := it.arun.Len
|
|
||||||
if it.brun.Len < min && it.brun.Valid() || !it.arun.Valid() {
|
|
||||||
min = it.brun.Len
|
|
||||||
}
|
|
||||||
it.next.Len += min
|
|
||||||
if it.arun.Valid() {
|
|
||||||
it.arun.Len -= min
|
|
||||||
}
|
|
||||||
if it.brun.Valid() {
|
|
||||||
it.brun.Len -= min
|
|
||||||
}
|
|
||||||
if err := fetch(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *addIt) HasNext() bool {
|
|
||||||
return it.next.Valid()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *addIt) NextRun() (Run, error) {
|
|
||||||
next := it.next
|
|
||||||
return next, it.prep()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Count(ri RunIterator) (uint64, error) {
|
|
||||||
var count uint64
|
|
||||||
|
|
||||||
for ri.HasNext() {
|
|
||||||
r, err := ri.NextRun()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if r.Val {
|
|
||||||
if math.MaxUint64-r.Len < count {
|
|
||||||
return 0, xerrors.New("RLE+ overflows")
|
|
||||||
}
|
|
||||||
count += r.Len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count, nil
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
package rlepluslazy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"sort"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSumRuns(t *testing.T) {
|
|
||||||
{
|
|
||||||
a, err := RunsFromSlice([]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
b, err := RunsFromSlice([]uint64{0, 1, 2, 3, 9, 10, 16, 17, 18, 50, 51, 70})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
s, err := Sum(a, b)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
bis, err := SliceFromRuns(s)
|
|
||||||
assert.Equal(t, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 50, 51, 70}, bis)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
a, err := RunsFromSlice([]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
b, err := RunsFromSlice([]uint64{0, 1, 2, 3, 9, 10, 16, 17, 18, 50, 51, 70})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
s, err := Sum(b, a)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
bis, err := SliceFromRuns(s)
|
|
||||||
assert.Equal(t, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 50, 51, 70}, bis)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func randomBits(N int, max uint64) []uint64 {
|
|
||||||
all := make(map[uint64]struct{})
|
|
||||||
for len(all) <= N {
|
|
||||||
x := rand.Uint64() % max
|
|
||||||
if _, has := all[x]; has {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
all[x] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]uint64, 0, N)
|
|
||||||
for x := range all {
|
|
||||||
res = append(res, x)
|
|
||||||
}
|
|
||||||
sort.Slice(res, func(i, j int) bool { return res[i] < res[j] })
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func sum(a, b []uint64) []uint64 {
|
|
||||||
all := make(map[uint64]struct{})
|
|
||||||
for _, x := range a {
|
|
||||||
all[x] = struct{}{}
|
|
||||||
}
|
|
||||||
for _, x := range b {
|
|
||||||
all[x] = struct{}{}
|
|
||||||
}
|
|
||||||
res := make([]uint64, 0, len(all))
|
|
||||||
for x := range all {
|
|
||||||
res = append(res, x)
|
|
||||||
}
|
|
||||||
sort.Slice(res, func(i, j int) bool { return res[i] < res[j] })
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSumRandom(t *testing.T) {
|
|
||||||
N := 100
|
|
||||||
|
|
||||||
for i := 0; i < N; i++ {
|
|
||||||
abits := randomBits(1000, 1500)
|
|
||||||
bbits := randomBits(1000, 1500)
|
|
||||||
sumbits := sum(abits, bbits)
|
|
||||||
|
|
||||||
a, err := RunsFromSlice(abits)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
b, err := RunsFromSlice(bbits)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
s, err := Sum(b, a)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
bis, err := SliceFromRuns(s)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, sumbits, bis)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user