Reduce allocations when building strings. Builder has a new CreateByteString function that writes a null-terimnated byte slice to the buffer. This results in zero allocations for writing strings.
diff --git a/go/builder.go b/go/builder.go index e1b1f43..cdae695 100644 --- a/go/builder.go +++ b/go/builder.go
@@ -247,16 +247,20 @@ // CreateString writes a null-terminated string as a vector. func (b *Builder) CreateString(s string) UOffsetT { + return b.CreateByteString([]byte(s)) +} + +// CreateByteString writes a null-terminated byteslice as a vector. +func (b *Builder) CreateByteString(s []byte) UOffsetT { b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte) b.PlaceByte(0) - x := []byte(s) - l := UOffsetT(len(x)) + l := UOffsetT(len(s)) b.head -= l - copy(b.Bytes[b.head:b.head+l], x) + copy(b.Bytes[b.head:b.head+l], s) - return b.EndVector(len(x)) + return b.EndVector(len(s)) } // CreateByteVector writes a ubyte vector
diff --git a/tests/GoTest.sh b/tests/GoTest.sh index 877a3ca..2011434 100755 --- a/tests/GoTest.sh +++ b/tests/GoTest.sh
@@ -43,8 +43,8 @@ --test.coverpkg=github.com/google/flatbuffers/go \ --cpp_data=${test_dir}/monsterdata_test.mon \ --out_data=${test_dir}/monsterdata_go_wire.mon \ - --test.bench=. \ - --test.benchtime=5s \ + --test.bench=Build \ + --test.benchtime=3s \ --fuzz=true \ --fuzz_fields=4 \ --fuzz_objects=10000
diff --git a/tests/go_test.go b/tests/go_test.go index c1ca165..87a81c3 100644 --- a/tests/go_test.go +++ b/tests/go_test.go
@@ -518,6 +518,15 @@ check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad 3, 0, 0, 0, 'f', 'o', 'o', 0}) + // test 6b: CreateByteString + + b = flatbuffers.NewBuilder(0) + b.CreateByteString([]byte("foo")) + check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad + b.CreateByteString([]byte("moop")) + check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad + 3, 0, 0, 0, 'f', 'o', 'o', 0}) + // test 7: empty vtable b = flatbuffers.NewBuilder(0) b.StartObject(0) @@ -1239,19 +1248,19 @@ buf, offset := CheckGeneratedBuild(b.Fatalf) bytes_length := int64(len(buf[offset:])) - reuse_str := "MyMonster" - reuse_test1 := "test1" - reuse_test2 := "test2" - reuse_fred := "Fred" + reuse_str := []byte("MyMonster") + reuse_test1 := []byte("test1") + reuse_test2 := []byte("test2") + reuse_fred := []byte("Fred") b.SetBytes(bytes_length) b.ReportAllocs() for i := 0; i < b.N; i++ { bldr := flatbuffers.NewBuilder(0) - str := bldr.CreateString(reuse_str) - test1 := bldr.CreateString(reuse_test1) - test2 := bldr.CreateString(reuse_test2) - fred := bldr.CreateString(reuse_fred) + str := bldr.CreateByteString(reuse_str) + test1 := bldr.CreateByteString(reuse_test1) + test2 := bldr.CreateByteString(reuse_test2) + fred := bldr.CreateByteString(reuse_fred) example.MonsterStartInventoryVector(bldr, 5) bldr.PrependByte(4)