Skip to content

Instantly share code, notes, and snippets.

@urakozz
Created December 14, 2015 16:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save urakozz/56a92841bcd8e4178933 to your computer and use it in GitHub Desktop.
Save urakozz/56a92841bcd8e4178933 to your computer and use it in GitHub Desktop.
Flat Buffers with Golang
// automatically generated, do not modify
package encoder
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type Container struct {
_tab flatbuffers.Table
}
func GetRootAsContainer(buf []byte, offset flatbuffers.UOffsetT) *Container {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &Container{}
x.Init(buf, n + offset)
return x
}
func (rcv *Container) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *Container) Testarrayofmonsters(obj *Monster, j int) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
x = rcv._tab.Indirect(x)
if obj == nil {
obj = new(Monster)
}
obj.Init(rcv._tab.Bytes, x)
return true
}
return false
}
func (rcv *Container) TestarrayofmonstersLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func ContainerStart(builder *flatbuffers.Builder) { builder.StartObject(1) }
func ContainerAddTestarrayofmonsters(builder *flatbuffers.Builder, testarrayofmonsters flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(testarrayofmonsters), 0) }
func ContainerStartTestarrayofmonstersVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4)
}
func ContainerEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
// flat_buffers.fbs
// namespace encoder;
// brew install flatbuffers
// flatc -g flat_buffers.fbs
table Container {
testarrayofmonsters:[Monster];
}
table Monster {
name:string;
phone:string;
birthday:double;
money:double;
siblings:short;
spouse:bool;
strings:[string];
}
root_type Container;
file_identifier "MONS";
file_extension "mon";
package encoder
// Flat Buffers
// Encode/Decode time: 0.430/0.285
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/google/flatbuffers/go"
"io/ioutil"
"time"
"fmt"
)
func TestMarshalFlatbuf(t *testing.T) {
builder := flatbuffers.NewBuilder(0)
name := builder.CreateString("alex")
str1 := builder.CreateString("str1")
str2 := builder.CreateString("str2")
MonsterStartStringsVector(builder, 2)
builder.PrependUOffsetT(str2)
builder.PrependUOffsetT(str1)
stringArr := builder.EndVector(2)
MonsterStart(builder)
MonsterAddName(builder, name)
MonsterAddMoney(builder, 1.345)
MonsterAddStrings(builder, stringArr)
monster := MonsterEnd(builder)
builder.Finish(monster)
b := builder.Bytes[builder.Head():]
n := flatbuffers.GetUOffsetT(b)
dec := &Monster{}
dec.Init(b, n)
assert.Equal(t, []byte("alex"), dec.Name())
assert.Equal(t, 1.345, dec.Money())
assert.Equal(t, 2, dec.StringsLength())
assert.Equal(t, []byte("str1"), dec.Strings(0))
assert.Equal(t, []byte("str2"), dec.Strings(1))
data:= generate()
tim := time.Now()
encode(data)
fmt.Println(time.Since(tim))
}
func BenchmarkFlatbufCompress(b *testing.B) {
b.StopTimer()
data := generate()
b.ReportAllocs()
b.StartTimer()
var enc []byte
for n := 0; n < b.N; n++ {
enc = encode(data)
}
ioutil.WriteFile("data_flatbuff.txt", enc, 0666)
}
func BenchmarkFlatbufDecompress(b *testing.B) {
b.ReportAllocs()
input, _ := ioutil.ReadFile("data_flatbuff.txt")
var total time.Duration
for n := 0; n < b.N; n++ {
tm := time.Now()
decode(input)
total += time.Since(tm)
}
}
func encode(data ASlice)[]byte{
b := flatbuffers.NewBuilder(0)
ptrs := make([]flatbuffers.UOffsetT, len(data))
for i := 0;i < len(data);i++ {
value := data[i]
name := b.CreateString(value.Name)
phone := b.CreateString(value.Phone)
MonsterStart(b)
MonsterAddName(b, name)
MonsterAddPhone(b, phone)
MonsterAddMoney(b, value.Money)
MonsterAddBirthday(b, float64(value.BirthDay.UnixNano()))
MonsterAddSiblings(b, int16(value.Siblings))
bt := byte(0x0)
if value.Spouse {
bt = 0x1
}
MonsterAddSpouse(b, bt)
monster := MonsterEnd(b)
ptrs[i] = monster
}
ContainerStartTestarrayofmonstersVector(b, len(ptrs))
for i := len(ptrs)-1;i >= 0;i-- {
b.PrependUOffsetT(ptrs[i])
}
vptr := b.EndVector(len(ptrs))
ContainerStart(b)
ContainerAddTestarrayofmonsters(b, vptr)
container := ContainerEnd(b)
b.Finish(container)
return b.Bytes[b.Head():]
}
func decode(input []byte) {
cont := GetRootAsContainer(input, 0)
res:= make(ASlice, cont.TestarrayofmonstersLength())
for i := 1; i < len(res);i++{
m := &Monster{}
cont.Testarrayofmonsters(m, i)
a := A{
Name:string(m.Name()),
Phone:string(m.Phone()),
Money:m.Money(),
BirthDay:time.Unix(int64(m.Birthday())/int64(time.Millisecond), 0),
Siblings:int32(m.Siblings()),
}
if m.Spouse() == 0x1 {
a.Spouse = true
}
res[i]=a
}
}
// automatically generated, do not modify
package encoder
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type Monster struct {
_tab flatbuffers.Table
}
func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *Monster) Name() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *Monster) Phone() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *Monster) Birthday() float64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return rcv._tab.GetFloat64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *Monster) Money() float64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.GetFloat64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *Monster) Siblings() int16 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
if o != 0 {
return rcv._tab.GetInt16(o + rcv._tab.Pos)
}
return 0
}
func (rcv *Monster) Spouse() byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.GetByte(o + rcv._tab.Pos)
}
return 0
}
func (rcv *Monster) Strings(j int) []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
if o != 0 {
a := rcv._tab.Vector(o)
return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j * 4))
}
return nil
}
func (rcv *Monster) StringsLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(7) }
func MonsterAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(name), 0) }
func MonsterAddPhone(builder *flatbuffers.Builder, phone flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(phone), 0) }
func MonsterAddBirthday(builder *flatbuffers.Builder, birthday float64) { builder.PrependFloat64Slot(2, birthday, 0) }
func MonsterAddMoney(builder *flatbuffers.Builder, money float64) { builder.PrependFloat64Slot(3, money, 0) }
func MonsterAddSiblings(builder *flatbuffers.Builder, siblings int16) { builder.PrependInt16Slot(4, siblings, 0) }
func MonsterAddSpouse(builder *flatbuffers.Builder, spouse byte) { builder.PrependByteSlot(5, spouse, 0) }
func MonsterAddStrings(builder *flatbuffers.Builder, strings flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(6, flatbuffers.UOffsetT(strings), 0) }
func MonsterStartStringsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4)
}
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
type ASlice []A
type AStruct struct{
Slice ASlice
}
type A struct {
Name string
BirthDay time.Time
Phone string
Siblings int32
Spouse bool
Money float64
}
func randString(l int) string {
buf := make([]byte, l)
for i := 0; i < (l+1)/2; i++ {
buf[i] = byte(rand.Intn(256))
}
return fmt.Sprintf("%x", buf)[:l]
}
func generate() ASlice {
a := make(ASlice, 0, 1000)
for i := 0; i < 1000; i++ {
a = append(a, A{
Name: randString(16),
BirthDay: time.Now(),
Phone: randString(10),
Siblings: int32(rand.Intn(5)),
Spouse: rand.Intn(2) == 1,
Money: rand.Float64(),
})
}
return a
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment