influxdb/tsdb/engine/tsm1/bool.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
}