mirror of
https://github.com/Oxalide/vsphere-influxdb-go.git
synced 2023-10-10 13:36:51 +02:00
175 lines
3.8 KiB
Go
175 lines
3.8 KiB
Go
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"
|
|
"fmt"
|
|
)
|
|
|
|
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 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(sz int) BooleanEncoder {
|
|
return BooleanEncoder{
|
|
bytes: make([]byte, 0, (sz+7)/8),
|
|
}
|
|
}
|
|
|
|
// Reset sets the encoder to its initial state.
|
|
func (e *BooleanEncoder) Reset() {
|
|
e.bytes = e.bytes[:0]
|
|
e.b = 0
|
|
e.i = 0
|
|
e.n = 0
|
|
}
|
|
|
|
// Write encodes b to the underlying buffer.
|
|
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
|
|
}
|
|
}
|
|
|
|
// Flush is no-op
|
|
func (e *BooleanEncoder) Flush() {}
|
|
|
|
// Bytes returns a new byte slice containing the encoded booleans from previous calls to Write.
|
|
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 struct {
|
|
b []byte
|
|
i int
|
|
n int
|
|
err error
|
|
}
|
|
|
|
// SetBytes initializes the decoder with a new set of bytes to read from.
|
|
// This must be called before calling any other methods.
|
|
func (e *BooleanDecoder) SetBytes(b []byte) {
|
|
if len(b) == 0 {
|
|
return
|
|
}
|
|
|
|
// First byte stores the encoding type, only have 1 bit-packet format
|
|
// currently ignore for now.
|
|
b = b[1:]
|
|
count, n := binary.Uvarint(b)
|
|
if n <= 0 {
|
|
e.err = fmt.Errorf("BooleanDecoder: invalid count")
|
|
return
|
|
}
|
|
|
|
e.b = b[n:]
|
|
e.i = -1
|
|
e.n = int(count)
|
|
|
|
if min := len(e.b) * 8; min < e.n {
|
|
// Shouldn't happen - TSM file was truncated/corrupted
|
|
e.n = min
|
|
}
|
|
}
|
|
|
|
// Next returns whether there are any bits remaining in the decoder.
|
|
// It returns false if there was an error decoding.
|
|
// The error is available on the Error method.
|
|
func (e *BooleanDecoder) Next() bool {
|
|
if e.err != nil {
|
|
return false
|
|
}
|
|
|
|
e.i++
|
|
return e.i < e.n
|
|
}
|
|
|
|
// Read returns the next bit from the decoder.
|
|
func (e *BooleanDecoder) Read() bool {
|
|
// Index into the byte slice
|
|
idx := e.i >> 3 // integer division by 8
|
|
|
|
// Bit position
|
|
pos := 7 - (e.i & 0x7)
|
|
|
|
// 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
|
|
}
|
|
|
|
// Error returns the error encountered during decoding, if one occurred.
|
|
func (e *BooleanDecoder) Error() error {
|
|
return e.err
|
|
}
|