first commit
This commit is contained in:
198
arr.go
Normal file
198
arr.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package bin
|
||||||
|
|
||||||
|
func DeleteArrElem(arr []byte, qty int, elemSize int, idx int) {
|
||||||
|
dstIdx := elemSize * idx
|
||||||
|
srcIdx := dstIdx + elemSize
|
||||||
|
|
||||||
|
end := qty * elemSize
|
||||||
|
|
||||||
|
for ; srcIdx < end; srcIdx++ {
|
||||||
|
arr[dstIdx] = arr[srcIdx]
|
||||||
|
dstIdx++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := elemSize * (qty - 1); i < end; i++ {
|
||||||
|
arr[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertArrElem(arr []byte, qty int, elem []byte, idx int) {
|
||||||
|
elemSize := len(elem)
|
||||||
|
|
||||||
|
srcIdx := qty*elemSize - 1 // last byte
|
||||||
|
dstIdx := srcIdx + elemSize
|
||||||
|
|
||||||
|
end := elemSize * idx
|
||||||
|
|
||||||
|
for ; srcIdx >= end; srcIdx-- {
|
||||||
|
arr[dstIdx] = arr[srcIdx]
|
||||||
|
dstIdx--
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вставляем элемент
|
||||||
|
for _, b := range elem {
|
||||||
|
arr[end] = b
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для массивов, которые начинаются с конца arr и движутся к началу
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// qty = 2
|
||||||
|
// 0 0 3 3 1 1
|
||||||
|
// 3 3 3 3 1 1
|
||||||
|
func InsertReverseArrElem(arr []byte, qty int, elem []byte, idx int) {
|
||||||
|
elemSize := len(elem)
|
||||||
|
|
||||||
|
srcIdx := len(arr) - qty*elemSize
|
||||||
|
dstIdx := srcIdx - elemSize
|
||||||
|
|
||||||
|
end := len(arr) - elemSize*idx
|
||||||
|
|
||||||
|
for ; srcIdx < end; srcIdx++ {
|
||||||
|
arr[dstIdx] = arr[srcIdx]
|
||||||
|
dstIdx++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вставляем элемент
|
||||||
|
i := end - elemSize
|
||||||
|
for _, b := range elem {
|
||||||
|
arr[i] = b
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Предполагается что значения отсортированы ASC
|
||||||
|
func FindArrElem(arr []byte, qty int, elem []byte, byteOrder ByteOrder) (elemIdx int, isFound bool) {
|
||||||
|
if qty == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Границы (индексы элементов массива)
|
||||||
|
a := 0
|
||||||
|
b := qty - 1
|
||||||
|
|
||||||
|
for {
|
||||||
|
elemIdx = (b-a)/2 + a
|
||||||
|
|
||||||
|
code := compareToArrElem(arr, elem, elemIdx, byteOrder)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -1, меньше
|
||||||
|
// 1, больше
|
||||||
|
// 0, равны
|
||||||
|
func compareToArrElem(arr []byte, elem []byte, elemIdx int, byteOrder ByteOrder) int {
|
||||||
|
if byteOrder == HL {
|
||||||
|
// индекс первого байта
|
||||||
|
idx := elemIdx * len(elem)
|
||||||
|
|
||||||
|
for _, b := range elem {
|
||||||
|
if b > arr[idx] {
|
||||||
|
return 1
|
||||||
|
} else if b < arr[idx] {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// индекс последнего байта
|
||||||
|
idx := (elemIdx+1)*len(elem) - 1
|
||||||
|
|
||||||
|
for bIdx := len(elem) - 1; bIdx >= 0; bIdx-- {
|
||||||
|
b := elem[bIdx]
|
||||||
|
if b > arr[idx] {
|
||||||
|
return 1
|
||||||
|
} else if b < arr[idx] {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
idx--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// func find(arr []int, num int) (int, bool) {
|
||||||
|
// var a, b, i int
|
||||||
|
// b = len(arr) - 1
|
||||||
|
// for {
|
||||||
|
// i = (b-a)/2 + a
|
||||||
|
// if num > arr[i] {
|
||||||
|
// a = i + 1
|
||||||
|
// if a > b {
|
||||||
|
// return i + 1, false
|
||||||
|
// }
|
||||||
|
// } else if num < arr[i] {
|
||||||
|
// b = i - 1
|
||||||
|
// if b < a {
|
||||||
|
// return i, false
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return i, true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
type KeyComparator interface {
|
||||||
|
CompareTo(int) int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Предполагается что значения отсортированы ASC
|
||||||
|
func BinarySearch(qty int, keyComparator KeyComparator) (elemIdx int, isFound bool) {
|
||||||
|
if qty == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Границы (индексы элементов массива)
|
||||||
|
a := 0
|
||||||
|
b := qty - 1
|
||||||
|
|
||||||
|
for {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
bin.sgo
Executable file
108
bin.sgo
Executable file
@@ -0,0 +1,108 @@
|
|||||||
|
package bin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PutVarInt32(w io.Writer, num int) (int, error) {
|
||||||
|
if num > 2147483647 {
|
||||||
|
return 0, fmt.Errorf("num %d overflows int32", num)
|
||||||
|
}
|
||||||
|
arr := make([]byte, 5)
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
arr[i] = byte(num & 127)
|
||||||
|
num >>= 7
|
||||||
|
if num == 0 {
|
||||||
|
arr[i] |= 128
|
||||||
|
return w.Write(arr[:i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// в последнем 9м байте все биты значащие
|
||||||
|
arr[5] = byte(num)
|
||||||
|
return w.Write(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VarInt32(src io.ByteReader) (num int, err error) {
|
||||||
|
var (
|
||||||
|
b byte
|
||||||
|
off uint
|
||||||
|
)
|
||||||
|
for ; off < 28; off += 7 {
|
||||||
|
b, err = src.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b < 128 {
|
||||||
|
num |= int(b) << off
|
||||||
|
} else {
|
||||||
|
num |= int(b&127) << off
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = src.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// в последнем 9м байте все биты значащие
|
||||||
|
num |= int(b&7) << 28
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutVarUint(arr []byte, num uint64) int {
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
arr[i] = byte(num & 127)
|
||||||
|
num >>= 7
|
||||||
|
if num == 0 {
|
||||||
|
arr[i] |= 128
|
||||||
|
return i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// в последнем 9м байте все биты значащие
|
||||||
|
arr[8] = byte(num)
|
||||||
|
return 9
|
||||||
|
}
|
||||||
|
|
||||||
|
func VarUint(src io.ByteReader) (num uint64, err error) {
|
||||||
|
var (
|
||||||
|
b byte
|
||||||
|
off uint
|
||||||
|
)
|
||||||
|
for ; off < 56; off += 7 {
|
||||||
|
b, err = src.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b < 128 {
|
||||||
|
num |= uint64(b) << off
|
||||||
|
} else {
|
||||||
|
num |= uint64(b&127) << off
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = src.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// в последнем 9м байте все биты значащие
|
||||||
|
num |= uint64(b) << 56
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func PackVarUint32(num int) (err error) {
|
||||||
|
idx := 0
|
||||||
|
for num > 127 {
|
||||||
|
s.vint[idx] = byte(num & 127)
|
||||||
|
num >>= 7
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
// Даже в последнем байте отсекаем старший бит (знак)
|
||||||
|
s.vint[idx] = byte(num&127) | 128
|
||||||
|
|
||||||
|
_, err = s.dst.Write(s.vint[:idx+1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
663
bin_test.go
Executable file
663
bin_test.go
Executable file
@@ -0,0 +1,663 @@
|
|||||||
|
package bin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
max7b uint64 = 127
|
||||||
|
max14b uint64 = 16383
|
||||||
|
max21b uint64 = 2097151
|
||||||
|
max28b uint64 = 268435455
|
||||||
|
max35b uint64 = 34359738367
|
||||||
|
max42b uint64 = 4398046511103
|
||||||
|
max49b uint64 = 562949953421311
|
||||||
|
max56b uint64 = 72057594037927935
|
||||||
|
|
||||||
|
max24b uint64 = 16777215
|
||||||
|
max40b uint64 = 1099511627775
|
||||||
|
max48b uint64 = 281474976710655
|
||||||
|
)
|
||||||
|
|
||||||
|
type UintAndSize struct {
|
||||||
|
Value uint64
|
||||||
|
Size int
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func TestVarUint64(t *testing.T) {
|
||||||
|
// числа между 0, 1 и MaxUint64 - это 2 в степени кратной семи
|
||||||
|
// плюс предыдущее число. Например: 2**7-1, 2**7
|
||||||
|
var nums = []UintAndSize{
|
||||||
|
{0, 1},
|
||||||
|
{1, 1},
|
||||||
|
{max7b, 1},
|
||||||
|
{max7b + 1, 2},
|
||||||
|
{max14b, 2},
|
||||||
|
{max14b + 1, 3},
|
||||||
|
{max21b, 3},
|
||||||
|
{max21b + 1, 4},
|
||||||
|
{max28b, 4},
|
||||||
|
{max28b + 1, 5},
|
||||||
|
{max35b, 5},
|
||||||
|
{max35b + 1, 6},
|
||||||
|
{max42b, 6},
|
||||||
|
{max42b + 1, 7},
|
||||||
|
{max49b, 7},
|
||||||
|
{max49b + 1, 8},
|
||||||
|
{max56b, 8},
|
||||||
|
{max56b + 1, 9},
|
||||||
|
{math.MaxUint64, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
buf.Reset()
|
||||||
|
n := PutVarUint64(buf, num.Value)
|
||||||
|
if n != num.Size {
|
||||||
|
t.Fatalf("Encoded size %d != estimated size %d for num %d\n", n, num.Size, num.Value)
|
||||||
|
}
|
||||||
|
encoded := buf.Bytes()
|
||||||
|
x, err := GetVarUint64(bytes.NewBuffer(encoded))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetVarUint64 error: %s\n", err)
|
||||||
|
}
|
||||||
|
if x != num.Value {
|
||||||
|
t.Fatalf("Origin num %d != decoded num %d. Buffer: %v\n", num.Value, x, encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVarUint32(t *testing.T) {
|
||||||
|
// числа между 0, 1 и MaxUint64 - это 2 в степени кратной семи
|
||||||
|
// плюс предыдущее число. Например: 2**7-1, 2**7
|
||||||
|
var nums = []UintAndSize{
|
||||||
|
{0, 1},
|
||||||
|
{1, 1},
|
||||||
|
{max7b, 1},
|
||||||
|
{max7b + 1, 2},
|
||||||
|
{max14b, 2},
|
||||||
|
{max14b + 1, 3},
|
||||||
|
{max21b, 3},
|
||||||
|
{max21b + 1, 4},
|
||||||
|
{max28b, 4},
|
||||||
|
{max28b + 1, 5},
|
||||||
|
{math.MaxUint32, 5},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
buf.Reset()
|
||||||
|
origin := uint32(num.Value)
|
||||||
|
n := PutVarUint32(buf, origin)
|
||||||
|
if n != num.Size {
|
||||||
|
t.Fatalf("Encoded size %d != estimated size %d for num %d\n", n, num.Size, origin)
|
||||||
|
}
|
||||||
|
encoded := buf.Bytes()
|
||||||
|
x, err := GetVarUint32(bytes.NewBuffer(encoded))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetVarUint32 error: %s\n", err)
|
||||||
|
}
|
||||||
|
if x != origin {
|
||||||
|
t.Fatalf("Origin num %d != decoded num %d. Buffer: %v\n", origin, x, encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
func TestMaxUint64(t *testing.T) {
|
||||||
|
// числа между 0, 1 и MaxUint64 - это 2 в степени кратной семи
|
||||||
|
// плюс предыдущее число. Например: 2**7-1, 2**7
|
||||||
|
var nums = []UintAndSize{
|
||||||
|
{0, 1},
|
||||||
|
{1, 1},
|
||||||
|
{math.MaxUint8, 1},
|
||||||
|
{math.MaxUint8 + 1, 2},
|
||||||
|
{math.MaxUint16, 2},
|
||||||
|
{math.MaxUint16 + 1, 3},
|
||||||
|
{max24b, 3},
|
||||||
|
{max24b + 1, 4},
|
||||||
|
{math.MaxUint32, 4},
|
||||||
|
{math.MaxUint32 + 1, 5},
|
||||||
|
{max40b, 5},
|
||||||
|
{max40b + 1, 6},
|
||||||
|
{max48b, 6},
|
||||||
|
{max48b + 1, 7},
|
||||||
|
{max56b, 7},
|
||||||
|
{max56b + 1, 8},
|
||||||
|
{math.MaxUint64, 8},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
buf.Reset()
|
||||||
|
n := PutMaxUint64(buf, num.Value)
|
||||||
|
if n != num.Size {
|
||||||
|
t.Fatalf("Encoded size %d != estimated size %d for num %d\n", n, num.Size, num.Value)
|
||||||
|
}
|
||||||
|
encoded := buf.Bytes()
|
||||||
|
x, err := GetMaxUint64(bytes.NewBuffer(encoded), n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetMaxUint64 error: %s\n", err)
|
||||||
|
}
|
||||||
|
if x != num.Value {
|
||||||
|
t.Fatalf("Origin num %d != decoded num %d. Buffer: %v\n", num.Value, x, encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func TestFloat32(t *testing.T) {
|
||||||
|
buf := []byte{234, 171, 234, 171, 234, 171, 234, 171, 234, 171}
|
||||||
|
|
||||||
|
r := bytes.NewBuffer(buf)
|
||||||
|
|
||||||
|
num, err := ReadFloat32(r, HL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("float32: %f\n", num)
|
||||||
|
|
||||||
|
x := float64(num)
|
||||||
|
|
||||||
|
fmt.Printf("float64: %f\n", x*4)
|
||||||
|
fmt.Printf("int64: %d\n", int64(x)+10)
|
||||||
|
|
||||||
|
mid := make([]byte, 4)
|
||||||
|
|
||||||
|
err = PutFloat32(mid, num, HL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%d\n", mid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test6bDateTime(t *testing.T) {
|
||||||
|
//
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
now = now.In(time.UTC)
|
||||||
|
|
||||||
|
w := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
Write6bDateTime(w, now)
|
||||||
|
|
||||||
|
arr := w.Bytes()
|
||||||
|
|
||||||
|
fmt.Printf("%s: %v, %d\n", now, arr, now.Unix())
|
||||||
|
|
||||||
|
r := bytes.NewBuffer(arr)
|
||||||
|
|
||||||
|
tm, _ := Read6bDateTime(r)
|
||||||
|
|
||||||
|
fmt.Printf("%s: %d\n", tm, tm.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitFloat(t *testing.T) {
|
||||||
|
f := 650179.6985999999 // округляет вниз .6985
|
||||||
|
total := 8.2291999999 // округляет вверх 8.2292
|
||||||
|
|
||||||
|
n := SplitFloat(f, 4)
|
||||||
|
x := SplitFloat(total, 4)
|
||||||
|
|
||||||
|
fmt.Printf("int: %d, frac: %d\n", n.Int, n.Frac)
|
||||||
|
fmt.Printf("total int: %d, frac: %d\n", x.Int, x.Frac)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitFloat2(t *testing.T) {
|
||||||
|
//prev := 65032252.8724999875 // округляет вниз .6985
|
||||||
|
//total := 9.2449999973 // округляет вверх 8.2292
|
||||||
|
|
||||||
|
fracDigits := 4
|
||||||
|
|
||||||
|
floatPrev := 65000005.499980002
|
||||||
|
|
||||||
|
floatTotal := 3.5000800019
|
||||||
|
|
||||||
|
prev := SplitFloat(floatPrev, fracDigits)
|
||||||
|
total := SplitFloat(floatTotal, fracDigits)
|
||||||
|
|
||||||
|
fmt.Printf("prev: i=%d, f=%d\n", prev.Int, prev.Frac)
|
||||||
|
fmt.Printf("total i=%d, f=%d\n", total.Int, total.Frac)
|
||||||
|
|
||||||
|
value := SplitFloat(floatPrev+floatTotal, fracDigits)
|
||||||
|
|
||||||
|
fmt.Printf("real i=%d, f=%d\n", value.Int, value.Frac)
|
||||||
|
|
||||||
|
calcInt := prev.Int + total.Int
|
||||||
|
calcFrac := prev.Frac + total.Frac
|
||||||
|
|
||||||
|
if calcFrac >= 10000 {
|
||||||
|
calcFrac -= 10000
|
||||||
|
calcInt += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("calc i=%d, f=%d\n", calcInt, calcFrac)
|
||||||
|
|
||||||
|
fmt.Printf("\n%.9f\n", 10000000.999999999)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBitOps(t *testing.T) {
|
||||||
|
var b byte = 255
|
||||||
|
|
||||||
|
var bitNo byte = 7
|
||||||
|
|
||||||
|
fmt.Printf("%08b\n", UnsetBit(b, bitNo))
|
||||||
|
fmt.Printf("%08b\n", SetBit(UnsetBit(b, bitNo), bitNo))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeFloat(t *testing.T) {
|
||||||
|
var buf = []byte{0xCE, 0x6E, 0x6B, 0x28}
|
||||||
|
|
||||||
|
f1, err := GetFloat32(buf, LH)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f2, err := GetFloat32(buf, HL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("LH: %v\nHL: %v\nBIN: %08b\n\n", f1, f2, buf)
|
||||||
|
|
||||||
|
n, err := strconv.ParseFloat("-1e9", 32)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := float32(n)
|
||||||
|
|
||||||
|
var arr = []byte{0, 0, 0, 0}
|
||||||
|
|
||||||
|
PutFloat32(arr, f, HL)
|
||||||
|
|
||||||
|
fmt.Printf("%v\nBIN: %08b\n", f, arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тесты массивов (для написания СУБД). Когда в байтовом виде записан массив из N элементов,
|
||||||
|
// фиксированного размера (например 4-байтовый uint32 или 2-байтовый uint16). Из массива
|
||||||
|
// нужно удалять элементы по индексу, либо в массив вставлять по индексу (чтобы другие
|
||||||
|
// элементы "подвинулись").
|
||||||
|
|
||||||
|
type _DeleteArrElemTestCase struct {
|
||||||
|
Arr []byte
|
||||||
|
Qty int
|
||||||
|
ElemSize int
|
||||||
|
Idx int
|
||||||
|
Result []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type _InsertArrElemTestCase struct {
|
||||||
|
Arr []byte
|
||||||
|
Qty int
|
||||||
|
Elem []byte
|
||||||
|
Idx int
|
||||||
|
Result []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteArrElem(t *testing.T) {
|
||||||
|
originArr := []byte{1, 1, 2, 2, 3, 3, 255, 0, 0, 0}
|
||||||
|
|
||||||
|
testCases := []_DeleteArrElemTestCase{
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 0,
|
||||||
|
Result: []byte{2, 2, 3, 3, 0, 0, 255, 0, 0, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 1,
|
||||||
|
Result: []byte{1, 1, 3, 3, 0, 0, 255, 0, 0, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 2,
|
||||||
|
Result: []byte{1, 1, 2, 2, 0, 0, 255, 0, 0, 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
arrcopy := make([]byte, len(testCase.Arr))
|
||||||
|
|
||||||
|
copy(arrcopy, testCase.Arr)
|
||||||
|
|
||||||
|
DeleteArrElem(arrcopy, testCase.Qty, testCase.ElemSize, testCase.Idx)
|
||||||
|
|
||||||
|
if !bytes.Equal(arrcopy, testCase.Result) {
|
||||||
|
t.Fatalf(`
|
||||||
|
Source: %v
|
||||||
|
Estimate: %v
|
||||||
|
Real: %v`,
|
||||||
|
testCase.Arr, testCase.Result, arrcopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertArrElem(t *testing.T) {
|
||||||
|
originArr := []byte{1, 1, 2, 2, 0, 0, 255, 0}
|
||||||
|
elem := []byte{7, 7}
|
||||||
|
|
||||||
|
testCases := []_InsertArrElemTestCase{
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 0,
|
||||||
|
Result: []byte{7, 7, 1, 1, 2, 2, 255, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 1,
|
||||||
|
Result: []byte{1, 1, 7, 7, 2, 2, 255, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 2,
|
||||||
|
Result: []byte{1, 1, 2, 2, 7, 7, 255, 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
arrcopy := make([]byte, len(testCase.Arr))
|
||||||
|
|
||||||
|
copy(arrcopy, testCase.Arr)
|
||||||
|
|
||||||
|
InsertArrElem(arrcopy, testCase.Qty, testCase.Elem, testCase.Idx)
|
||||||
|
|
||||||
|
if !bytes.Equal(arrcopy, testCase.Result) {
|
||||||
|
t.Fatalf(`
|
||||||
|
Source: %v
|
||||||
|
Estimate: %v
|
||||||
|
Real: %v`,
|
||||||
|
testCase.Arr, testCase.Result, arrcopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteReverseArrElem(t *testing.T) {
|
||||||
|
originArr := []byte{0, 0, 255, 3, 3, 2, 2, 1, 1}
|
||||||
|
|
||||||
|
testCases := []_DeleteArrElemTestCase{
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 0,
|
||||||
|
Result: []byte{0, 0, 255, 0, 0, 3, 3, 2, 2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 1,
|
||||||
|
Result: []byte{0, 0, 255, 0, 0, 3, 3, 1, 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 3,
|
||||||
|
ElemSize: 2,
|
||||||
|
Idx: 2,
|
||||||
|
Result: []byte{0, 0, 255, 0, 0, 2, 2, 1, 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
arrcopy := make([]byte, len(testCase.Arr))
|
||||||
|
|
||||||
|
copy(arrcopy, testCase.Arr)
|
||||||
|
|
||||||
|
DeleteReverseArrElem(arrcopy, testCase.Qty, testCase.ElemSize, testCase.Idx)
|
||||||
|
|
||||||
|
if !bytes.Equal(arrcopy, testCase.Result) {
|
||||||
|
t.Fatalf(`
|
||||||
|
Source: %v
|
||||||
|
Estimate: %v
|
||||||
|
Real: %v`,
|
||||||
|
testCase.Arr, testCase.Result, arrcopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertReverseArrElem(t *testing.T) {
|
||||||
|
originArr := []byte{0, 255, 0, 0, 2, 2, 1, 1}
|
||||||
|
elem := []byte{7, 7}
|
||||||
|
|
||||||
|
testCases := []_InsertArrElemTestCase{
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 0,
|
||||||
|
Result: []byte{0, 255, 2, 2, 1, 1, 7, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 1,
|
||||||
|
Result: []byte{0, 255, 2, 2, 7, 7, 1, 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Arr: originArr,
|
||||||
|
Qty: 2,
|
||||||
|
Elem: elem,
|
||||||
|
Idx: 2,
|
||||||
|
Result: []byte{0, 255, 7, 7, 2, 2, 1, 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
arrcopy := make([]byte, len(testCase.Arr))
|
||||||
|
|
||||||
|
copy(arrcopy, testCase.Arr)
|
||||||
|
|
||||||
|
InsertReverseArrElem(arrcopy, testCase.Qty, testCase.Elem, testCase.Idx)
|
||||||
|
|
||||||
|
if !bytes.Equal(arrcopy, testCase.Result) {
|
||||||
|
t.Fatalf(`
|
||||||
|
Source: %v
|
||||||
|
Estimate: %v
|
||||||
|
Real: %v`,
|
||||||
|
testCase.Arr, testCase.Result, arrcopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareToArrElem(t *testing.T) {
|
||||||
|
arr := []byte{1, 2, 3, 4}
|
||||||
|
elem := []byte{5, 2}
|
||||||
|
|
||||||
|
code := compareToArrElem(arr, elem, 1, HL)
|
||||||
|
|
||||||
|
fmt.Printf("code: %d\n", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
type _FindArrElemTestCase struct {
|
||||||
|
Elem []byte // элемент, который будем искать в массиве
|
||||||
|
// Результат поиска - индекс и флаг
|
||||||
|
Idx int
|
||||||
|
Found bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindArrElem(t *testing.T) {
|
||||||
|
arr := []byte{2, 2, 5, 5, 7, 7, 0, 0}
|
||||||
|
|
||||||
|
testCases := []_FindArrElemTestCase{
|
||||||
|
{
|
||||||
|
Elem: []byte{1, 1},
|
||||||
|
Idx: 0,
|
||||||
|
Found: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{2, 2},
|
||||||
|
Idx: 0,
|
||||||
|
Found: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{3, 3},
|
||||||
|
Idx: 1,
|
||||||
|
Found: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{5, 5},
|
||||||
|
Idx: 1,
|
||||||
|
Found: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{6, 6},
|
||||||
|
Idx: 2,
|
||||||
|
Found: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{7, 7},
|
||||||
|
Idx: 2,
|
||||||
|
Found: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Elem: []byte{8, 8},
|
||||||
|
Idx: 3,
|
||||||
|
Found: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
errorPattern := `Case:
|
||||||
|
byteOrder: %s
|
||||||
|
elem: %v
|
||||||
|
idx: %d
|
||||||
|
found: %t
|
||||||
|
|
||||||
|
Result:
|
||||||
|
idx: %d
|
||||||
|
found: %t
|
||||||
|
`
|
||||||
|
|
||||||
|
var (
|
||||||
|
idx int
|
||||||
|
found bool
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
idx, found = FindArrElem(arr, 3, testCase.Elem, LH)
|
||||||
|
if idx != testCase.Idx || found != testCase.Found {
|
||||||
|
t.Fatalf(errorPattern,
|
||||||
|
LH, testCase.Elem, testCase.Idx, testCase.Found, idx, found)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тоже самое, но с другим порядком байт
|
||||||
|
idx, found = FindArrElem(arr, 3, testCase.Elem, HL)
|
||||||
|
if idx != testCase.Idx || found != testCase.Found {
|
||||||
|
t.Fatalf(errorPattern,
|
||||||
|
HL, testCase.Elem, testCase.Idx, testCase.Found, idx, found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("idx: %d, found: %t\n", idx, found)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloatToUint(t *testing.T) {
|
||||||
|
//f =
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntToUint(t *testing.T) {
|
||||||
|
var i int64 = 20 //-math.MaxInt64 - 1
|
||||||
|
|
||||||
|
u := Int64AsUint64(i)
|
||||||
|
|
||||||
|
fmt.Printf("%v\n", u)
|
||||||
|
|
||||||
|
x := Uint64AsInt64(u)
|
||||||
|
|
||||||
|
fmt.Printf("%v\n", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytesOrders = []ByteOrder{LH, HL}
|
||||||
|
|
||||||
|
func TestInt24(t *testing.T) {
|
||||||
|
var nums = []int32{-1, 0, 1, -4915195, 4915195}
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
for _, byteOrder := range bytesOrders {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
err := WriteInt24(buf, num, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s; num=%d; byteOrder=%s\n", err, num, byteOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
unpacked, err := ReadInt24(buf, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if unpacked != num {
|
||||||
|
t.Fatalf("num %d != unpacked %d (byteOrder=%s)\n", num, unpacked, byteOrder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInt48(t *testing.T) {
|
||||||
|
var nums = []int64{-1, 0, 1, -4915195, 4915195}
|
||||||
|
|
||||||
|
for _, num := range nums {
|
||||||
|
for _, byteOrder := range bytesOrders {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
err := WriteInt48(buf, num, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s; num=%d; byteOrder=%s\n", err, num, byteOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
unpacked, err := ReadInt48(buf, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if unpacked != num {
|
||||||
|
t.Fatalf("num %d != unpacked %d (byteOrder=%s)\n", num, unpacked, byteOrder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInt32(t *testing.T) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
byteOrder := HL
|
||||||
|
|
||||||
|
err := WriteInt32(buf, ^math.MaxInt32, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%08b\n", buf.Bytes())
|
||||||
|
|
||||||
|
num, err := ReadInt32(buf, byteOrder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(num)
|
||||||
|
}
|
||||||
47
buffer.go
Normal file
47
buffer.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package bin
|
||||||
|
|
||||||
|
type Buffer struct {
|
||||||
|
arr []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBuffer(arr []byte) *Buffer {
|
||||||
|
s := new(Buffer)
|
||||||
|
s.arr = arr
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) WriteByte(b byte) (err error) {
|
||||||
|
s.arr = append(s.arr, b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) Write(data []byte) (int, error) {
|
||||||
|
s.arr = append(s.arr, data...)
|
||||||
|
return len(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) ByteAt(idx int) byte {
|
||||||
|
return s.arr[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) WriteByteAt(b byte, idx int) {
|
||||||
|
s.arr[idx] = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) Len() int {
|
||||||
|
return len(s.arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) Bytes() []byte {
|
||||||
|
return s.arr[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) CopyBytes() []byte {
|
||||||
|
dst := make([]byte, len(s.arr))
|
||||||
|
copy(dst, s.arr)
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Buffer) Reset() {
|
||||||
|
s.arr = s.arr[:0]
|
||||||
|
}
|
||||||
27
buffer_test.go
Normal file
27
buffer_test.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package bin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuffer(t *testing.T) {
|
||||||
|
arr := make([]byte, 0)
|
||||||
|
|
||||||
|
buf := NewBuffer(arr)
|
||||||
|
buf.WriteByte(100)
|
||||||
|
|
||||||
|
fmt.Println(buf.ByteAt(0))
|
||||||
|
|
||||||
|
buf.Write([]byte{1, 2, 3})
|
||||||
|
buf.WriteByteAt(200, 0)
|
||||||
|
|
||||||
|
fmt.Println(buf.ByteAt(0))
|
||||||
|
|
||||||
|
fmt.Println(buf.Bytes())
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
|
||||||
|
fmt.Println(buf.Bytes())
|
||||||
|
fmt.Println(buf.Len())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user