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 }