Add int packer and unpacker
This commit is contained in:
parent
47163dce87
commit
4605d3907c
67
packer/packer.go
Normal file
67
packer/packer.go
Normal 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
163
packer/packer_test.go
Normal 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)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue