2019-05-22 21:16:55 +00:00
|
|
|
package encoding
|
|
|
|
|
|
|
|
import (
|
2019-09-20 10:07:59 +00:00
|
|
|
"encoding/binary"
|
2019-05-22 21:16:55 +00:00
|
|
|
"fmt"
|
|
|
|
"sync"
|
2024-05-12 09:24:48 +00:00
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
|
2019-05-22 21:16:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MarshalUint16 appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalUint16(dst []byte, u uint16) []byte {
|
|
|
|
return append(dst, byte(u>>8), byte(u))
|
|
|
|
}
|
|
|
|
|
2023-06-20 05:40:52 +00:00
|
|
|
// UnmarshalUint16 returns unmarshaled uint16 from src.
|
2024-01-23 20:50:11 +00:00
|
|
|
//
|
|
|
|
// the caller must ensure that len(src) >= 2
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalUint16(src []byte) uint16 {
|
2019-09-20 10:07:59 +00:00
|
|
|
// This is faster than the manual conversion.
|
2024-01-23 20:50:11 +00:00
|
|
|
return binary.BigEndian.Uint16(src)
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalUint32 appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalUint32(dst []byte, u uint32) []byte {
|
|
|
|
return append(dst, byte(u>>24), byte(u>>16), byte(u>>8), byte(u))
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalUint32 returns unmarshaled uint32 from src.
|
2024-01-23 20:50:11 +00:00
|
|
|
//
|
|
|
|
// The caller must ensure than len(src) >= 4
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalUint32(src []byte) uint32 {
|
2019-09-20 10:07:59 +00:00
|
|
|
// This is faster than the manual conversion.
|
2024-01-23 20:50:11 +00:00
|
|
|
return binary.BigEndian.Uint32(src)
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalUint64 appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalUint64(dst []byte, u uint64) []byte {
|
|
|
|
return append(dst, byte(u>>56), byte(u>>48), byte(u>>40), byte(u>>32), byte(u>>24), byte(u>>16), byte(u>>8), byte(u))
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalUint64 returns unmarshaled uint64 from src.
|
2024-01-23 20:50:11 +00:00
|
|
|
//
|
|
|
|
// The caller must ensure that len(src) >= 8
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalUint64(src []byte) uint64 {
|
2019-09-20 10:07:59 +00:00
|
|
|
// This is faster than the manual conversion.
|
2024-01-23 20:50:11 +00:00
|
|
|
return binary.BigEndian.Uint64(src)
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalInt16 appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalInt16(dst []byte, v int16) []byte {
|
|
|
|
// Such encoding for negative v must improve compression.
|
|
|
|
v = (v << 1) ^ (v >> 15) // zig-zag encoding without branching.
|
|
|
|
u := uint16(v)
|
|
|
|
return append(dst, byte(u>>8), byte(u))
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalInt16 returns unmarshaled int16 from src.
|
2024-01-23 20:50:11 +00:00
|
|
|
//
|
|
|
|
// The caller must ensure that len(src) >= 2
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalInt16(src []byte) int16 {
|
2019-09-20 10:07:59 +00:00
|
|
|
// This is faster than the manual conversion.
|
2024-01-23 20:50:11 +00:00
|
|
|
u := binary.BigEndian.Uint16(src)
|
2019-05-22 21:16:55 +00:00
|
|
|
v := int16(u>>1) ^ (int16(u<<15) >> 15) // zig-zag decoding without branching.
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalInt64 appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalInt64(dst []byte, v int64) []byte {
|
|
|
|
// Such encoding for negative v must improve compression.
|
|
|
|
v = (v << 1) ^ (v >> 63) // zig-zag encoding without branching.
|
|
|
|
u := uint64(v)
|
|
|
|
return append(dst, byte(u>>56), byte(u>>48), byte(u>>40), byte(u>>32), byte(u>>24), byte(u>>16), byte(u>>8), byte(u))
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalInt64 returns unmarshaled int64 from src.
|
2024-01-23 20:50:11 +00:00
|
|
|
//
|
|
|
|
// The caller must ensure that len(src) >= 8
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalInt64(src []byte) int64 {
|
2019-09-20 10:07:59 +00:00
|
|
|
// This is faster than the manual conversion.
|
2024-01-23 20:50:11 +00:00
|
|
|
u := binary.BigEndian.Uint64(src)
|
2019-05-22 21:16:55 +00:00
|
|
|
v := int64(u>>1) ^ (int64(u<<63) >> 63) // zig-zag decoding without branching.
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalVarInt64 appends marshalsed v to dst and returns the result.
|
|
|
|
func MarshalVarInt64(dst []byte, v int64) []byte {
|
2024-05-12 14:32:11 +00:00
|
|
|
u := uint64((v << 1) ^ (v >> 63))
|
|
|
|
|
|
|
|
if v < (1<<6) && v > (-1<<6) {
|
|
|
|
return append(dst, byte(u))
|
|
|
|
}
|
|
|
|
if u < (1 << (2 * 7)) {
|
|
|
|
return append(dst, byte(u|0x80), byte(u>>7))
|
|
|
|
}
|
|
|
|
if u < (1 << (3 * 7)) {
|
|
|
|
return append(dst, byte(u|0x80), byte((u>>7)|0x80), byte(u>>(2*7)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slow path for big integers
|
|
|
|
var tmp [1]uint64
|
|
|
|
tmp[0] = u
|
|
|
|
return MarshalVarUint64s(dst, tmp[:])
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalVarInt64s appends marshaled vs to dst and returns the result.
|
|
|
|
func MarshalVarInt64s(dst []byte, vs []int64) []byte {
|
2024-02-01 03:36:28 +00:00
|
|
|
dstLen := len(dst)
|
2019-05-22 21:16:55 +00:00
|
|
|
for _, v := range vs {
|
2024-02-01 03:36:28 +00:00
|
|
|
if v >= (1<<6) || v <= (-1<<6) {
|
|
|
|
return marshalVarInt64sSlow(dst[:dstLen], vs)
|
|
|
|
}
|
|
|
|
u := uint64((v << 1) ^ (v >> 63))
|
|
|
|
dst = append(dst, byte(u))
|
|
|
|
}
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
func marshalVarInt64sSlow(dst []byte, vs []int64) []byte {
|
|
|
|
for _, v := range vs {
|
|
|
|
u := uint64((v << 1) ^ (v >> 63))
|
|
|
|
|
|
|
|
// Cases below are sorted in the descending order of frequency on real data
|
|
|
|
if u < (1 << 7) {
|
|
|
|
dst = append(dst, byte(u))
|
2019-05-22 21:16:55 +00:00
|
|
|
continue
|
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
if u < (1 << (2 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte(u>>7))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (3 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte(u>>(2*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if u >= (1 << (8 * 7)) {
|
|
|
|
if u < (1 << (9 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte((u>>(7*7))|0x80), byte(u>>(8*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte((u>>(7*7))|0x80), byte((u>>(8*7))|0x80), 1)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if u < (1 << (4 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte(u>>(3*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (5 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte(u>>(4*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (6 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80), byte(u>>(5*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (7 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80), byte((u>>(5*7))|0x80), byte(u>>(6*7)))
|
|
|
|
continue
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte(u>>(7*7)))
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
2024-05-12 14:32:11 +00:00
|
|
|
// UnmarshalVarInt64 returns unmarshaled int64 from src and returns the remaining tail from src.
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalVarInt64(src []byte) ([]byte, int64, error) {
|
2024-05-12 14:32:11 +00:00
|
|
|
// TODO substitute binary.Uvarint with binary.Varint when benchmark results will show it is faster.
|
|
|
|
// It is slower on amd64/linux Go1.22.
|
|
|
|
u64, offset := binary.Uvarint(src)
|
|
|
|
if offset <= 0 {
|
|
|
|
return src, 0, fmt.Errorf("cannot unmarshal varint")
|
|
|
|
}
|
|
|
|
i64 := int64(int64(u64>>1) ^ (int64(u64<<63) >> 63))
|
|
|
|
return src[offset:], i64, nil
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
2024-05-12 14:32:11 +00:00
|
|
|
// UnmarshalVarInt64s unmarshals len(dst) int64 values from src to dst and returns the remaining tail from src.
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalVarInt64s(dst []int64, src []byte) ([]byte, error) {
|
2024-02-01 03:36:28 +00:00
|
|
|
if len(src) < len(dst) {
|
|
|
|
return src, fmt.Errorf("too small len(src)=%d; it must be bigger or equal to len(dst)=%d", len(src), len(dst))
|
|
|
|
}
|
|
|
|
for i := range dst {
|
|
|
|
c := src[i]
|
|
|
|
if c >= 0x80 {
|
|
|
|
return unmarshalVarInt64sSlow(dst, src)
|
|
|
|
}
|
|
|
|
dst[i] = int64(int8(c>>1) ^ (int8(c<<7) >> 7))
|
|
|
|
}
|
|
|
|
return src[len(dst):], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshalVarInt64sSlow(dst []int64, src []byte) ([]byte, error) {
|
2019-05-22 21:16:55 +00:00
|
|
|
idx := uint(0)
|
|
|
|
for i := range dst {
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("cannot unmarshal varint from empty data")
|
|
|
|
}
|
|
|
|
c := src[idx]
|
|
|
|
idx++
|
|
|
|
if c < 0x80 {
|
2024-02-01 03:36:28 +00:00
|
|
|
// Fast path for 1 byte
|
|
|
|
dst[i] = int64(int8(c>>1) ^ (int8(c<<7) >> 7))
|
2019-05-22 21:16:55 +00:00
|
|
|
continue
|
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varint at byte 1; src=%x", src[idx-1:])
|
|
|
|
}
|
|
|
|
d := src[idx]
|
|
|
|
idx++
|
|
|
|
if d < 0x80 {
|
|
|
|
// Fast path for 2 bytes
|
|
|
|
u := uint64(c&0x7f) | (uint64(d) << 7)
|
|
|
|
dst[i] = int64(u>>1) ^ (int64(u<<63) >> 63)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varint at byte 2; src=%x", src[idx-2:])
|
|
|
|
}
|
|
|
|
e := src[idx]
|
|
|
|
idx++
|
|
|
|
if e < 0x80 {
|
|
|
|
// Fast path for 3 bytes
|
|
|
|
u := uint64(c&0x7f) | (uint64(d&0x7f) << 7) | (uint64(e) << (2 * 7))
|
|
|
|
dst[i] = int64(u>>1) ^ (int64(u<<63) >> 63)
|
2024-02-01 03:33:59 +00:00
|
|
|
continue
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
|
|
|
|
u := uint64(c&0x7f) | (uint64(d&0x7f) << 7) | (uint64(e&0x7f) << (2 * 7))
|
|
|
|
|
|
|
|
// Slow path
|
|
|
|
j := idx
|
|
|
|
for {
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varint; src=%x", src[j-3:])
|
|
|
|
}
|
|
|
|
c := src[idx]
|
|
|
|
idx++
|
|
|
|
if c < 0x80 {
|
2024-02-01 03:33:59 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
|
|
|
|
// These are the most common cases
|
|
|
|
switch idx - j {
|
|
|
|
case 1:
|
|
|
|
u |= (uint64(src[j]) << (3 * 7))
|
|
|
|
case 2:
|
|
|
|
b := src[j : j+2 : j+2]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]) << (4 * 7))
|
|
|
|
case 3:
|
|
|
|
b := src[j : j+3 : j+3]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]) << (5 * 7))
|
|
|
|
case 4:
|
|
|
|
b := src[j : j+4 : j+4]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]) << (6 * 7))
|
|
|
|
case 5:
|
|
|
|
b := src[j : j+5 : j+5]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]) << (7 * 7))
|
|
|
|
case 6:
|
|
|
|
b := src[j : j+6 : j+6]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]&0x7f) << (7 * 7)) | (uint64(b[5]) << (8 * 7))
|
|
|
|
case 7:
|
|
|
|
b := src[j : j+7 : j+7]
|
|
|
|
if b[6] > 1 {
|
|
|
|
return src[idx:], fmt.Errorf("too big encoded varint; src=%x", src[j-3:])
|
|
|
|
}
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]&0x7f) << (7 * 7)) | (uint64(b[5]&0x7f) << (8 * 7)) | (1 << (9 * 7))
|
|
|
|
default:
|
|
|
|
return src[idx:], fmt.Errorf("too long encoded varint; the maximum allowed length is 10 bytes; got %d bytes; src=%x", idx-j+3, src[j-3:])
|
2024-02-01 03:33:59 +00:00
|
|
|
}
|
2019-05-22 21:16:55 +00:00
|
|
|
|
2024-02-01 03:36:28 +00:00
|
|
|
dst[i] = int64(u>>1) ^ (int64(u<<63) >> 63)
|
2024-02-01 03:33:59 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
return src[idx:], nil
|
2024-02-01 03:33:59 +00:00
|
|
|
}
|
|
|
|
|
2019-05-22 21:16:55 +00:00
|
|
|
// MarshalVarUint64 appends marshaled u to dst and returns the result.
|
|
|
|
func MarshalVarUint64(dst []byte, u uint64) []byte {
|
2024-05-12 14:32:11 +00:00
|
|
|
if u < (1 << 7) {
|
|
|
|
return append(dst, byte(u))
|
|
|
|
}
|
|
|
|
if u < (1 << (2 * 7)) {
|
|
|
|
return append(dst, byte(u|0x80), byte(u>>7))
|
|
|
|
}
|
|
|
|
if u < (1 << (3 * 7)) {
|
|
|
|
return append(dst, byte(u|0x80), byte((u>>7)|0x80), byte(u>>(2*7)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slow path for big integers.
|
2019-05-22 21:16:55 +00:00
|
|
|
var tmp [1]uint64
|
|
|
|
tmp[0] = u
|
|
|
|
return MarshalVarUint64s(dst, tmp[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalVarUint64s appends marshaled us to dst and returns the result.
|
|
|
|
func MarshalVarUint64s(dst []byte, us []uint64) []byte {
|
2024-02-01 03:36:28 +00:00
|
|
|
dstLen := len(dst)
|
|
|
|
for _, u := range us {
|
|
|
|
if u >= (1 << 7) {
|
|
|
|
return marshalVarUint64sSlow(dst[:dstLen], us)
|
|
|
|
}
|
|
|
|
dst = append(dst, byte(u))
|
|
|
|
}
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
func marshalVarUint64sSlow(dst []byte, us []uint64) []byte {
|
2019-05-22 21:16:55 +00:00
|
|
|
for _, u := range us {
|
2024-02-01 03:36:28 +00:00
|
|
|
// Cases below are sorted in the descending order of frequency on real data
|
|
|
|
if u < (1 << 7) {
|
2019-05-22 21:16:55 +00:00
|
|
|
dst = append(dst, byte(u))
|
|
|
|
continue
|
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
if u < (1 << (2 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte(u>>7))
|
|
|
|
continue
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
if u < (1 << (3 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte(u>>(2*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if u >= (1 << (8 * 7)) {
|
|
|
|
if u < (1 << (9 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte((u>>(7*7))|0x80), byte(u>>(8*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte((u>>(7*7))|0x80), byte((u>>(8*7))|0x80), 1)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if u < (1 << (4 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte(u>>(3*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (5 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte(u>>(4*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (6 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80), byte(u>>(5*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if u < (1 << (7 * 7)) {
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80), byte((u>>(5*7))|0x80), byte(u>>(6*7)))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
dst = append(dst, byte(u|0x80), byte((u>>7)|0x80), byte((u>>(2*7))|0x80), byte((u>>(3*7))|0x80), byte((u>>(4*7))|0x80),
|
|
|
|
byte((u>>(5*7))|0x80), byte((u>>(6*7))|0x80), byte(u>>(7*7)))
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
2024-05-12 14:32:11 +00:00
|
|
|
// UnmarshalVarUint64 returns unmarshaled uint64 from src and returns the remaining tail from src.
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalVarUint64(src []byte) ([]byte, uint64, error) {
|
2024-05-12 14:32:11 +00:00
|
|
|
u64, offset := binary.Uvarint(src)
|
|
|
|
if offset <= 0 {
|
|
|
|
return src, 0, fmt.Errorf("cannot read varuint")
|
|
|
|
}
|
|
|
|
return src[offset:], u64, nil
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
2024-05-12 14:32:11 +00:00
|
|
|
// UnmarshalVarUint64s unmarshals len(dst) uint64 values from src to dst and returns the remaining tail from src.
|
2019-05-22 21:16:55 +00:00
|
|
|
func UnmarshalVarUint64s(dst []uint64, src []byte) ([]byte, error) {
|
2024-02-01 03:36:28 +00:00
|
|
|
if len(src) < len(dst) {
|
|
|
|
return src, fmt.Errorf("too small len(src)=%d; it must be bigger or equal to len(dst)=%d", len(src), len(dst))
|
|
|
|
}
|
|
|
|
for i := range dst {
|
|
|
|
c := src[i]
|
|
|
|
if c >= 0x80 {
|
|
|
|
return unmarshalVarUint64sSlow(dst, src)
|
|
|
|
}
|
|
|
|
dst[i] = uint64(c)
|
|
|
|
}
|
|
|
|
return src[len(dst):], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshalVarUint64sSlow(dst []uint64, src []byte) ([]byte, error) {
|
2019-05-22 21:16:55 +00:00
|
|
|
idx := uint(0)
|
|
|
|
for i := range dst {
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("cannot unmarshal varuint from empty data")
|
|
|
|
}
|
|
|
|
c := src[idx]
|
|
|
|
idx++
|
|
|
|
if c < 0x80 {
|
2024-02-01 03:36:28 +00:00
|
|
|
// Fast path for 1 byte
|
2019-05-22 21:16:55 +00:00
|
|
|
dst[i] = uint64(c)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-02-01 03:36:28 +00:00
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varuint at byte 1; src=%x", src[idx-1:])
|
|
|
|
}
|
|
|
|
d := src[idx]
|
|
|
|
idx++
|
|
|
|
if d < 0x80 {
|
|
|
|
// Fast path for 2 bytes
|
|
|
|
dst[i] = uint64(c&0x7f) | (uint64(d) << 7)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if idx >= uint(len(src)) {
|
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varuint at byte 2; src=%x", src[idx-2:])
|
|
|
|
}
|
|
|
|
e := src[idx]
|
|
|
|
idx++
|
|
|
|
if e < 0x80 {
|
|
|
|
// Fast path for 3 bytes
|
|
|
|
dst[i] = uint64(c&0x7f) | (uint64(d&0x7f) << 7) | (uint64(e) << (2 * 7))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
u := uint64(c&0x7f) | (uint64(d&0x7f) << 7) | (uint64(e&0x7f) << (2 * 7))
|
|
|
|
|
2019-05-22 21:16:55 +00:00
|
|
|
// Slow path
|
2024-02-01 03:36:28 +00:00
|
|
|
j := idx
|
|
|
|
for {
|
2019-05-22 21:16:55 +00:00
|
|
|
if idx >= uint(len(src)) {
|
2024-02-01 03:36:28 +00:00
|
|
|
return nil, fmt.Errorf("unexpected end of encoded varint; src=%x", src[j-3:])
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
c := src[idx]
|
2019-05-22 21:16:55 +00:00
|
|
|
idx++
|
2024-02-01 03:36:28 +00:00
|
|
|
if c < 0x80 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// These are the most common cases
|
|
|
|
switch idx - j {
|
|
|
|
case 1:
|
|
|
|
u |= (uint64(src[j]) << (3 * 7))
|
|
|
|
case 2:
|
|
|
|
b := src[j : j+2 : j+2]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]) << (4 * 7))
|
|
|
|
case 3:
|
|
|
|
b := src[j : j+3 : j+3]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]) << (5 * 7))
|
|
|
|
case 4:
|
|
|
|
b := src[j : j+4 : j+4]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]) << (6 * 7))
|
|
|
|
case 5:
|
|
|
|
b := src[j : j+5 : j+5]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]) << (7 * 7))
|
|
|
|
case 6:
|
|
|
|
b := src[j : j+6 : j+6]
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]&0x7f) << (7 * 7)) | (uint64(b[5]) << (8 * 7))
|
|
|
|
case 7:
|
|
|
|
b := src[j : j+7 : j+7]
|
|
|
|
if b[6] > 1 {
|
|
|
|
return src[idx:], fmt.Errorf("too big encoded varuint; src=%x", src[j-3:])
|
|
|
|
}
|
|
|
|
u |= (uint64(b[0]&0x7f) << (3 * 7)) | (uint64(b[1]&0x7f) << (4 * 7)) | (uint64(b[2]&0x7f) << (5 * 7)) | (uint64(b[3]&0x7f) << (6 * 7)) |
|
|
|
|
(uint64(b[4]&0x7f) << (7 * 7)) | (uint64(b[5]&0x7f) << (8 * 7)) | (1 << (9 * 7))
|
|
|
|
default:
|
|
|
|
return src[idx:], fmt.Errorf("too long encoded varuint; the maximum allowed length is 10 bytes; got %d bytes; src=%x", idx-j+3, src[j-3:])
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
2024-02-01 03:36:28 +00:00
|
|
|
|
2019-05-22 21:16:55 +00:00
|
|
|
dst[i] = u
|
|
|
|
}
|
|
|
|
return src[idx:], nil
|
|
|
|
}
|
|
|
|
|
2023-06-20 05:40:52 +00:00
|
|
|
// MarshalBool appends marshaled v to dst and returns the result.
|
|
|
|
func MarshalBool(dst []byte, v bool) []byte {
|
|
|
|
x := byte(0)
|
|
|
|
if v {
|
|
|
|
x = 1
|
|
|
|
}
|
|
|
|
return append(dst, x)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalBool unmarshals bool from src.
|
|
|
|
func UnmarshalBool(src []byte) bool {
|
|
|
|
return src[0] != 0
|
|
|
|
}
|
|
|
|
|
2019-05-22 21:16:55 +00:00
|
|
|
// MarshalBytes appends marshaled b to dst and returns the result.
|
|
|
|
func MarshalBytes(dst, b []byte) []byte {
|
|
|
|
dst = MarshalVarUint64(dst, uint64(len(b)))
|
|
|
|
dst = append(dst, b...)
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalBytes returns unmarshaled bytes from src.
|
|
|
|
func UnmarshalBytes(src []byte) ([]byte, []byte, error) {
|
|
|
|
tail, n, err := UnmarshalVarUint64(src)
|
|
|
|
if err != nil {
|
2020-06-30 19:58:18 +00:00
|
|
|
return nil, nil, fmt.Errorf("cannot unmarshal string size: %w", err)
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
src = tail
|
|
|
|
if uint64(len(src)) < n {
|
|
|
|
return nil, nil, fmt.Errorf("src is too short for reading string with size %d; len(src)=%d", n, len(src))
|
|
|
|
}
|
|
|
|
return src[n:], src[:n], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetInt64s returns an int64 slice with the given size.
|
|
|
|
// The slice contents isn't initialized - it may contain garbage.
|
|
|
|
func GetInt64s(size int) *Int64s {
|
|
|
|
v := int64sPool.Get()
|
|
|
|
if v == nil {
|
|
|
|
return &Int64s{
|
|
|
|
A: make([]int64, size),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is := v.(*Int64s)
|
2024-05-12 09:24:48 +00:00
|
|
|
is.A = slicesutil.SetLength(is.A, size)
|
2019-05-22 21:16:55 +00:00
|
|
|
return is
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutInt64s returns is to the pool.
|
|
|
|
func PutInt64s(is *Int64s) {
|
|
|
|
int64sPool.Put(is)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Int64s holds an int64 slice
|
|
|
|
type Int64s struct {
|
|
|
|
A []int64
|
|
|
|
}
|
|
|
|
|
|
|
|
var int64sPool sync.Pool
|
|
|
|
|
|
|
|
// GetUint64s returns an uint64 slice with the given size.
|
|
|
|
// The slice contents isn't initialized - it may contain garbage.
|
|
|
|
func GetUint64s(size int) *Uint64s {
|
|
|
|
v := uint64sPool.Get()
|
|
|
|
if v == nil {
|
|
|
|
return &Uint64s{
|
|
|
|
A: make([]uint64, size),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is := v.(*Uint64s)
|
2024-05-12 09:24:48 +00:00
|
|
|
is.A = slicesutil.SetLength(is.A, size)
|
2019-05-22 21:16:55 +00:00
|
|
|
return is
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutUint64s returns is to the pool.
|
|
|
|
func PutUint64s(is *Uint64s) {
|
|
|
|
uint64sPool.Put(is)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uint64s holds an uint64 slice
|
|
|
|
type Uint64s struct {
|
|
|
|
A []uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
var uint64sPool sync.Pool
|
2023-06-20 05:40:52 +00:00
|
|
|
|
|
|
|
// GetUint32s returns an uint32 slice with the given size.
|
|
|
|
// The slize contents isn't initialized - it may contain garbage.
|
|
|
|
func GetUint32s(size int) *Uint32s {
|
|
|
|
v := uint32sPool.Get()
|
|
|
|
if v == nil {
|
|
|
|
return &Uint32s{
|
|
|
|
A: make([]uint32, size),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is := v.(*Uint32s)
|
2024-05-12 09:24:48 +00:00
|
|
|
is.A = slicesutil.SetLength(is.A, size)
|
2023-06-20 05:40:52 +00:00
|
|
|
return is
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutUint32s returns is to the pool.
|
|
|
|
func PutUint32s(is *Uint32s) {
|
|
|
|
uint32sPool.Put(is)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uint32s holds an uint32 slice
|
|
|
|
type Uint32s struct {
|
|
|
|
A []uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
var uint32sPool sync.Pool
|