142 lines
2.9 KiB
Go
142 lines
2.9 KiB
Go
package tsm1
|
|
|
|
// bool encoding uses 1 bit per value. Each compressed byte slice contains a 1 byte header
|
|
// indicating the compression type, followed by a variable byte encoded length indicating
|
|
// how many booleans are packed in the slice. The remaining bytes contains 1 byte for every
|
|
// 8 boolean values encoded.
|
|
|
|
import "encoding/binary"
|
|
|
|
const (
|
|
// boolUncompressed is an uncompressed boolean format.
|
|
// Not yet implemented.
|
|
boolUncompressed = 0
|
|
|
|
// boolCompressedBitPacked is an bit packed format using 1 bit per boolean
|
|
boolCompressedBitPacked = 1
|
|
)
|
|
|
|
// BoolEncoder encodes a series of bools to an in-memory buffer.
|
|
type BoolEncoder interface {
|
|
Write(b bool)
|
|
Bytes() ([]byte, error)
|
|
}
|
|
|
|
type boolEncoder struct {
|
|
// The encoded bytes
|
|
bytes []byte
|
|
|
|
// The current byte being encoded
|
|
b byte
|
|
|
|
// The number of bools packed into b
|
|
i int
|
|
|
|
// The total number of bools written
|
|
n int
|
|
}
|
|
|
|
// NewBoolEncoder returns a new instance of BoolEncoder.
|
|
func NewBoolEncoder() BoolEncoder {
|
|
return &boolEncoder{}
|
|
}
|
|
|
|
func (e *boolEncoder) Write(b bool) {
|
|
// If we have filled the current byte, flush it
|
|
if e.i >= 8 {
|
|
e.flush()
|
|
}
|
|
|
|
// Use 1 bit for each boolen value, shift the current byte
|
|
// by 1 and set the least signficant bit acordingly
|
|
e.b = e.b << 1
|
|
if b {
|
|
e.b |= 1
|
|
}
|
|
|
|
// Increment the current bool count
|
|
e.i++
|
|
// Increment the total bool count
|
|
e.n++
|
|
}
|
|
|
|
func (e *boolEncoder) flush() {
|
|
// Pad remaining byte w/ 0s
|
|
for e.i < 8 {
|
|
e.b = e.b << 1
|
|
e.i++
|
|
}
|
|
|
|
// If we have bits set, append them to the byte slice
|
|
if e.i > 0 {
|
|
e.bytes = append(e.bytes, e.b)
|
|
e.b = 0
|
|
e.i = 0
|
|
}
|
|
}
|
|
|
|
func (e *boolEncoder) Bytes() ([]byte, error) {
|
|
// Ensure the current byte is flushed
|
|
e.flush()
|
|
b := make([]byte, 10+1)
|
|
|
|
// Store the encoding type in the 4 high bits of the first byte
|
|
b[0] = byte(boolCompressedBitPacked) << 4
|
|
|
|
i := 1
|
|
// Encode the number of bools written
|
|
i += binary.PutUvarint(b[i:], uint64(e.n))
|
|
|
|
// Append the packed booleans
|
|
return append(b[:i], e.bytes...), nil
|
|
}
|
|
|
|
// BoolDecoder decodes a series of bools from an in-memory buffer.
|
|
type BoolDecoder interface {
|
|
Next() bool
|
|
Read() bool
|
|
Error() error
|
|
}
|
|
|
|
type boolDecoder struct {
|
|
b []byte
|
|
i int
|
|
n int
|
|
err error
|
|
}
|
|
|
|
// NewBoolDecoder returns a new instance of BoolDecoder.
|
|
func NewBoolDecoder(b []byte) BoolDecoder {
|
|
// First byte stores the encoding type, only have 1 bit-packet format
|
|
// currently ignore for now.
|
|
b = b[1:]
|
|
count, n := binary.Uvarint(b)
|
|
return &boolDecoder{b: b[n:], i: -1, n: int(count)}
|
|
}
|
|
|
|
func (e *boolDecoder) Next() bool {
|
|
e.i++
|
|
return e.i < e.n
|
|
}
|
|
|
|
func (e *boolDecoder) Read() bool {
|
|
// Index into the byte slice
|
|
idx := e.i / 8
|
|
|
|
// Bit position
|
|
pos := (8 - e.i%8) - 1
|
|
|
|
// The mask to select the bit
|
|
mask := byte(1 << uint(pos))
|
|
|
|
// The packed byte
|
|
v := e.b[idx]
|
|
|
|
// Returns true if the bit is set
|
|
return v&mask == mask
|
|
}
|
|
|
|
func (e *boolDecoder) Error() error {
|
|
return e.err
|
|
}
|