Просмотр исходного кода

Fix Size for maps.

This was terribly broken, but we got lucky for small map entries.
The old code was trying to compute the size of the tag codes for
the key and value, but that's the responsibility of the sizer for
the particular key and value. What size_new_map needs to account for
is the length of the tag code and length varint of the map entry itself.

Fixes #21.
David Symonds 11 лет назад
Родитель
Сommit
a8323e2cd7
4 измененных файлов с 20 добавлено и 4 удалено
  1. 6 4
      proto/encode.go
  2. 5 0
      proto/size_test.go
  3. 8 0
      proto/testdata/test.pb.go
  4. 1 0
      proto/testdata/test.proto

+ 6 - 4
proto/encode.go

@@ -1128,10 +1128,12 @@ func size_new_map(p *Properties, base structPointer) int {
 		keycopy.Set(key)
 		valcopy.Set(val)
 
-		// Tag codes are two bytes per map entry.
-		n += 2
-		n += p.mkeyprop.size(p.mkeyprop, keybase)
-		n += p.mvalprop.size(p.mvalprop, valbase)
+		// Tag codes for key and val are the responsibility of the sub-sizer.
+		keysize := p.mkeyprop.size(p.mkeyprop, keybase)
+		valsize := p.mvalprop.size(p.mvalprop, valbase)
+		entry := keysize + valsize
+		// Add on tag code and length of map entry itself.
+		n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry
 	}
 	return n
 }

+ 5 - 0
proto/size_test.go

@@ -33,6 +33,7 @@ package proto_test
 
 import (
 	"log"
+	"strings"
 	"testing"
 
 	. "github.com/golang/protobuf/proto"
@@ -119,6 +120,10 @@ var SizeTests = []struct {
 	{"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}},
 	{"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}},
 	{"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte{}}}},
+
+	{"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}},
+	{"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}},
+	{"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}},
 }
 
 func TestSize(t *testing.T) {

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

@@ -1890,6 +1890,7 @@ type MessageWithMap struct {
 	NameMapping      map[int32]string         `protobuf:"bytes,1,rep,name=name_mapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	MsgMapping       map[int64]*FloatingPoint `protobuf:"bytes,2,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	ByteMapping      map[bool][]byte          `protobuf:"bytes,3,rep,name=byte_mapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	StrToStr         map[string]string        `protobuf:"bytes,4,rep,name=str_to_str" json:"str_to_str,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	XXX_unrecognized []byte                   `json:"-"`
 }
 
@@ -1918,6 +1919,13 @@ func (m *MessageWithMap) GetByteMapping() map[bool][]byte {
 	return nil
 }
 
+func (m *MessageWithMap) GetStrToStr() map[string]string {
+	if m != nil {
+		return m.StrToStr
+	}
+	return nil
+}
+
 var E_Greeting = &proto.ExtensionDesc{
 	ExtendedType:  (*MyMessage)(nil),
 	ExtensionType: ([]string)(nil),

+ 1 - 0
proto/testdata/test.proto

@@ -431,4 +431,5 @@ message MessageWithMap {
   map<int32, string> name_mapping = 1;
   map<sint64, FloatingPoint> msg_mapping = 2;
   map<bool, bytes> byte_mapping = 3;
+  map<string, string> str_to_str = 4;
 }