70aaa8fc92
This reverts commit 6ed57ede6a
.
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
115 lines
3.0 KiB
Go
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
|
|
}
|