Remove unnecessary allocations from int64 decoder
The decoder was creating a large slice and decoding all values when instead, it could decode one packed value as needed.pull/4317/merge
parent
5a49e1a04b
commit
8d2ecb5df5
|
@ -46,14 +46,12 @@ func (e *int64Encoder) encodePacked() ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b := make([]byte, 1+len(encoded)*8+4)
|
b := make([]byte, 1+len(encoded)*8)
|
||||||
// 4 high bits of first byte store the encoding type for the block
|
// 4 high bits of first byte store the encoding type for the block
|
||||||
b[0] = byte(EncodingPacked) << 4
|
b[0] = byte(EncodingPacked) << 4
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(b[1:5], uint32(len(e.values)))
|
|
||||||
|
|
||||||
for i, v := range encoded {
|
for i, v := range encoded {
|
||||||
binary.BigEndian.PutUint64(b[5+i*8:5+i*8+8], v)
|
binary.BigEndian.PutUint64(b[1+i*8:1+i*8+8], v)
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
@ -64,86 +62,78 @@ func (e *int64Encoder) encodeUncompressed() ([]byte, error) {
|
||||||
b[0] = byte(EncodingUncompressed) << 4
|
b[0] = byte(EncodingUncompressed) << 4
|
||||||
|
|
||||||
for i, v := range e.values {
|
for i, v := range e.values {
|
||||||
binary.BigEndian.PutUint64(b[1+i*8:1+i*8+8], uint64(v))
|
binary.BigEndian.PutUint64(b[1+i*8:1+i*8+8], v)
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type int64Decoder struct {
|
type int64Decoder struct {
|
||||||
values []uint64
|
values []uint64
|
||||||
v int64
|
bytes []byte
|
||||||
buf []uint64
|
i int
|
||||||
vbuf []uint64
|
n int
|
||||||
|
|
||||||
|
encoding byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInt64Decoder(b []byte) Int64Decoder {
|
func NewInt64Decoder(b []byte) Int64Decoder {
|
||||||
d := &int64Decoder{
|
d := &int64Decoder{
|
||||||
buf: make([]uint64, 240),
|
values: make([]uint64, 240),
|
||||||
vbuf: make([]uint64, 1),
|
|
||||||
}
|
}
|
||||||
d.decode(b)
|
|
||||||
|
d.SetBytes(b)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *int64Decoder) SetBytes(b []byte) {
|
func (d *int64Decoder) SetBytes(b []byte) {
|
||||||
d.decode(b)
|
if len(b) > 0 {
|
||||||
|
d.encoding = b[0] >> 4
|
||||||
|
d.bytes = b[1:]
|
||||||
|
}
|
||||||
|
d.i = 0
|
||||||
|
d.n = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *int64Decoder) Next() bool {
|
func (d *int64Decoder) Next() bool {
|
||||||
if len(d.values) == 0 {
|
if d.i >= d.n && len(d.bytes) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
d.v = ZigZagDecode(d.values[0])
|
|
||||||
d.values = d.values[1:]
|
d.i += 1
|
||||||
return true
|
|
||||||
|
if d.i >= d.n {
|
||||||
|
switch d.encoding {
|
||||||
|
case EncodingUncompressed:
|
||||||
|
d.decodeUncompressed()
|
||||||
|
case EncodingPacked:
|
||||||
|
d.decodePacked()
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown encoding %v", d.encoding))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d.i < d.n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *int64Decoder) Read() int64 {
|
func (d *int64Decoder) Read() int64 {
|
||||||
return d.v
|
return ZigZagDecode(d.values[d.i])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *int64Decoder) decode(b []byte) {
|
func (d *int64Decoder) decodePacked() {
|
||||||
if len(b) == 0 {
|
if len(d.bytes) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encoding type is stored in the 4 high bits of the first byte
|
v := binary.BigEndian.Uint64(d.bytes[0:8])
|
||||||
encoding := b[0] >> 4
|
n, _ := simple8b.DecodeSingle(d.values, v)
|
||||||
switch encoding {
|
|
||||||
case EncodingUncompressed:
|
d.n = n
|
||||||
d.decodeUncompressed(b[1:])
|
d.i = 0
|
||||||
case EncodingPacked:
|
d.bytes = d.bytes[8:]
|
||||||
d.decodePacked(b[1:])
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unknown encoding %v", encoding))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *int64Decoder) decodePacked(b []byte) {
|
func (d *int64Decoder) decodeUncompressed() {
|
||||||
if len(b) == 0 {
|
d.values[0] = binary.BigEndian.Uint64(d.bytes[0:8])
|
||||||
return
|
d.i = 0
|
||||||
}
|
d.n = 1
|
||||||
|
d.bytes = d.bytes[8:]
|
||||||
count := binary.BigEndian.Uint32(b[:4])
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
d.values = make([]uint64, count)
|
|
||||||
b = b[4:]
|
|
||||||
j := 0
|
|
||||||
for i := 0; i < len(b); i += 8 {
|
|
||||||
d.vbuf[0] = binary.BigEndian.Uint64(b[i : i+8])
|
|
||||||
n, _ := simple8b.Decode(d.buf, d.vbuf)
|
|
||||||
copy(d.values[j:], d.buf[:n])
|
|
||||||
j += n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *int64Decoder) decodeUncompressed(b []byte) {
|
|
||||||
d.values = make([]uint64, len(b)/8)
|
|
||||||
for i := range d.values {
|
|
||||||
d.values[i] = binary.BigEndian.Uint64(b[i*8 : i*8+8])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,10 @@ func Test_Int64Encoder_AllNegative(t *testing.T) {
|
||||||
dec := pd1.NewInt64Decoder(b)
|
dec := pd1.NewInt64Decoder(b)
|
||||||
i := 0
|
i := 0
|
||||||
for dec.Next() {
|
for dec.Next() {
|
||||||
|
if i > len(values) {
|
||||||
|
t.Fatalf("read too many values: got %v, exp %v", i, len(values))
|
||||||
|
}
|
||||||
|
|
||||||
if values[i] != dec.Read() {
|
if values[i] != dec.Read() {
|
||||||
t.Fatalf("read value %d mismatch: got %v, exp %v", i, dec.Read(), values[i])
|
t.Fatalf("read value %d mismatch: got %v, exp %v", i, dec.Read(), values[i])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue