Generate sizer functions for oneofs.
This improves oneof sizing performance by ~9x.
func BenchmarkSizeTrivial(b *testing.B) {
benchmarkSize(b, &MyMessage{Count: Int32(0)})
}
func BenchmarkSizeOneof(b *testing.B) {
benchmarkSize(b, &Communique{Union: &Communique_Number{0}})
}
Without this change:
BenchmarkSizeTrivial-12 5000000 355 ns/op
BenchmarkSizeOneof-12 500000 2754 ns/op
With this change:
BenchmarkSizeTrivial-12 5000000 336 ns/op
BenchmarkSizeOneof-12 5000000 306 ns/op
Signed-off-by: David Symonds <dsymonds@golang.org>
diff --git a/proto/encode.go b/proto/encode.go
index 7321e1a..231b074 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -105,6 +105,11 @@
return nil
}
+// SizeVarint returns the varint encoding size of an integer.
+func SizeVarint(x uint64) int {
+ return sizeVarint(x)
+}
+
func sizeVarint(x uint64) (n int) {
for {
n++
@@ -1248,24 +1253,9 @@
}
// Factor in any oneof fields.
- // TODO: This could be faster and use less reflection.
- if prop.oneofMarshaler != nil {
- sv := reflect.ValueOf(structPointer_Interface(base, prop.stype)).Elem()
- for i := 0; i < prop.stype.NumField(); i++ {
- fv := sv.Field(i)
- if fv.Kind() != reflect.Interface || fv.IsNil() {
- continue
- }
- if prop.stype.Field(i).Tag.Get("protobuf_oneof") == "" {
- continue
- }
- spv := fv.Elem() // interface -> *T
- sv := spv.Elem() // *T -> T
- sf := sv.Type().Field(0) // StructField inside T
- var prop Properties
- prop.Init(sf.Type, "whatever", sf.Tag.Get("protobuf"), &sf)
- n += prop.size(&prop, toStructPointer(spv))
- }
+ if prop.oneofSizer != nil {
+ m := structPointer_Interface(base, prop.stype).(Message)
+ n += prop.oneofSizer(m)
}
return