diff --git a/lib/rlepluslazy/internal/bitvector.go b/lib/rlepluslazy/internal/bitvector.go deleted file mode 100644 index e6d1971f8..000000000 --- a/lib/rlepluslazy/internal/bitvector.go +++ /dev/null @@ -1,229 +0,0 @@ -package bitvector - -import ( - "errors" - "log" -) - -var ( - // ErrOutOfRange - the index passed is out of range for the BitVector - ErrOutOfRange = errors.New("index out of range") -) - -// BitNumbering indicates the ordering of bits, either -// least-significant bit in position 0, or most-significant bit -// in position 0. -// -// It it used in 3 ways with BitVector: -// 1. Ordering of bits within the Buf []byte structure -// 2. What order to add bits when using Extend() -// 3. What order to read bits when using Take() -// -// https://en.wikipedia.org/wiki/Bit_numbering -type BitNumbering int - -const ( - // LSB0 - bit ordering starts with the low-order bit - LSB0 BitNumbering = iota - - // MSB0 - bit ordering starts with the high-order bit - MSB0 -) - -// BitVector is used to manipulate ordered collections of bits -type BitVector struct { - Buf []byte - - // BytePacking is the bit ordering within bytes - BytePacking BitNumbering - - // Len is the logical number of bits in the vector. - // The last byte in Buf may have undefined bits if Len is not a multiple of 8 - Len uint -} - -// NewBitVector constructs a new BitVector from a slice of bytes. -// -// The bytePacking parameter is required to know how to interpret the bit ordering within the bytes. -func NewBitVector(buf []byte, bytePacking BitNumbering) *BitVector { - return &BitVector{ - BytePacking: bytePacking, - Buf: buf, - Len: uint(len(buf) * 8), - } -} - -// Push adds a single bit to the BitVector. -// -// Although it takes a byte, only the low-order bit is used, so just use 0 or 1. -func (v *BitVector) Push(val byte) { - if v.Len%8 == 0 { - v.Buf = append(v.Buf, 0) - } - lastIdx := v.Len / 8 - - switch v.BytePacking { - case LSB0: - v.Buf[lastIdx] |= (val & 1) << (v.Len % 8) - default: - v.Buf[lastIdx] |= (val & 1) << (7 - (v.Len % 8)) - } - - v.Len++ -} - -// Get returns a single bit as a byte -- either 0 or 1 -func (v *BitVector) Get(idx uint) (byte, error) { - if idx >= v.Len { - return 0, ErrOutOfRange - } - blockIdx := idx / 8 - - switch v.BytePacking { - case LSB0: - return v.Buf[blockIdx] >> (idx % 8) & 1, nil - default: - return v.Buf[blockIdx] >> (7 - idx%8) & 1, nil - } -} - -// Extend adds up to 8 bits to the receiver -// -// Given a byte b == 0b11010101 -// v.Extend(b, 4, LSB0) would add < 1, 0, 1, 0 > -// v.Extend(b, 4, MSB0) would add < 1, 1, 0, 1 > -// -// Panics if count is out of range -func (v *BitVector) Extend(val byte, count uint, order BitNumbering) { - if count > 8 { - log.Panicf("invalid count") - } - - for i := uint(0); i < count; i++ { - switch order { - case LSB0: - v.Push((val >> i) & 1) - default: - v.Push((val >> (7 - i)) & 1) - } - } -} - -// Take reads up to 8 bits at the given index. -// -// Given a BitVector < 1, 1, 0, 1, 0, 1, 0, 1 > -// v.Take(0, 4, LSB0) would return 0b00001011 -// v.Take(0, 4, MSB0) would return 0b11010000 -// -// Panics if count is out of range -func (v *BitVector) Take(index uint, count uint, order BitNumbering) (out byte) { - if count > 8 { - log.Panicf("invalid count") - } - - if order == LSB0 && v.BytePacking == LSB0 { - x := index >> 3 - r := index & 7 - var o uint16 - l := uint(len(v.Buf)) - - if x+1 < l { - o = uint16(v.Buf[x]) | uint16(v.Buf[x+1])<<8 - } else if x < l { - o = uint16(v.Buf[x]) - } - - o = o >> r - return byte(o & (0xFF >> (8 - count))) - } - - for i := uint(0); i < count; i++ { - val, _ := v.Get(index + i) - - switch order { - case LSB0: - out |= val << i - default: - out |= val << (7 - i) - } - } - return -} - -var masks = [9]byte{ - 0x0, - 0x1, - 0x3, - 0x7, - 0xF, - 0x1F, - 0x3F, - 0x7F, - 0xFF, -} - -// Iterator returns a function, which when invoked, returns the number -// of bits requested, and increments an internal cursor. -// -// When the end of the BitVector is reached, it returns zeroes indefinitely -// -// Panics if count is out of range -func (v *BitVector) Iterator(order BitNumbering) func(uint) byte { - if order == LSB0 && v.BytePacking == LSB0 { - // Here be dragons - // This is about 10x faster - index := int(0) - - var rest uint64 - for n := 7; n >= 0; n-- { - var o uint64 - if len(v.Buf) > n { - o = uint64(v.Buf[n]) - } - - rest = rest<<8 | o - index++ - } - - bitCap := uint(64) - - return func(bits uint) (out byte) { - if bits > 8 { - log.Panicf("invalid count") - } - res := byte(rest) & masks[bits] - rest = rest >> bits - bitCap = bitCap - bits - - if bitCap < 8 { - var add uint64 - - for n := 6; n >= 0; n-- { - var o uint64 - if len(v.Buf) > index+n { - o = uint64(v.Buf[index+n]) - } - - add = add<<8 | o - } - index = index + 7 - rest = rest | add<<(bitCap) - bitCap = bitCap + 7*8 - } - - return res - } - - } else { - cursor := uint(0) - return func(count uint) (out byte) { - if count > 8 { - log.Panicf("invalid count") - } - - out = v.Take(cursor, count, order) - cursor += count - return - } - } -} diff --git a/lib/rlepluslazy/internal/bitvector_test.go b/lib/rlepluslazy/internal/bitvector_test.go deleted file mode 100644 index 880a33639..000000000 --- a/lib/rlepluslazy/internal/bitvector_test.go +++ /dev/null @@ -1,153 +0,0 @@ -package bitvector_test - -import ( - "runtime" - "testing" - - "github.com/stretchr/testify/assert" - - bitvector "github.com/filecoin-project/go-lotus/lib/rlepluslazy/internal" -) - -func TestBitVector(t *testing.T) { - t.Run("zero value", func(t *testing.T) { - var v bitvector.BitVector - - assert.Equal(t, bitvector.LSB0, v.BytePacking) - }) - - t.Run("Push", func(t *testing.T) { - // MSB0 bit numbering - v := bitvector.BitVector{BytePacking: bitvector.MSB0} - v.Push(1) - v.Push(0) - v.Push(1) - v.Push(1) - - assert.Equal(t, byte(176), v.Buf[0]) - - // LSB0 bit numbering - v = bitvector.BitVector{BytePacking: bitvector.LSB0} - v.Push(1) - v.Push(0) - v.Push(1) - v.Push(1) - - assert.Equal(t, byte(13), v.Buf[0]) - }) - - t.Run("Get", func(t *testing.T) { - bits := []byte{1, 0, 1, 1, 0, 0, 1, 0} - - for _, numbering := range []bitvector.BitNumbering{bitvector.MSB0, bitvector.LSB0} { - v := bitvector.BitVector{BytePacking: numbering} - - for _, bit := range bits { - v.Push(bit) - } - - for idx, expected := range bits { - actual, _ := v.Get(uint(idx)) - assert.Equal(t, expected, actual) - } - } - }) - - t.Run("Extend", func(t *testing.T) { - val := byte(171) // 0b10101011 - - var v bitvector.BitVector - - // MSB0 bit numbering - v = bitvector.BitVector{} - v.Extend(val, 4, bitvector.MSB0) - assertBitVector(t, []byte{1, 0, 1, 0}, v) - v.Extend(val, 5, bitvector.MSB0) - assertBitVector(t, []byte{1, 0, 1, 0, 1, 0, 1, 0, 1}, v) - - // LSB0 bit numbering - v = bitvector.BitVector{} - v.Extend(val, 4, bitvector.LSB0) - assertBitVector(t, []byte{1, 1, 0, 1}, v) - v.Extend(val, 5, bitvector.LSB0) - assertBitVector(t, []byte{1, 1, 0, 1, 1, 1, 0, 1, 0}, v) - }) - - t.Run("invalid counts to Take/Extend/Iterator cause panics", func(t *testing.T) { - v := bitvector.BitVector{BytePacking: bitvector.LSB0} - - assert.Panics(t, func() { v.Extend(0xff, 9, bitvector.LSB0) }) - - assert.Panics(t, func() { v.Take(0, 9, bitvector.LSB0) }) - - next := v.Iterator(bitvector.LSB0) - assert.Panics(t, func() { next(9) }) - }) - - t.Run("Take", func(t *testing.T) { - var v bitvector.BitVector - - bits := []byte{1, 0, 1, 0, 1, 0, 1, 1} - for _, bit := range bits { - v.Push(bit) - } - - assert.Equal(t, byte(176), v.Take(4, 4, bitvector.MSB0)) - assert.Equal(t, byte(13), v.Take(4, 4, bitvector.LSB0)) - }) - - t.Run("Iterator", func(t *testing.T) { - var buf []byte - - // make a bitvector of 256 sample bits - for i := 0; i < 1000; i++ { - buf = append(buf, byte(i)) - } - - v := bitvector.NewBitVector(buf, bitvector.LSB0) - - next := v.Iterator(bitvector.LSB0) - - // compare to Get() - for i := uint(0); i < v.Len; i++ { - expected, _ := v.Get(i) - assert.Equal(t, expected, next(1), "at index %d", i) - } - - // out of range should return zero - assert.Equal(t, byte(0), next(1)) - assert.Equal(t, byte(0), next(8)) - - // compare to Take() - next = v.Iterator(bitvector.LSB0) - assert.Equal(t, next(5), v.Take(0, 5, bitvector.LSB0)) - assert.Equal(t, next(8), v.Take(5, 8, bitvector.LSB0)) - }) -} - -// Note: When using this helper assertion, expectedBits should *only* be 0s and 1s. -func assertBitVector(t *testing.T, expectedBits []byte, actual bitvector.BitVector) { - assert.Equal(t, uint(len(expectedBits)), actual.Len) - - for idx, bit := range expectedBits { - actualBit, err := actual.Get(uint(idx)) - assert.NoError(t, err) - assert.Equal(t, bit, actualBit) - } -} - -func BenchmarkTake(b *testing.B) { - buf := make([]byte, 0, 128) - for i := 0; i < 128; i++ { - buf = append(buf, byte(128+i)) - } - - v := bitvector.NewBitVector(buf, bitvector.LSB0) - b.ReportAllocs() - b.ResetTimer() - - next := v.Iterator(bitvector.LSB0) - for i := 0; i < b.N; i++ { - runtime.KeepAlive(next(8)) - } -}