Add int packer and unpacker

This commit is contained in:
ChillerDragon 2024-06-17 12:23:54 +08:00
parent 47163dce87
commit 4605d3907c
2 changed files with 230 additions and 0 deletions

67
packer/packer.go Normal file
View file

@ -0,0 +1,67 @@
package packer
import "errors"
func PackInt(num int) ([]byte, error) {
dstLen := 4
res := []byte{0x00}
idx := 0
if num < 0 {
res[0] |= 0x40 // set sign bit
num = ^num
}
res[0] |= byte(num & 0x3F) // pack 6 bit into dst
num >>= 6 // discard 6 bits
for num != 0 {
if idx > dstLen {
return nil, errors.New("Int too big")
}
res = append(res, 0x00)
res[idx] |= 0x80 // set extend bit
idx++
res[idx] = byte(num & 0x7F) // pack 7 bit
num >>= 7 // discard 7 bits
}
return res, nil
}
func UnpackInt(data []byte) int {
sign := int(data[0]>>6) & 1
res := int(data[0] & 0x3F)
i := 0
// fake loop should only loop once
// its the poor mans goto hack
for {
if (data[i] & 0x80) == 0 {
break
}
i += 1
res |= int(data[i]&0x7F) << 6
if (data[i] & 0x80) == 0 {
break
}
i += 1
res |= int(data[i]&0x7F) << (6 + 7)
if (data[i] & 0x80) == 0 {
break
}
i += 1
res |= int(data[i]&0x7F) << (6 + 7 + 7)
if (data[i] & 0x80) == 0 {
break
}
i += 1
res |= int(data[i]&0x7F) << (6 + 7 + 7 + 7)
break
}
res ^= -sign
return res
}

163
packer/packer_test.go Normal file
View file

@ -0,0 +1,163 @@
package packer
import (
"reflect"
"testing"
)
// pack
func TestPackSmallPositiveInts(t *testing.T) {
got, err := PackInt(1)
want := []byte{0x01}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestPackMultiBytePositiveInts(t *testing.T) {
got, err := PackInt(63)
want := []byte{0x3F}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got, err = PackInt(64)
want = []byte{0x80, 0x01}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got, err = PackInt(65)
want = []byte{0x81, 0x01}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestPackSmallNegativeInts(t *testing.T) {
got, err := PackInt(-1)
want := []byte{0x40}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got, err = PackInt(-2)
want = []byte{0x41}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestPackMultiByteNegativeInts(t *testing.T) {
got, err := PackInt(-63)
want := []byte{0x7E}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got, err = PackInt(-64)
want = []byte{0x7F}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got, err = PackInt(-65)
want = []byte{0xC0, 0x01}
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
// unpack
func TestUnpackSmallPositiveInts(t *testing.T) {
got := UnpackInt([]byte{0x01})
want := 1
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got = UnpackInt([]byte{0x02})
want = 2
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got = UnpackInt([]byte{0x03})
want = 3
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestUnpackMultiBytePositiveInts(t *testing.T) {
got := UnpackInt([]byte{0x3f})
want := 63
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got = UnpackInt([]byte{0x80, 0x01})
want = 64
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
got = UnpackInt([]byte{0x81, 0x01})
want = 65
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}