User Tools

Site Tools


Binary coding-decoding at reflect

As research

goos: linux
goarch: amd64
pkg: fsm/finder
cpu: Intel(R) Core(TM) i5-4300U CPU @ 1.90GHz
BenchmarkBinWrite-4     	13289688	       185.1 ns/op	     128 B/op	       4 allocs/op
BenchmarkAtoi-4         	53319615	        44.95 ns/op	       7 B/op	       0 allocs/op
BenchmarkEncoder-4      	40339908	        57.88 ns/op	      15 B/op	       1 allocs/op
BenchmarkEncoderHex-4   	21469190	       118.1 ns/op	      31 B/op	       2 allocs/op
PASS
ok  	fsm/finder	10.142s
icoder.go
//
// Package for converting integers to byte array and vice versa.
// BigEndian byte order is used.
//
package icoder
 
import (
    "bytes"
    "encoding/binary"
    "errors"
    "reflect"
)
 
const sizeOfInt64 int = 8
const sizeOfInt32 int = 4
const sizeOfInt16 int = 2
 
// Standard method for comparison
func BinWrite(v interface{}) ([]byte, error) {
    buffer := new(bytes.Buffer)
    err := binary.Write(buffer, binary.BigEndian, v)
    return buffer.Bytes(), err
}
 
// Converts an integer or an integer reference to an appropriately
// sized byte array. If a non-integer number is passed,
// the function returns an error
func Encoder(intv interface{}) ([]byte, error) {
    const sizeOfInt64 int = 8
    const bitsPerByte int = 8
    var err error
    var uintv uint64
 
    buffer := make([]byte, sizeOfInt64)
    v := reflect.ValueOf(intv)
    i := reflect.Indirect(v)
    t := i.Type()
 
    kind := t.Kind()
    switch kind {
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
            uintv = uint64(i.Int())
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
            uintv = uint64(i.Uint())
        default:
            return buffer, errors.New("type is not int or uint kind")
    }
    vSize := t.Bits() / bitsPerByte
    binary.BigEndian.PutUint64(buffer, uintv)
    return buffer[sizeOfInt64 - vSize:], err
}
 
 
// Converts a byte array to an integer passed by reference
func Decoder(b []byte, s interface{}) error {
    var err error
    var uintv uint64
 
    lenb := len(b)
    buffer := make([]byte, sizeOfInt64 - lenb)
    buffer = append(buffer, b...)
    uintv = binary.BigEndian.Uint64(buffer)
 
    v := reflect.ValueOf(s)
    i := reflect.Indirect(v)
    t := i.Type()
 
    kind := t.Kind()
    switch kind {
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
            i.SetInt(int64(uintv))
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
            i.SetUint(uint64(uintv))
        default:
            return errors.New("type is not int or uint kind")
    }
    return err
}
 
// Converts an integer to a byte array
func EncoderU64(s uint64) []byte {
    buffer := make([]byte, sizeOfInt64)
    binary.BigEndian.PutUint64(buffer, s)
    return buffer
}
 
// Converts an integer to a byte array
func EncoderU32(s uint32) []byte {
    buffer := make([]byte, sizeOfInt32)
    binary.BigEndian.PutUint32(buffer, s)
    return buffer
}
 
// Converts an integer to a byte array
func EncoderU16(s uint16) []byte {
    buffer := make([]byte, sizeOfInt16)
    binary.BigEndian.PutUint16(buffer, s)
    return buffer
}
 
// Converts a byte array to an integer.
func DecoderU64(b []byte) uint64 {
    return binary.BigEndian.Uint64(b)
}
 
// Converts a byte array to an integer.
func DecoderU32(b []byte) uint32 {
    return binary.BigEndian.Uint32(b)
}
 
// Converts a byte array to an integer.
func DecoderU16(b []byte) uint16 {
    return binary.BigEndian.Uint16(b)
}
//EOF
icoder_test.go
//
// $Id$
//
package icoder
 
import (
    "encoding/hex"
    "testing"
    "strconv"
    "github.com/stretchr/testify/assert"
)
 
func TestEncoderDecoder64(t *testing.T) {
    i := uint64(12345678901234567898)
    b, err := Encoder(i)
    if err != nil {
        t.Fatal(err)
    }
    var o uint64
    err = Decoder(b, &o)
    if err != nil {
        t.Fatal(err)
    }
    assert.Equal(t, i, o, nil)
}
 
 
func TestEncoderDecoder32(t *testing.T) {
    i := uint32(1234567890)
    b, err := Encoder(i)
    if err != nil {
        t.Fatal(err)
    }
    var o uint32
    err = Decoder(b, &o)
    if err != nil {
        t.Fatal(err)
    }
    assert.Equal(t, i, o, nil)
}
 
func TestEncoderDecoderU64(t *testing.T) {
    i := uint64(1234567890123456789)
    b := EncoderU64(i)
    o := DecoderU64(b)
    assert.Equal(t, i, o, nil)
}
 
func TestEncoderDecoderU32(t *testing.T) {
    i := uint32(1234567890)
    b := EncoderU32(i)
    o := DecoderU32(b)
    assert.Equal(t, i, o, nil)
}
 
func TestEncoderDecoderU16(t *testing.T) {
    i := uint16(12345)
    b := EncoderU16(i)
    o := DecoderU16(b)
    assert.Equal(t, i, o, nil)
}
 
func BenchmarkBinWrite(b *testing.B) {
    for i := 0; i < b.N; i++ {
        i64 := int64(i)
        _, err := BinWrite(&i64)
        if err != nil {
            b.Error(err)
        }
    }
}
 
func BenchmarkAtoi(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = strconv.Itoa(i)
    }
}
 
func BenchmarkEncoder(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _, err := Encoder(i)
        if err != nil {
            b.Error(err)
        }
    }
}
 
func BenchmarkEncoderHex(b *testing.B) {
    for i := 0; i < b.N; i++ {
        bytes, err := Encoder(i)
        if err != nil {
            b.Error(err)
        }
        _ = hex.EncodeToString(bytes)
    }
}
//EOF