lotus/lib/rlepluslazy/bitvec.go
Jakub Sztandera 70aaa8fc92
Revert "Fix small bug in RLE"
This reverts commit 6ed57ede6a.

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-01-30 16:14:32 -08:00

115 lines
3.0 KiB
Go

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
}