Skip to content

Commit

Permalink
Replace rleplus with rlepluslazy
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Jakub Sztandera <[email protected]>
  • Loading branch information
Jakub Sztandera committed Dec 7, 2019
1 parent 438b607 commit f9b464b
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 42 deletions.
86 changes: 61 additions & 25 deletions chain/types/bitfield.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ package types
import (
"fmt"
"io"
"sort"

"github.com/filecoin-project/lotus/extern/rleplus"
rlepluslazy "github.com/filecoin-project/lotus/lib/rlepluslazy"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
)

type BitField struct {
rle rlepluslazy.RLE

bits map[uint64]struct{}
}

func NewBitField() BitField {
return BitField{bits: make(map[uint64]struct{})}
rle, _ := rlepluslazy.FromBuf([]byte{})
return BitField{
rle: rle,
bits: make(map[uint64]struct{}),
}
}

func BitFieldFromSet(setBits []uint64) BitField {
Expand All @@ -26,31 +31,59 @@ func BitFieldFromSet(setBits []uint64) BitField {
return res
}

func (bf BitField) sum() (rlepluslazy.RunIterator, error) {
if len(bf.bits) == 0 {
return bf.rle.RunIterator()
}

a, err := bf.rle.RunIterator()
if err != nil {
return nil, err
}
slc := make([]uint64, 0, len(bf.bits))
for b := range bf.bits {
slc = append(slc, b)
}

b, err := rlepluslazy.RunsFromSlice(slc)
if err != nil {
return nil, err
}

res, err := rlepluslazy.Sum(a, b)
if err != nil {
return nil, err
}
return res, nil
}

// Set ...s bit in the BitField
func (bf BitField) Set(bit uint64) {
bf.bits[bit] = struct{}{}
}

// Clear ...s bit in the BitField
func (bf BitField) Clear(bit uint64) {
delete(bf.bits, bit)
}

// Has checkes if bit is set in the BitField
func (bf BitField) Has(bit uint64) bool {
_, ok := bf.bits[bit]
return ok
func (bf BitField) Count() (uint64, error) {
s, err := bf.sum()
if err != nil {
return 0, err
}
return rlepluslazy.Count(s)
}

// All returns all set bits, in random order
func (bf BitField) All() []uint64 {
res := make([]uint64, 0, len(bf.bits))
for i := range bf.bits {
res = append(res, i)
func (bf BitField) All() ([]uint64, error) {

runs, err := bf.sum()
if err != nil {
return nil, err
}

sort.Slice(res, func(i, j int) bool { return res[i] < res[j] })
return res
res, err := rlepluslazy.SliceFromRuns(runs)
if err != nil {
return nil, err
}

return res, err
}

func (bf BitField) MarshalCBOR(w io.Writer) error {
Expand All @@ -59,7 +92,12 @@ func (bf BitField) MarshalCBOR(w io.Writer) error {
ints = append(ints, i)
}

rle, _, err := rleplus.Encode(ints) // Encode sorts internally
s, err := bf.sum()
if err != nil {
return err
}

rle, err := rlepluslazy.EncodeRuns(s, []byte{})
if err != nil {
return err
}
Expand Down Expand Up @@ -88,19 +126,17 @@ func (bf *BitField) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("expected byte array")
}

rle := make([]byte, extra)
if _, err := io.ReadFull(br, rle); err != nil {
buf := make([]byte, extra)
if _, err := io.ReadFull(br, buf); err != nil {
return err
}

ints, err := rleplus.Decode(rle)
rle, err := rlepluslazy.FromBuf(buf)
if err != nil {
return xerrors.Errorf("could not decode rle+: %w", err)
}
bf.rle = rle
bf.bits = make(map[uint64]struct{})
for _, i := range ints {
bf.bits[i] = struct{}{}
}

return nil
}
42 changes: 27 additions & 15 deletions lib/rlepluslazy/rleplus.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,18 @@ var (

type RLE struct {
buf []byte

changes []change
}

type change struct {
set bool
reset bool
index uint64
}

func (c change) valid() bool {
return c.reset || c.set
}

func FromBuf(buf []byte) (*RLE, error) {
rle := &RLE{buf: buf}
func FromBuf(buf []byte) (RLE, error) {
rle := RLE{buf: buf}

if len(buf) > 0 && buf[0]&3 != Version {
return nil, xerrors.Errorf("could not create RLE+ for a buffer: %w", ErrWrongVersion)
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
Expand All @@ -45,7 +38,26 @@ func (rle *RLE) RunIterator() (RunIterator, error) {
return source, err
}

func (rle *RLE) Count() (uint64, error) {
it, err := rle.RunIterator()
if err != nil {
return 0, err
}
return Count(it)
}

/*
type change struct {
set bool
reset bool
index uint64
}
func (c change) valid() bool {
return c.reset || c.set
}
func (rle *RLE) RunIterator() (RunIterator, error) {
if err != nil {
return nil, err
}
Expand Down
24 changes: 24 additions & 0 deletions lib/rlepluslazy/runs.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package rlepluslazy

import (
"math"

"golang.org/x/xerrors"
)

func Sum(a, b RunIterator) (RunIterator, error) {
it := addIt{a: a, b: b}
it.prep()
Expand Down Expand Up @@ -94,3 +100,21 @@ 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
}
4 changes: 2 additions & 2 deletions lib/rlepluslazy/runs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ func TestSumRandom(t *testing.T) {
N := 100

for i := 0; i < N; i++ {
abits := randomBits(1000, 2000)
bbits := randomBits(1000, 2000)
abits := randomBits(1000, 1500)
bbits := randomBits(1000, 1500)
sumbits := sum(abits, bbits)

a, err := RunsFromSlice(abits)
Expand Down

0 comments on commit f9b464b

Please sign in to comment.