You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
621 lines
11 KiB
621 lines
11 KiB
package bin
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
)
|
|
|
|
const (
|
|
varInt64SignFlag = 0b01000000
|
|
maxReadAttempts = 5
|
|
)
|
|
|
|
var (
|
|
ErrNoSpace = errors.New("no space")
|
|
ErrIncompleteWrite = errors.New("incomplete write")
|
|
|
|
ErrReadOverflow = errors.New("bin: reader returned 'n' > bufsize")
|
|
// ErrNegativeReadCount shows 100% bug in the source reader
|
|
ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'")
|
|
)
|
|
|
|
// READ
|
|
|
|
func ReadUint16(src io.Reader) (num uint16, err error) {
|
|
var (
|
|
q = 2
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return GetUint16(arr), nil
|
|
}
|
|
|
|
func ReadUint24AsInt(src io.Reader) (num int, err error) {
|
|
var (
|
|
q = 3
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return GetUint24AsInt(arr), nil
|
|
}
|
|
|
|
func ReadUint32(src io.Reader) (num uint32, err error) {
|
|
var (
|
|
q = 4
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return GetUint32(arr), nil
|
|
}
|
|
|
|
func ReadUint64(src io.Reader) (num uint64, err error) {
|
|
var (
|
|
q = 8
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return GetUint64(arr), nil
|
|
}
|
|
|
|
func ReadFloat64(src io.Reader) (num float64, err error) {
|
|
var (
|
|
q = 8
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return GetFloat64(arr), nil
|
|
}
|
|
|
|
func ReadUnixtime(src io.Reader) (num int64, err error) {
|
|
var (
|
|
q = 8
|
|
arr = make([]byte, q)
|
|
)
|
|
n, err := src.Read(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if n != q {
|
|
return 0, fmt.Errorf("read %d bytes only", n)
|
|
}
|
|
return int64(GetUint64(arr)), nil
|
|
}
|
|
|
|
// READ VAR
|
|
|
|
func ReadVarUint64(src io.Reader) (num uint64, n int, err error) {
|
|
var (
|
|
p = make([]byte, 1)
|
|
b byte
|
|
)
|
|
for i := range 8 {
|
|
_, err = src.Read(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
n++
|
|
b = p[0]
|
|
if b >= 128 {
|
|
num |= uint64(b&127) << uint(i*7)
|
|
return
|
|
}
|
|
num |= uint64(b) << uint(i*7)
|
|
}
|
|
_, err = src.Read(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
n++
|
|
num |= uint64(p[0]) << 56
|
|
return
|
|
}
|
|
|
|
// GET
|
|
|
|
func GetUint16(arr []byte) uint16 {
|
|
return uint16(arr[0]) | (uint16(arr[1]) << 8)
|
|
}
|
|
|
|
func GetUint16AsInt(arr []byte) int {
|
|
return int(arr[0]) | (int(arr[1]) << 8)
|
|
}
|
|
|
|
func GetUint24AsInt(arr []byte) int {
|
|
return int(arr[0]) | (int(arr[1]) << 8) | (int(arr[2]) << 16)
|
|
}
|
|
|
|
func GetUint32(arr []byte) uint32 {
|
|
return uint32(arr[0]) | (uint32(arr[1]) << 8) |
|
|
(uint32(arr[2]) << 16) | (uint32(arr[3]) << 24)
|
|
}
|
|
|
|
func GetUint32AsInt64(arr []byte) int64 {
|
|
u32 := uint32(arr[0]) | (uint32(arr[1]) << 8) |
|
|
(uint32(arr[2]) << 16) | (uint32(arr[3]) << 24)
|
|
return int64(u32)
|
|
}
|
|
|
|
func GetUint40(arr []byte) uint64 {
|
|
return uint64(arr[0]) | (uint64(arr[1]) << 8) |
|
|
(uint64(arr[2]) << 16) | (uint64(arr[3]) << 24) |
|
|
(uint64(arr[4]) << 32)
|
|
}
|
|
|
|
func GetUint48(arr []byte) uint64 {
|
|
return uint64(arr[0]) | (uint64(arr[1]) << 8) |
|
|
(uint64(arr[2]) << 16) | (uint64(arr[3]) << 24) |
|
|
(uint64(arr[4]) << 32) | (uint64(arr[5]) << 40)
|
|
}
|
|
|
|
func GetUint64(arr []byte) uint64 {
|
|
return uint64(arr[0]) | (uint64(arr[1]) << 8) |
|
|
(uint64(arr[2]) << 16) | (uint64(arr[3]) << 24) |
|
|
(uint64(arr[4]) << 32) | (uint64(arr[5]) << 40) |
|
|
(uint64(arr[6]) << 48) | (uint64(arr[7]) << 56)
|
|
}
|
|
|
|
func GetFloat32(arr []byte) float32 {
|
|
return math.Float32frombits(GetUint32(arr))
|
|
}
|
|
|
|
func GetFloat64(arr []byte) float64 {
|
|
return math.Float64frombits(GetUint64(arr))
|
|
}
|
|
|
|
func GetUnixtime(arr []byte) int64 {
|
|
u32 := uint32(arr[0]) | (uint32(arr[1]) << 8) |
|
|
(uint32(arr[2]) << 16) | (uint32(arr[3]) << 24)
|
|
return int64(u32)
|
|
}
|
|
|
|
func GetVarUint64(arr []byte) (num uint64, n int, err error) {
|
|
var b byte
|
|
for i := range 8 {
|
|
if i >= len(arr) {
|
|
return 0, 0, io.EOF
|
|
}
|
|
b = arr[i]
|
|
if b >= 128 {
|
|
num |= uint64(b&127) << uint(i*7)
|
|
return num, i + 1, nil
|
|
}
|
|
num |= uint64(b) << uint(i*7)
|
|
}
|
|
if len(arr) < 9 {
|
|
return 0, 0, io.EOF
|
|
}
|
|
return num | uint64(arr[8])<<56, 9, nil
|
|
}
|
|
|
|
func ReverseGetVarUint64(arr []byte) (num uint64, n int, err error) {
|
|
var (
|
|
b byte
|
|
j = len(arr) - 1
|
|
)
|
|
for i := range 8 {
|
|
if j < 0 {
|
|
return 0, 0, io.EOF
|
|
}
|
|
b = arr[j]
|
|
if b >= 128 {
|
|
num |= uint64(b&127) << uint(i*7)
|
|
return num, i + 1, nil
|
|
}
|
|
num |= uint64(b) << uint(i*7)
|
|
j--
|
|
}
|
|
if j < 0 {
|
|
return 0, 0, io.EOF
|
|
}
|
|
return num | uint64(arr[j])<<56, 9, nil
|
|
}
|
|
|
|
func GetVarInt64(arr []byte) (num int64, n int, err error) {
|
|
u64, n, err := GetVarUint64(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return DecodeZigZag(u64), n, nil
|
|
}
|
|
|
|
func ReverseGetVarInt64(arr []byte) (num int64, n int, err error) {
|
|
u64, n, err := ReverseGetVarUint64(arr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return DecodeZigZag(u64), n, nil
|
|
}
|
|
|
|
// PUT
|
|
|
|
func PutUint16(arr []byte, num uint16) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
}
|
|
|
|
func PutIntAsUint16(arr []byte, num int) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
}
|
|
|
|
func PutIntAsUint24(arr []byte, num int) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
}
|
|
|
|
func PutUint32(arr []byte, num uint32) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
arr[3] = byte(num >> 24)
|
|
}
|
|
|
|
func PutInt64AsUint32(arr []byte, num int64) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
arr[3] = byte(num >> 24)
|
|
}
|
|
|
|
func PutUint40(arr []byte, num uint64) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
arr[3] = byte(num >> 24)
|
|
arr[4] = byte(num >> 32)
|
|
}
|
|
|
|
func PutUint48(arr []byte, num uint64) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
arr[3] = byte(num >> 24)
|
|
arr[4] = byte(num >> 32)
|
|
arr[5] = byte(num >> 40)
|
|
}
|
|
|
|
func PutUint64(arr []byte, num uint64) {
|
|
arr[0] = byte(num)
|
|
arr[1] = byte(num >> 8)
|
|
arr[2] = byte(num >> 16)
|
|
arr[3] = byte(num >> 24)
|
|
arr[4] = byte(num >> 32)
|
|
arr[5] = byte(num >> 40)
|
|
arr[6] = byte(num >> 48)
|
|
arr[7] = byte(num >> 56)
|
|
}
|
|
|
|
func PutFloat32(arr []byte, num float32) {
|
|
PutUint32(arr, math.Float32bits(num))
|
|
}
|
|
|
|
func PutFloat64(arr []byte, num float64) {
|
|
PutUint64(arr, math.Float64bits(num))
|
|
}
|
|
|
|
// WRITE
|
|
|
|
func WriteUint16(dst io.Writer, num uint16) error {
|
|
arr := []byte{
|
|
byte(num),
|
|
byte(num >> 8),
|
|
}
|
|
n, err := dst.Write(arr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n != 2 {
|
|
return ErrIncompleteWrite
|
|
}
|
|
return err
|
|
}
|
|
|
|
func WriteUint32(dst io.Writer, num uint32) error {
|
|
arr := []byte{
|
|
byte(num),
|
|
byte(num >> 8),
|
|
byte(num >> 16),
|
|
byte(num >> 24),
|
|
}
|
|
n, err := dst.Write(arr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n != 4 {
|
|
return ErrIncompleteWrite
|
|
}
|
|
return err
|
|
}
|
|
|
|
func WriteFloat64(dst io.Writer, num float64) error {
|
|
arr := make([]byte, 8)
|
|
PutUint64(arr, math.Float64bits(num))
|
|
n, err := dst.Write(arr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n != 2 {
|
|
return ErrIncompleteWrite
|
|
}
|
|
return err
|
|
}
|
|
|
|
// WRITE VAR
|
|
|
|
func WriteVarUint64(dst io.Writer, num uint64) (int, error) {
|
|
arr := make([]byte, 9)
|
|
for i := range 8 {
|
|
arr[i] = byte(num & 127)
|
|
num >>= 7
|
|
if num == 0 {
|
|
arr[i] |= 128
|
|
size := i + 1
|
|
n, err := dst.Write(arr[:size])
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
if n != size {
|
|
return n, ErrIncompleteWrite
|
|
}
|
|
return size, nil
|
|
}
|
|
}
|
|
arr[8] = byte(num)
|
|
n, err := dst.Write(arr)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
if n != 9 {
|
|
return n, ErrIncompleteWrite
|
|
}
|
|
return 9, nil
|
|
}
|
|
|
|
func PutVarUint64(arr []byte, num uint64) (int, error) {
|
|
for i := range 8 {
|
|
if i >= len(arr) {
|
|
return 0, ErrNoSpace
|
|
}
|
|
arr[i] = byte(num & 127)
|
|
num >>= 7
|
|
if num == 0 {
|
|
arr[i] |= 128
|
|
return i + 1, nil
|
|
}
|
|
}
|
|
if len(arr) < 9 {
|
|
return 0, ErrNoSpace
|
|
}
|
|
arr[8] = byte(num)
|
|
return 9, nil
|
|
}
|
|
|
|
func ReversePutVarUint64(arr []byte, num uint64) (int, error) {
|
|
var tmp [9]byte
|
|
for i := range 8 {
|
|
tmp[i] = byte(num & 127)
|
|
num >>= 7
|
|
if num == 0 {
|
|
tmp[i] |= 128
|
|
n := i + 1
|
|
if len(arr) < n {
|
|
return 0, ErrNoSpace
|
|
}
|
|
for j := i; j >= 0; j-- {
|
|
arr[i-j] = tmp[j]
|
|
}
|
|
return n, nil
|
|
}
|
|
}
|
|
tmp[8] = byte(num)
|
|
n := 9
|
|
if len(arr) < n {
|
|
return 0, ErrNoSpace
|
|
}
|
|
for j := 8; j >= 0; j-- {
|
|
arr[8-j] = tmp[j]
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func PutVarUint64AtEnd(arr []byte, num uint64) (int, error) {
|
|
var (
|
|
tmp [9]byte
|
|
n int
|
|
)
|
|
for i := range 8 {
|
|
tmp[i] = byte(num & 127)
|
|
num >>= 7
|
|
if num == 0 {
|
|
tmp[i] |= 128
|
|
n = i + 1
|
|
break
|
|
}
|
|
}
|
|
if n == 0 {
|
|
tmp[8] = byte(num)
|
|
n = 9
|
|
}
|
|
if len(arr) < n {
|
|
return 0, ErrNoSpace
|
|
}
|
|
j := len(arr) - n
|
|
for i := range n {
|
|
arr[j] = tmp[i]
|
|
j++
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func PutVarInt64(arr []byte, x int64) (int, error) {
|
|
return PutVarUint64(arr, EncodeZigZag(x))
|
|
}
|
|
|
|
func PutVarInt64AtEnd(arr []byte, x int64) (int, error) {
|
|
return PutVarUint64AtEnd(arr, EncodeZigZag(x))
|
|
}
|
|
|
|
func ReversePutVarInt64(arr []byte, x int64) (int, error) {
|
|
return ReversePutVarUint64(arr, EncodeZigZag(x))
|
|
}
|
|
|
|
type KeyComparator interface {
|
|
CompareTo(int) int
|
|
}
|
|
|
|
func BinarySearch(qty int, keyComparator KeyComparator) (elemIdx int, isFound bool) {
|
|
if qty == 0 {
|
|
return
|
|
}
|
|
a := 0
|
|
b := qty - 1
|
|
for {
|
|
var (
|
|
elemIdx = (b-a)/2 + a
|
|
code = keyComparator.CompareTo(elemIdx)
|
|
)
|
|
|
|
if code == 1 {
|
|
a = elemIdx + 1
|
|
if a > b {
|
|
return elemIdx + 1, false
|
|
}
|
|
} else if code == -1 {
|
|
b = elemIdx - 1
|
|
if b < a {
|
|
return elemIdx, false
|
|
}
|
|
} else {
|
|
return elemIdx, true
|
|
}
|
|
}
|
|
}
|
|
|
|
func DeleteReverseArrElem(arr []byte, qty int, elemSize int, idx int) {
|
|
dstIdx := len(arr) - idx*elemSize - 1
|
|
srcIdx := dstIdx - elemSize
|
|
|
|
end := len(arr) - qty*elemSize
|
|
|
|
for ; srcIdx >= end; srcIdx-- {
|
|
arr[dstIdx] = arr[srcIdx]
|
|
dstIdx--
|
|
}
|
|
|
|
for i := end; i < end+elemSize; i++ {
|
|
arr[i] = 0
|
|
}
|
|
}
|
|
|
|
// ZigZag
|
|
|
|
// ZigZag encoding: int64 -> uint64
|
|
func EncodeZigZag(x int64) uint64 {
|
|
return uint64(x<<1) ^ uint64(x>>63)
|
|
}
|
|
|
|
// ZigZag decoding: uint64 -> int64
|
|
func DecodeZigZag(u uint64) int64 {
|
|
return int64(u>>1) ^ -(int64(u & 1))
|
|
}
|
|
|
|
func ReadN(r io.Reader, n int) (_ []byte, err error) {
|
|
if n < 0 {
|
|
err = fmt.Errorf("wrong n=%d", n)
|
|
return
|
|
}
|
|
buf := make([]byte, n)
|
|
err = ReadNInto(r, buf)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func ReadNInto(r io.Reader, buf []byte) (err error) {
|
|
if len(buf) == 0 {
|
|
return
|
|
}
|
|
|
|
var q, total, readAttempts int
|
|
|
|
for readAttempts < maxReadAttempts {
|
|
bufsize := len(buf) - total
|
|
q, err = r.Read(buf[total:])
|
|
if q == bufsize {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
if q > bufsize {
|
|
err = ErrReadOverflow
|
|
return
|
|
}
|
|
if q < 0 {
|
|
err = ErrNegativeReadCount
|
|
return
|
|
}
|
|
if q == 0 {
|
|
readAttempts++
|
|
} else {
|
|
total += q
|
|
}
|
|
}
|
|
err = io.ErrNoProgress
|
|
return
|
|
}
|
|
|
|
func CalcVarUint64Length(num uint64) int {
|
|
for i := range 8 {
|
|
num >>= 7
|
|
if num == 0 {
|
|
return i + 1
|
|
}
|
|
}
|
|
return 9
|
|
}
|
|
|
|
func CalcVarInt64Length(num int64) int {
|
|
u64 := EncodeZigZag(num)
|
|
for i := range 8 {
|
|
u64 >>= 7
|
|
if u64 == 0 {
|
|
return i + 1
|
|
}
|
|
}
|
|
return 9
|
|
}
|
|
|