package tsm1 // boolean 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 ( // booleanUncompressed is an uncompressed boolean format. // Not yet implemented. booleanUncompressed = 0 // booleanCompressedBitPacked is an bit packed format using 1 bit per boolean booleanCompressedBitPacked = 1 ) // BooleanEncoder encodes a series of booleans to an in-memory buffer. type BooleanEncoder interface { Write(b bool) Bytes() ([]byte, error) } type booleanEncoder 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 } // NewBooleanEncoder returns a new instance of BooleanEncoder. func NewBooleanEncoder() BooleanEncoder { return &booleanEncoder{} } func (e *booleanEncoder) Write(b bool) { // If we have filled the current byte, flush it if e.i >= 8 { e.flush() } // Use 1 bit for each boolean 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 boolean count e.i++ // Increment the total boolean count e.n++ } func (e *booleanEncoder) 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 *booleanEncoder) 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(booleanCompressedBitPacked) << 4 i := 1 // Encode the number of booleans written i += binary.PutUvarint(b[i:], uint64(e.n)) // Append the packed booleans return append(b[:i], e.bytes...), nil } // BooleanDecoder decodes a series of booleans from an in-memory buffer. type BooleanDecoder interface { Next() bool Read() bool Error() error } type booleanDecoder struct { b []byte i int n int err error } // NewBooleanDecoder returns a new instance of BooleanDecoder. func NewBooleanDecoder(b []byte) BooleanDecoder { // 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 &booleanDecoder{b: b[n:], i: -1, n: int(count)} } func (e *booleanDecoder) Next() bool { e.i++ return e.i < e.n } func (e *booleanDecoder) 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 *booleanDecoder) Error() error { return e.err }