tape: Add table encoding/decoding functions
This commit is contained in:
parent
4f3b256821
commit
3d8a012477
59
tape/table.go
Normal file
59
tape/table.go
Normal file
@ -0,0 +1,59 @@
|
||||
package tape
|
||||
|
||||
import "iter"
|
||||
|
||||
// encoding and decoding functions must not make any allocations
|
||||
|
||||
type TablePushFunc func(tag uint16, value []byte) (n int, err error)
|
||||
|
||||
func DecodeTable(data []byte) iter.Seq2[uint16, []byte] {
|
||||
return func(yield func(tag uint16, value []byte) bool) {
|
||||
n := 0
|
||||
for {
|
||||
tag, nn, err := DecodeI16[uint16](data[n:])
|
||||
if err != nil { return }
|
||||
n += nn
|
||||
|
||||
length, nn, err := DecodeGBEU[uint64](data[n:])
|
||||
if err != nil { return }
|
||||
n += nn
|
||||
|
||||
value := data[n:n + int(length)]
|
||||
yield(tag, value)
|
||||
n += int(length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeTable(data []byte) TablePushFunc {
|
||||
return func(tag uint16, value []byte) (n int, err error) {
|
||||
if n >= len(data) { return n, ErrWrongBufferLength }
|
||||
nn, err := EncodeI16(data[n:], uint16(tag))
|
||||
if err != nil { return n, err }
|
||||
n += nn
|
||||
|
||||
if n >= len(data) { return n, ErrWrongBufferLength }
|
||||
nn, err = EncodeGBEU(data[n:], uint(len(value)))
|
||||
if err != nil { return n, err }
|
||||
n += nn
|
||||
|
||||
if n >= len(data) { return n, ErrWrongBufferLength }
|
||||
nn = copy(data[n:], value)
|
||||
n += nn
|
||||
if nn < len(value) {
|
||||
return n, ErrWrongBufferLength
|
||||
}
|
||||
|
||||
if n >= len(data) { return n, ErrWrongBufferLength }
|
||||
data = data[n:]
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
func TableSize(itemLengths ...int) int {
|
||||
sum := 0
|
||||
for _, length := range itemLengths {
|
||||
sum += GBEUSize(uint(length)) + length
|
||||
}
|
||||
return sum
|
||||
}
|
100
tape/table_test.go
Normal file
100
tape/table_test.go
Normal file
@ -0,0 +1,100 @@
|
||||
package tape
|
||||
|
||||
import "fmt"
|
||||
import "slices"
|
||||
// import "errors"
|
||||
import "testing"
|
||||
// import "math/rand"
|
||||
|
||||
var longText =
|
||||
`Curious, I started off in that direction, only for Prism to stop me. "Wrong way, Void. It's right over here." He trotted over to a door to the left of us. It was marked with the number '4004'. He took a key out of his saddlebags, unlocked it, and pushed it open. "You know, some say this suite is haunted. They call the ghost that lives here the 'Spirit of 4004'. Ooooh!" He made paddling motions in the air with his hooves.`
|
||||
|
||||
func TestTable(test *testing.T) {
|
||||
item5 := []byte("hello")
|
||||
item7 := []byte("world")
|
||||
item0 := []byte(longText)
|
||||
item3249 := []byte { 0x0, 0x1, 0x2, 0x3, 0xA0, 0x5 }
|
||||
|
||||
buffer := [512]byte { }
|
||||
push := EncodeTable(buffer[:])
|
||||
_, err := push(5, item5)
|
||||
if err != nil { test.Fatal(err)}
|
||||
_, err = push(7, item7)
|
||||
if err != nil { test.Fatal(err)}
|
||||
_, err = push(0, item0)
|
||||
if err != nil { test.Fatal(err)}
|
||||
_, err = push(3249, item3249)
|
||||
if err != nil { test.Fatal(err)}
|
||||
|
||||
test.Logf("len of longText: %d 0x%X", len(longText), len(longText))
|
||||
correct := []byte("\x00\x05\x05hello\x00\x07\x05world\x00\x00\x83\x28" + longText)
|
||||
if got := buffer[:len(correct)]; !slices.Equal(got, correct) {
|
||||
if !compareHexArray(test, correct, got) {
|
||||
test.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableSmall(test *testing.T) {
|
||||
item2 := []byte("hello")
|
||||
item3249 := []byte { 0x0, 0x1, 0x2, 0x3, 0xA0, 0x5 }
|
||||
|
||||
buffer := [64]byte { }
|
||||
push := EncodeTable(buffer[:])
|
||||
_, err := push(2, item2)
|
||||
if err != nil { test.Fatal(err) }
|
||||
_, err = push(3249, item3249)
|
||||
if err != nil { test.Fatal(err) }
|
||||
|
||||
correct := []byte("\x00\x02\x05hello\x0C\xB1\x06\x00\x01\x02\x03\xA0\x05")
|
||||
if got := buffer[:len(correct)]; !slices.Equal(got, correct) {
|
||||
if !compareHexArray(test, correct, got) {
|
||||
test.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpHexArray(data []byte) (message string) {
|
||||
for _, item := range data {
|
||||
message = fmt.Sprintf("%s %02X", message, item)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func compareHexArray(test *testing.T, correct, got []byte) bool {
|
||||
index := 0
|
||||
for {
|
||||
if index >= len(correct) {
|
||||
if index < len(got) {
|
||||
test.Log("correct longer than got")
|
||||
test.Log("got: ", dumpHexArray(got))
|
||||
test.Log("correct:", dumpHexArray(correct))
|
||||
return false
|
||||
}
|
||||
}
|
||||
if index >= len(got) {
|
||||
if index < len(correct) {
|
||||
test.Log("got longer than correct")
|
||||
test.Log("got: ", dumpHexArray(got))
|
||||
test.Log("correct:", dumpHexArray(correct))
|
||||
return false
|
||||
}
|
||||
}
|
||||
if correct[index] != got[index] {
|
||||
test.Log("not equal")
|
||||
test.Log("got: ", dumpHexArray(got))
|
||||
test.Log("correct:", dumpHexArray(correct))
|
||||
partLow := index - 8
|
||||
partHigh := index + 8
|
||||
test.Log("got part ", dumpHexArray(safeSlice(got, partLow, partHigh)))
|
||||
test.Log("correct part", dumpHexArray(safeSlice(correct, partLow, partHigh)))
|
||||
return false
|
||||
}
|
||||
index ++
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func safeSlice[T any](slice []T, low, high int) []T {
|
||||
return slice[max(low, 0):min(high, len(slice))]
|
||||
}
|
Loading…
Reference in New Issue
Block a user