diff --git a/little/little.go b/little/little.go index f68c9e2..7266796 100644 --- a/little/little.go +++ b/little/little.go @@ -29,9 +29,10 @@ var ( // ErrNegativeReadCount shows 100% bug in the source reader ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'") - ErrNoSpace = errors.New("bin: no space") - ErrTooLong = errors.New("bin: too long") // слишком длинная строка или массив байт - ErrRange = errors.New("bin: out of range") + ErrNoSpace = errors.New("bin: no space") + ErrTooLong = errors.New("bin: too long") // слишком длинная строка или массив байт + ErrRange = errors.New("bin: out of range") + ErrNegativeSize = errors.New("bin: negative size") ) func ReadByteAsInt(r io.Reader) (i int, err error) { @@ -1013,10 +1014,16 @@ func ReadBool(src io.Reader) (bool, error) { return b == 1, nil } -// uint64 +// READ/WRITE VAR SIZE + func WriteVarSize(w io.Writer, n int) (int, error) { - num := uint64(n) - a := make([]byte, 9) + if n < 0 { + return 0, ErrNegativeSize + } + var ( + num = uint64(n) + a = make([]byte, 9) + ) for i := 0; i < 8; i++ { a[i] = byte(num & 127) num >>= 7 @@ -1100,3 +1107,55 @@ func CountVarSize(n int) int { } return 9 } + +// PUT/GET VAR SIZE + +func PutVarSize(a []byte, n int) (int, error) { + if n < 0 { + return 0, ErrNegativeSize + } + var ( + num = uint64(n) + tmp = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0} + ) + for i := 0; i < 8; i++ { + if i < len(a) { + if num < 128 { + tmp[i] = byte(num) | 128 + q := i + 1 + copy(a, tmp[:q]) + return q, nil + } + tmp[i] = byte(num & 127) + num >>= 7 + } else { + return 0, ErrNoSpace + } + } + if len(a) < 9 { + return 0, ErrNoSpace + } + tmp[8] = byte(num) + copy(a, tmp) + return 9, nil +} + +func GetVarSize(a []byte) (int, error) { + var num uint64 + for i := 0; i < 8; i++ { + if i < len(a) { + b := a[i] + num |= uint64(b&127) << uint(i*7) + if b >= 128 { + return int(num), nil + } + } else { + return 0, ErrNoSpace + } + } + if len(a) < 9 { + return 0, ErrNoSpace + } + num |= uint64(a[8]) << 56 + return int(num), nil +} diff --git a/little/little_test.go b/little/little_test.go index c087270..c092359 100644 --- a/little/little_test.go +++ b/little/little_test.go @@ -361,7 +361,7 @@ func TestWriteReadInt16(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteInt16(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadInt16(w) if err != nil { @@ -383,7 +383,7 @@ func TestWriteReadInt24(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteInt24(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadInt24(w) if err != nil { @@ -405,7 +405,7 @@ func TestWriteReadInt32(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteInt32(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadInt32(w) if err != nil { @@ -427,7 +427,7 @@ func TestWriteReadInt48(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteInt48(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadInt48(w) if err != nil { @@ -449,7 +449,7 @@ func TestWriteReadInt64(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteInt64(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadInt64(w) if err != nil { @@ -471,7 +471,7 @@ func TestWriteReadUint16(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteUint16(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadUint16(w) if err != nil { @@ -492,7 +492,7 @@ func TestWriteReadUint24(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteUint24(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadUint24(w) if err != nil { @@ -513,7 +513,7 @@ func TestWriteReadUint32(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteUint32(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadUint32(w) if err != nil { @@ -534,7 +534,7 @@ func TestWriteReadUint48(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteUint48(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadUint48(w) if err != nil { @@ -555,7 +555,7 @@ func TestWriteReadUint64(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteUint64(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadUint64(w) if err != nil { @@ -582,7 +582,7 @@ func TestWriteReadFloat32(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteFloat32(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadFloat32(w) if err != nil { @@ -608,7 +608,7 @@ func TestWriteReadFloat64(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteFloat64(w, num) if err != nil { - return + t.Fatal(err) } decoded, err := ReadFloat64(w) if err != nil { @@ -633,7 +633,7 @@ func TestWriteReadString8(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteString8(w, origin) if err != nil { - return + t.Fatal(err) } decoded, err := ReadString8(w) if err != nil { @@ -662,7 +662,7 @@ func TestWriteReadString16(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteString16(w, origin) if err != nil { - return + t.Fatal(err) } decoded, err := ReadString16(w) if err != nil { @@ -691,7 +691,7 @@ func TestWriteReadBool(t *testing.T) { w := bytes.NewBuffer(nil) err := WriteBool(w, flag) if err != nil { - return + t.Fatal(err) } decoded, err := ReadBool(w) if err != nil { @@ -761,30 +761,31 @@ func TestCountVarUint64(t *testing.T) { } } +var varSizeTestCases = []struct { + Num int + Count int +}{ + {Num: (1 << 7) - 1, Count: 1}, + {Num: (1 << 7), Count: 2}, + {Num: (1 << 14) - 1, Count: 2}, + {Num: (1 << 14), Count: 3}, + {Num: (1 << 21) - 1, Count: 3}, + {Num: (1 << 21), Count: 4}, + {Num: (1 << 28) - 1, Count: 4}, + {Num: (1 << 28), Count: 5}, + {Num: (1 << 35) - 1, Count: 5}, + {Num: (1 << 35), Count: 6}, + {Num: (1 << 42) - 1, Count: 6}, + {Num: (1 << 42), Count: 7}, + {Num: (1 << 49) - 1, Count: 7}, + {Num: (1 << 49), Count: 8}, + {Num: (1 << 56) - 1, Count: 8}, + {Num: (1 << 56), Count: 9}, + {Num: (1 << 63) - 1, Count: 9}, +} + func TestCountVarSize(t *testing.T) { - var testCases = []struct { - Num int - Count int - }{ - {Num: (1 << 7) - 1, Count: 1}, - {Num: (1 << 7), Count: 2}, - {Num: (1 << 14) - 1, Count: 2}, - {Num: (1 << 14), Count: 3}, - {Num: (1 << 21) - 1, Count: 3}, - {Num: (1 << 21), Count: 4}, - {Num: (1 << 28) - 1, Count: 4}, - {Num: (1 << 28), Count: 5}, - {Num: (1 << 35) - 1, Count: 5}, - {Num: (1 << 35), Count: 6}, - {Num: (1 << 42) - 1, Count: 6}, - {Num: (1 << 42), Count: 7}, - {Num: (1 << 49) - 1, Count: 7}, - {Num: (1 << 49), Count: 8}, - {Num: (1 << 56) - 1, Count: 8}, - {Num: (1 << 56), Count: 9}, - {Num: (1 << 63) - 1, Count: 9}, - } - for _, testCase := range testCases { + for _, testCase := range varSizeTestCases { count := CountVarSize(testCase.Num) if count != testCase.Count { t.Fatalf("calculated count %d is not equal %d for num %d\n", @@ -793,6 +794,60 @@ func TestCountVarSize(t *testing.T) { } } +func TestWriteReadVarSize(t *testing.T) { + for _, testCase := range varSizeTestCases { + w := bytes.NewBuffer(nil) + count, err := WriteVarSize(w, testCase.Num) + if err != nil { + t.Fatal(err) + } + decoded, err := ReadVarSize(w) + if err != nil { + t.Fatal(err) + } + if decoded != testCase.Num { + t.Fatalf("num %d not equal decoded %d", testCase.Num, decoded) + } + if count != testCase.Count { + t.Fatalf("count %d not equal decoded count %d of num %d", + testCase.Count, count, testCase.Num) + } + } + // negative size + w := bytes.NewBuffer(nil) + _, err := WriteVarSize(w, -1) + if err != ErrNegativeSize { + t.Fatal("negative size did not lead to ErrNegativeSize") + } +} + +func TestPutGetVarSize(t *testing.T) { + for _, testCase := range varSizeTestCases { + a := make([]byte, 9) + count, err := PutVarSize(a, testCase.Num) + if err != nil { + t.Fatal(err) + } + decoded, err := GetVarSize(a) + if err != nil { + t.Fatal(err) + } + if decoded != testCase.Num { + t.Fatalf("num %d not equal decoded %d", testCase.Num, decoded) + } + if count != testCase.Count { + t.Fatalf("count %d not equal decoded count %d of num %d", + testCase.Count, count, testCase.Num) + } + } + // negative size + a := make([]byte, 9) + _, err := PutVarSize(a, -1) + if err != ErrNegativeSize { + t.Fatal("negative size did not lead to ErrNegativeSize") + } +} + // HELPERS const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"