hopp/tape/array.go

207 lines
6.7 KiB
Go

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
}