tape: Break out array code into separate file
This commit is contained in:
parent
4438210963
commit
c3337641bc
206
tape/array.go
Normal file
206
tape/array.go
Normal file
@ -0,0 +1,206 @@
|
||||
package tape
|
||||
|
||||
import "fmt"
|
||||
import "iter"
|
||||
import "slices"
|
||||
|
||||
// encoding and decoding functions must not make any allocations
|
||||
|
||||
func DecodeArray(data []byte, itemLength int) iter.Seq[[]byte] {
|
||||
return slices.Chunk(data, itemLength)
|
||||
}
|
||||
|
||||
func EncodeArray(data []byte, items ...[]byte) (n int, err error) {
|
||||
for _, item := range items {
|
||||
if n >= len(data) { return n, ErrWrongBufferLength }
|
||||
copy(data[n:], item)
|
||||
n += len(item)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func ArraySize(length, itemLength int) int {
|
||||
return length * itemLength
|
||||
}
|
||||
|
||||
// DecodeStringArray decodes a packed string array from the given data.
|
||||
func DecodeStringArray[T String](data []byte) (result []T, n int, err error) {
|
||||
for len(data) > 0 {
|
||||
if len(data) < 2 { return nil, n, fmt.Errorf("decoding []string: %w", ErrWrongBufferLength) }
|
||||
itemSize16, nn, _ := DecodeI16[uint16](data[:2])
|
||||
itemSize := int(itemSize16)
|
||||
n += nn
|
||||
data = data[nn:]
|
||||
if len(data) < itemSize { return nil, n, fmt.Errorf("decoding []string: %w", ErrWrongBufferLength) }
|
||||
result = append(result, T(data[:itemSize]))
|
||||
data = data[itemSize:]
|
||||
n += itemSize
|
||||
}
|
||||
return result, n, nil
|
||||
}
|
||||
|
||||
// EncodeStringArray encodes a packed string array into the given buffer.
|
||||
func EncodeStringArray[T String](buffer []byte, value []T) (n int, err error) {
|
||||
for _, item := range value {
|
||||
length, err := StringSize(item)
|
||||
if err != nil { return n, err }
|
||||
if len(buffer) < 2 + length { return n, fmt.Errorf("encoding []string: %w", ErrWrongBufferLength) }
|
||||
EncodeI16(buffer[:2], uint16(length))
|
||||
buffer = buffer[2:]
|
||||
copy(buffer, item)
|
||||
buffer = buffer[length:]
|
||||
n += 2 + length
|
||||
}
|
||||
if len(buffer) > 0 { return n, fmt.Errorf("encoding []string: %w", ErrWrongBufferLength) }
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// StringArraySize returns the size of a packed string array. Returns 0 and an
|
||||
// error if the size is too large.
|
||||
func StringArraySize[T String](value []T) (int, error) {
|
||||
total := 0
|
||||
for _, item := range value {
|
||||
total += 2 + len(item)
|
||||
}
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI8Array decodes a packed array of 8 bit integers from the given data.
|
||||
func DecodeI8Array[T Int8](data []byte) (result []T, n int, err error) {
|
||||
result = make([]T, len(data))
|
||||
for index, item := range data {
|
||||
result[index] = T(item)
|
||||
}
|
||||
return result, len(data), nil
|
||||
}
|
||||
|
||||
// EncodeI8Array encodes a packed array of 8 bit integers into the given buffer.
|
||||
func EncodeI8Array[T Int8](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) { return 0, fmt.Errorf("encoding []int8: %w", ErrWrongBufferLength) }
|
||||
for index, item := range value {
|
||||
buffer[index] = byte(item)
|
||||
}
|
||||
return len(buffer), nil
|
||||
}
|
||||
|
||||
// I8ArraySize returns the size of a packed 8 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I8ArraySize[T Int8](value []T) (int, error) {
|
||||
total := len(value)
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI16Array decodes a packed array of 16 bit integers from the given data.
|
||||
func DecodeI16Array[T Int16](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 2 != 0 { return nil, 0, fmt.Errorf("decoding []int16: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 2
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 2
|
||||
result[index] = T(data[offset]) << 8 | T(data[offset + 1])
|
||||
}
|
||||
return result, len(data) / 2, nil
|
||||
}
|
||||
|
||||
// EncodeI16Array encodes a packed array of 16 bit integers into the given buffer.
|
||||
func EncodeI16Array[T Int16](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 2 { return 0, fmt.Errorf("encoding []int16: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 8)
|
||||
buffer[1] = byte(item)
|
||||
buffer = buffer[2:]
|
||||
}
|
||||
return len(value) * 2, nil
|
||||
}
|
||||
|
||||
// I16ArraySize returns the size of a packed 16 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I16ArraySize[T Int16](value []T) (int, error) {
|
||||
total := len(value) * 2
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI32Array decodes a packed array of 32 bit integers from the given data.
|
||||
func DecodeI32Array[T Int32](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 4 != 0 { return nil, 0, fmt.Errorf("decoding []int32: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 4
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 4
|
||||
result[index] =
|
||||
T(data[offset + 0]) << 24 |
|
||||
T(data[offset + 1]) << 16 |
|
||||
T(data[offset + 2]) << 8 |
|
||||
T(data[offset + 3])
|
||||
}
|
||||
return result, len(data) / 4, nil
|
||||
}
|
||||
|
||||
// EncodeI32Array encodes a packed array of 32 bit integers into the given buffer.
|
||||
func EncodeI32Array[T Int32](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 4 { return 0, fmt.Errorf("encoding []int32: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 24)
|
||||
buffer[1] = byte(item >> 16)
|
||||
buffer[2] = byte(item >> 8)
|
||||
buffer[3] = byte(item)
|
||||
buffer = buffer[4:]
|
||||
}
|
||||
return len(value) * 4, nil
|
||||
}
|
||||
|
||||
// I32ArraySize returns the size of a packed 32 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I32ArraySize[T Int32](value []T) (int, error) {
|
||||
total := len(value) * 4
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI64Array decodes a packed array of 32 bit integers from the given data.
|
||||
func DecodeI64Array[T Int64](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 8 != 0 { return nil, 0, fmt.Errorf("decoding []int64: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 8
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 8
|
||||
result[index] =
|
||||
T(data[offset + 0]) << 56 |
|
||||
T(data[offset + 1]) << 48 |
|
||||
T(data[offset + 2]) << 40 |
|
||||
T(data[offset + 3]) << 32 |
|
||||
T(data[offset + 4]) << 24 |
|
||||
T(data[offset + 5]) << 16 |
|
||||
T(data[offset + 6]) << 8 |
|
||||
T(data[offset + 7])
|
||||
}
|
||||
return result, len(data) / 8, nil
|
||||
}
|
||||
|
||||
// EncodeI64Array encodes a packed array of 64 bit integers into the given buffer.
|
||||
func EncodeI64Array[T Int64](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 8 { return 0, fmt.Errorf("encoding []int64: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 56)
|
||||
buffer[1] = byte(item >> 48)
|
||||
buffer[2] = byte(item >> 40)
|
||||
buffer[3] = byte(item >> 32)
|
||||
buffer[4] = byte(item >> 24)
|
||||
buffer[5] = byte(item >> 16)
|
||||
buffer[6] = byte(item >> 8)
|
||||
buffer[7] = byte(item)
|
||||
buffer = buffer[8:]
|
||||
}
|
||||
return len(value) * 8, nil
|
||||
}
|
||||
|
||||
// I64ArraySize returns the size of a packed 64 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I64ArraySize[T Int64](value []T) (int, error) {
|
||||
total := len(value) * 8
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
131
tape/array_test.go
Normal file
131
tape/array_test.go
Normal file
@ -0,0 +1,131 @@
|
||||
package tape
|
||||
|
||||
// import "fmt"
|
||||
import "slices"
|
||||
// import "errors"
|
||||
import "testing"
|
||||
import "math/rand"
|
||||
|
||||
func TestI8Array(test *testing.T) {
|
||||
var buffer [64]byte
|
||||
_, err := EncodeI8Array[uint8](buffer[:], []uint8 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int8: wrong buffer length") { test.Fatal(err) }
|
||||
_, err = EncodeI8Array[uint8](buffer[:0], []uint8 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int8: wrong buffer length") { test.Fatal(err) }
|
||||
_, _, err = DecodeI8Array[uint8](buffer[:])
|
||||
if err != nil { test.Fatal(err) }
|
||||
_, _, err = DecodeI8Array[uint8](buffer[:0])
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
for _ = range largeNumberNTestRounds {
|
||||
array := randInts[uint8](rand.Intn(16))
|
||||
length, _ := I8ArraySize(array)
|
||||
if length != len(array) { test.Fatalf("%d != %d", length, len(array)) }
|
||||
_, err := EncodeI8Array[uint8](buffer[:length], array)
|
||||
if err != nil { test.Fatal(err) }
|
||||
decoded, _, err := DecodeI8Array[uint8](buffer[:length])
|
||||
if err != nil { test.Fatal(err) }
|
||||
if !slices.Equal(decoded, array) {
|
||||
test.Fatalf("%v != %v", decoded, array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestI16Array(test *testing.T) {
|
||||
var buffer [128]byte
|
||||
_, err := EncodeI16Array[uint16](buffer[:], []uint16 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int16: wrong buffer length") { test.Fatal(err) }
|
||||
_, err = EncodeI16Array[uint16](buffer[:0], []uint16 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int16: wrong buffer length") { test.Fatal(err) }
|
||||
_, _, err = DecodeI16Array[uint16](buffer[:])
|
||||
if err != nil { test.Fatal(err) }
|
||||
_, _, err = DecodeI16Array[uint16](buffer[:0])
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
for _ = range largeNumberNTestRounds {
|
||||
array := randInts[uint16](rand.Intn(16))
|
||||
length, _ := I16ArraySize(array)
|
||||
if length != 2 * len(array) { test.Fatalf("%d != %d", length, 2 * len(array)) }
|
||||
_, err := EncodeI16Array[uint16](buffer[:length], array)
|
||||
if err != nil { test.Fatal(err) }
|
||||
decoded, _, err := DecodeI16Array[uint16](buffer[:length])
|
||||
if err != nil { test.Fatal(err) }
|
||||
if !slices.Equal(decoded, array) {
|
||||
test.Fatalf("%v != %v", decoded, array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestI32Array(test *testing.T) {
|
||||
var buffer [256]byte
|
||||
_, err := EncodeI32Array[uint32](buffer[:], []uint32 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int32: wrong buffer length") { test.Fatal(err) }
|
||||
_, err = EncodeI32Array[uint32](buffer[:0], []uint32 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int32: wrong buffer length") { test.Fatal(err) }
|
||||
_, _, err = DecodeI32Array[uint32](buffer[:])
|
||||
if err != nil { test.Fatal(err) }
|
||||
_, _, err = DecodeI32Array[uint32](buffer[:0])
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
for _ = range largeNumberNTestRounds {
|
||||
array := randInts[uint32](rand.Intn(16))
|
||||
length, _ := I32ArraySize(array)
|
||||
if length != 4 * len(array) { test.Fatalf("%d != %d", length, 4 * len(array)) }
|
||||
_, err := EncodeI32Array[uint32](buffer[:length], array)
|
||||
if err != nil { test.Fatal(err) }
|
||||
decoded, _, err := DecodeI32Array[uint32](buffer[:length])
|
||||
if err != nil { test.Fatal(err) }
|
||||
if !slices.Equal(decoded, array) {
|
||||
test.Fatalf("%v != %v", decoded, array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestI64Array(test *testing.T) {
|
||||
var buffer [512]byte
|
||||
_, err := EncodeI64Array[uint64](buffer[:], []uint64 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int64: wrong buffer length") { test.Fatal(err) }
|
||||
_, err = EncodeI64Array[uint64](buffer[:0], []uint64 { 0, 4, 50, 19 })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []int64: wrong buffer length") { test.Fatal(err) }
|
||||
_, _, err = DecodeI64Array[uint64](buffer[:])
|
||||
if err != nil { test.Fatal(err) }
|
||||
_, _, err = DecodeI64Array[uint64](buffer[:0])
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
for _ = range largeNumberNTestRounds {
|
||||
array := randInts[uint64](rand.Intn(16))
|
||||
length, _ := I64ArraySize(array)
|
||||
if length != 8 * len(array) { test.Fatalf("%d != %d", length, 8 * len(array)) }
|
||||
_, err := EncodeI64Array[uint64](buffer[:length], array)
|
||||
if err != nil { test.Fatal(err) }
|
||||
decoded, _, err := DecodeI64Array[uint64](buffer[:length])
|
||||
if err != nil { test.Fatal(err) }
|
||||
if !slices.Equal(decoded, array) {
|
||||
test.Fatalf("%v != %v", decoded, array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArray(test *testing.T) {
|
||||
var buffer [8192]byte
|
||||
_, err := EncodeStringArray[string](buffer[:], []string { "0", "4", "50", "19" })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []string: wrong buffer length") { test.Fatal(err) }
|
||||
_, err = EncodeStringArray[string](buffer[:0], []string { "0", "4", "50", "19" })
|
||||
if !errIs(err, ErrWrongBufferLength, "encoding []string: wrong buffer length") { test.Fatal(err) }
|
||||
_, _, err = DecodeStringArray[string](buffer[:0])
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
for _ = range largeNumberNTestRounds {
|
||||
array := randStrings[string](rand.Intn(16), 16)
|
||||
length, _ := StringArraySize(array)
|
||||
// TODO test length
|
||||
_, err := EncodeStringArray[string](buffer[:length], array)
|
||||
if err != nil { test.Fatal(err) }
|
||||
decoded, _, err := DecodeStringArray[string](buffer[:length])
|
||||
if err != nil { test.Fatal(err) }
|
||||
if !slices.Equal(decoded, array) {
|
||||
test.Fatalf("%v != %v", decoded, array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
182
tape/types.go
182
tape/types.go
@ -169,188 +169,6 @@ func StringSize[T String](value T) (int, error) {
|
||||
return len(value), nil
|
||||
}
|
||||
|
||||
// DecodeStringArray decodes a packed string array from the given data.
|
||||
func DecodeStringArray[T String](data []byte) (result []T, n int, err error) {
|
||||
for len(data) > 0 {
|
||||
if len(data) < 2 { return nil, n, fmt.Errorf("decoding []string: %w", ErrWrongBufferLength) }
|
||||
itemSize16, nn, _ := DecodeI16[uint16](data[:2])
|
||||
itemSize := int(itemSize16)
|
||||
n += nn
|
||||
data = data[nn:]
|
||||
if len(data) < itemSize { return nil, n, fmt.Errorf("decoding []string: %w", ErrWrongBufferLength) }
|
||||
result = append(result, T(data[:itemSize]))
|
||||
data = data[itemSize:]
|
||||
n += itemSize
|
||||
}
|
||||
return result, n, nil
|
||||
}
|
||||
|
||||
// EncodeStringArray encodes a packed string array into the given buffer.
|
||||
func EncodeStringArray[T String](buffer []byte, value []T) (n int, err error) {
|
||||
for _, item := range value {
|
||||
length, err := StringSize(item)
|
||||
if err != nil { return n, err }
|
||||
if len(buffer) < 2 + length { return n, fmt.Errorf("encoding []string: %w", ErrWrongBufferLength) }
|
||||
EncodeI16(buffer[:2], uint16(length))
|
||||
buffer = buffer[2:]
|
||||
copy(buffer, item)
|
||||
buffer = buffer[length:]
|
||||
n += 2 + length
|
||||
}
|
||||
if len(buffer) > 0 { return n, fmt.Errorf("encoding []string: %w", ErrWrongBufferLength) }
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// StringArraySize returns the size of a packed string array. Returns 0 and an
|
||||
// error if the size is too large.
|
||||
func StringArraySize[T String](value []T) (int, error) {
|
||||
total := 0
|
||||
for _, item := range value {
|
||||
total += 2 + len(item)
|
||||
}
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI8Array decodes a packed array of 8 bit integers from the given data.
|
||||
func DecodeI8Array[T Int8](data []byte) (result []T, n int, err error) {
|
||||
result = make([]T, len(data))
|
||||
for index, item := range data {
|
||||
result[index] = T(item)
|
||||
}
|
||||
return result, len(data), nil
|
||||
}
|
||||
|
||||
// EncodeI8Array encodes a packed array of 8 bit integers into the given buffer.
|
||||
func EncodeI8Array[T Int8](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) { return 0, fmt.Errorf("encoding []int8: %w", ErrWrongBufferLength) }
|
||||
for index, item := range value {
|
||||
buffer[index] = byte(item)
|
||||
}
|
||||
return len(buffer), nil
|
||||
}
|
||||
|
||||
// I8ArraySize returns the size of a packed 8 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I8ArraySize[T Int8](value []T) (int, error) {
|
||||
total := len(value)
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI16Array decodes a packed array of 16 bit integers from the given data.
|
||||
func DecodeI16Array[T Int16](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 2 != 0 { return nil, 0, fmt.Errorf("decoding []int16: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 2
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 2
|
||||
result[index] = T(data[offset]) << 8 | T(data[offset + 1])
|
||||
}
|
||||
return result, len(data) / 2, nil
|
||||
}
|
||||
|
||||
// EncodeI16Array encodes a packed array of 16 bit integers into the given buffer.
|
||||
func EncodeI16Array[T Int16](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 2 { return 0, fmt.Errorf("encoding []int16: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 8)
|
||||
buffer[1] = byte(item)
|
||||
buffer = buffer[2:]
|
||||
}
|
||||
return len(value) * 2, nil
|
||||
}
|
||||
|
||||
// I16ArraySize returns the size of a packed 16 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I16ArraySize[T Int16](value []T) (int, error) {
|
||||
total := len(value) * 2
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI32Array decodes a packed array of 32 bit integers from the given data.
|
||||
func DecodeI32Array[T Int32](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 4 != 0 { return nil, 0, fmt.Errorf("decoding []int32: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 4
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 4
|
||||
result[index] =
|
||||
T(data[offset + 0]) << 24 |
|
||||
T(data[offset + 1]) << 16 |
|
||||
T(data[offset + 2]) << 8 |
|
||||
T(data[offset + 3])
|
||||
}
|
||||
return result, len(data) / 4, nil
|
||||
}
|
||||
|
||||
// EncodeI32Array encodes a packed array of 32 bit integers into the given buffer.
|
||||
func EncodeI32Array[T Int32](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 4 { return 0, fmt.Errorf("encoding []int32: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 24)
|
||||
buffer[1] = byte(item >> 16)
|
||||
buffer[2] = byte(item >> 8)
|
||||
buffer[3] = byte(item)
|
||||
buffer = buffer[4:]
|
||||
}
|
||||
return len(value) * 4, nil
|
||||
}
|
||||
|
||||
// I32ArraySize returns the size of a packed 32 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I32ArraySize[T Int32](value []T) (int, error) {
|
||||
total := len(value) * 4
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// DecodeI64Array decodes a packed array of 32 bit integers from the given data.
|
||||
func DecodeI64Array[T Int64](data []byte) (value []T, n int, err error) {
|
||||
if len(data) % 8 != 0 { return nil, 0, fmt.Errorf("decoding []int64: %w", ErrWrongBufferLength) }
|
||||
length := len(data) / 8
|
||||
result := make([]T, length)
|
||||
for index := range length {
|
||||
offset := index * 8
|
||||
result[index] =
|
||||
T(data[offset + 0]) << 56 |
|
||||
T(data[offset + 1]) << 48 |
|
||||
T(data[offset + 2]) << 40 |
|
||||
T(data[offset + 3]) << 32 |
|
||||
T(data[offset + 4]) << 24 |
|
||||
T(data[offset + 5]) << 16 |
|
||||
T(data[offset + 6]) << 8 |
|
||||
T(data[offset + 7])
|
||||
}
|
||||
return result, len(data) / 8, nil
|
||||
}
|
||||
|
||||
// EncodeI64Array encodes a packed array of 64 bit integers into the given buffer.
|
||||
func EncodeI64Array[T Int64](buffer []byte, value []T) (n int, err error) {
|
||||
if len(buffer) != len(value) * 8 { return 0, fmt.Errorf("encoding []int64: %w", ErrWrongBufferLength) }
|
||||
for _, item := range value {
|
||||
buffer[0] = byte(item >> 56)
|
||||
buffer[1] = byte(item >> 48)
|
||||
buffer[2] = byte(item >> 40)
|
||||
buffer[3] = byte(item >> 32)
|
||||
buffer[4] = byte(item >> 24)
|
||||
buffer[5] = byte(item >> 16)
|
||||
buffer[6] = byte(item >> 8)
|
||||
buffer[7] = byte(item)
|
||||
buffer = buffer[8:]
|
||||
}
|
||||
return len(value) * 8, nil
|
||||
}
|
||||
|
||||
// I64ArraySize returns the size of a packed 64 bit integer array. Returns 0 and
|
||||
// an error if the size is too large.
|
||||
func I64ArraySize[T Int64](value []T) (int, error) {
|
||||
total := len(value) * 8
|
||||
if total > dataMaxSize { return 0, ErrDataTooLarge }
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// U16CastSafe safely casts an integer to a uint16. If an overflow or underflow
|
||||
// occurs, it will return (0, false).
|
||||
func U16CastSafe(n int) (uint16, bool) {
|
||||
|
Loading…
Reference in New Issue
Block a user