Remove old bitvector

License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
Jakub Sztandera 2019-09-23 19:59:21 +02:00 committed by Jakub Sztandera
parent 01c0a6ec9f
commit 794490c490
No known key found for this signature in database
GPG Key ID: 9A9AF56F8B3879BA
2 changed files with 0 additions and 382 deletions

View File

@ -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
}
}
}

View File

@ -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))
}
}