فهرست منبع

goprotobuf: Fix Size accounting of packed fields.

Fixes #40.

R=crawshaw
CC=golang-dev
https://codereview.appspot.com/10477043
David Symonds 12 سال پیش
والد
کامیت
9c8d84777b
4فایلهای تغییر یافته به همراه28 افزوده شده و 12 حذف شده
  1. 13 12
      proto/size.go
  2. 6 0
      proto/size_test.go
  3. 8 0
      proto/testdata/test.pb.go
  4. 1 0
      proto/testdata/test.proto

+ 13 - 12
proto/size.go

@@ -108,26 +108,27 @@ func sizeField(x reflect.Value, prop *Properties) (n int) {
 			return len(prop.tagcode) + sizeVarint(uint64(n)) + n
 		}
 
-		// Non-packed repeated fields have a per-element header of the tagcode.
-		// Packed repeated fields only have a single header: the tag code plus a varint of the number of bytes.
 		var nb int
-		if !prop.Packed {
-			nb = len(prop.tagcode) * n
-		} else {
-			nb = len(prop.tagcode) + sizeVarint(uint64(n))
-		}
 
 		// []bool and repeated fixed integer types are easy.
 		switch {
 		case et.Kind() == reflect.Bool:
-			return nb + n
+			nb += n
 		case prop.WireType == WireFixed64:
-			return nb + n*8
+			nb += n * 8
 		case prop.WireType == WireFixed32:
-			return nb + n*4
+			nb += n * 4
+		default:
+			for i := 0; i < n; i++ {
+				nb += sizeField(x.Index(i), prop)
+			}
 		}
-		for i := 0; i < n; i++ {
-			nb += sizeField(x.Index(i), prop)
+		// Non-packed repeated fields have a per-element header of the tagcode.
+		// Packed repeated fields only have a single header: the tag code plus a varint of the number of bytes.
+		if !prop.Packed {
+			nb += len(prop.tagcode) * n
+		} else {
+			nb += len(prop.tagcode) + sizeVarint(uint64(nb))
 		}
 		return nb
 	}

+ 6 - 0
proto/size_test.go

@@ -85,6 +85,12 @@ var SizeTests = []struct {
 	{"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}},
 	{"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729}}},
 	{"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}},
+	{"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{
+		// Need enough large numbers to verify that the header is counting the number of bytes
+		// for the field, not the number of elements.
+		1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
+		1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
+	}}},
 	{"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}},
 	{"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}},
 	// Nested.

+ 8 - 0
proto/testdata/test.pb.go

@@ -1657,6 +1657,7 @@ type MoreRepeated struct {
 	BoolsPacked      []bool   `protobuf:"varint,2,rep,packed,name=bools_packed" json:"bools_packed,omitempty"`
 	Ints             []int32  `protobuf:"varint,3,rep,name=ints" json:"ints,omitempty"`
 	IntsPacked       []int32  `protobuf:"varint,4,rep,packed,name=ints_packed" json:"ints_packed,omitempty"`
+	Int64SPacked     []int64  `protobuf:"varint,7,rep,packed,name=int64s_packed" json:"int64s_packed,omitempty"`
 	Strings          []string `protobuf:"bytes,5,rep,name=strings" json:"strings,omitempty"`
 	Fixeds           []uint32 `protobuf:"fixed32,6,rep,name=fixeds" json:"fixeds,omitempty"`
 	XXX_unrecognized []byte   `json:"-"`
@@ -1694,6 +1695,13 @@ func (m *MoreRepeated) GetIntsPacked() []int32 {
 	return nil
 }
 
+func (m *MoreRepeated) GetInt64SPacked() []int64 {
+	if m != nil {
+		return m.Int64SPacked
+	}
+	return nil
+}
+
 func (m *MoreRepeated) GetStrings() []string {
 	if m != nil {
 		return m.Strings

+ 1 - 0
proto/testdata/test.proto

@@ -393,6 +393,7 @@ message MoreRepeated {
   repeated bool bools_packed = 2 [packed=true];
   repeated int32 ints = 3;
   repeated int32 ints_packed = 4 [packed=true];
+  repeated int64 int64s_packed = 7 [packed=true];
   repeated string strings = 5;
   repeated fixed32 fixeds = 6;
 }