Jelajahi Sumber

Export changes from Google-internal version:
- faster text parsing
- use numbers instead of repeated Xs for package import name conflict resolution

R=r
CC=golang-dev
http://codereview.appspot.com/2540041

David Symonds 15 tahun lalu
induk
melakukan
79eae3323b
4 mengubah file dengan 45 tambahan dan 17 penghapusan
  1. 3 2
      compiler/generator/generator.go
  2. 7 4
      proto/properties.go
  3. 11 11
      proto/text_parser.go
  4. 24 0
      proto/text_parser_test.go

+ 3 - 2
compiler/generator/generator.go

@@ -42,6 +42,7 @@ import (
 	"log"
 	"os"
 	"path"
+	"strconv"
 	"strings"
 
 	"goprotobuf.googlecode.com/hg/proto"
@@ -332,9 +333,9 @@ var pkgNamesInUse = make(map[string]bool)
 // Pkg is the candidate name.  If f is nil, it's a builtin package like "proto" and
 // has no file descriptor.
 func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
-	for pkgNamesInUse[pkg] {
+	for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ {
 		// It's a duplicate; must rename.
-		pkg += "X"
+		pkg = orig + strconv.Itoa(i)
 	}
 	// Install it.
 	pkgNamesInUse[pkg] = true

+ 7 - 4
proto/properties.go

@@ -78,10 +78,11 @@ type valueDecoder func(o *Buffer) (x uint64, err os.Error)
 
 // StructProperties represents properties for all the fields of a struct.
 type StructProperties struct {
-	Prop     []*Properties // properties for each field
-	reqCount int           // required count
-	tags     map[int]int   // map from proto tag to struct field number
-	nscratch uintptr       // size of scratch space
+	Prop      []*Properties  // properties for each field
+	reqCount  int            // required count
+	tags      map[int]int    // map from proto tag to struct field number
+	origNames map[string]int // map from original name to struct field number
+	nscratch  uintptr        // size of scratch space
 }
 
 // Properties represents the protocol-specific behavior of a single struct field.
@@ -411,6 +412,7 @@ func GetProperties(t *reflect.StructType) *StructProperties {
 
 	// build properties
 	prop.Prop = make([]*Properties, t.NumField())
+	prop.origNames = make(map[string]int)
 	for i := 0; i < t.NumField(); i++ {
 		f := t.Field(i)
 		p := new(Properties)
@@ -423,6 +425,7 @@ func GetProperties(t *reflect.StructType) *StructProperties {
 			p.sizeof = unsafe.Sizeof(vmap)
 		}
 		prop.Prop[i] = p
+		prop.origNames[p.OrigName] = i
 		if debug {
 			print(i, " ", f.Name, " ", t.String(), " ")
 			if p.Tag > 0 {

+ 11 - 11
proto/text_parser.go

@@ -254,11 +254,9 @@ func (p *textParser) missingRequiredFieldError(sv *reflect.StructValue) *ParseEr
 // Returns the index in the struct for the named field, as well as the parsed tag properties.
 func structFieldByName(st *reflect.StructType, name string) (int, *Properties, bool) {
 	sprops := GetProperties(st)
-	for i := 0; i < st.NumField(); i++ {
-		props := sprops.Prop[i]
-		if props.OrigName == name {
-			return i, props, true
-		}
+	i, ok := sprops.origNames[name]
+	if ok {
+		return i, sprops.Prop[i], true
 	}
 	return -1, nil, false
 }
@@ -370,15 +368,17 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
 			return nil
 		}
 		// Repeated field. May already exist.
-		cnt := fv.Len()
-		nav := reflect.MakeSlice(at, cnt, cnt+1)
-		reflect.ArrayCopy(nav, fv)
-		fv.Set(nav)
-		fv.SetLen(cnt + 1)
+		flen := fv.Len()
+		if flen == fv.Cap() {
+			nav := reflect.MakeSlice(at, flen, 2*flen+1)
+			reflect.ArrayCopy(nav, fv)
+			fv.Set(nav)
+		}
+		fv.SetLen(flen + 1)
 
 		// Read one.
 		p.back()
-		return p.readAny(fv.Elem(cnt), nil) // TODO: pass properties?
+		return p.readAny(fv.Elem(flen), nil) // TODO: pass properties?
 	case *reflect.BoolValue:
 		// Either "true", "false", 1 or 0.
 		switch tok.value {

+ 24 - 0
proto/text_parser_test.go

@@ -256,3 +256,27 @@ func TestUnmarshalText(t *testing.T) {
 		}
 	}
 }
+
+var benchInput string
+
+func init() {
+	benchInput = "count: 4\n"
+	for i := 0; i < 1000; i++ {
+		benchInput += "pet: \"fido\"\n"
+	}
+
+	// Check it is valid input.
+	pb := new(MyMessage)
+	err := UnmarshalText(benchInput, pb)
+	if err != nil {
+		panic("Bad benchmark input: " + err.String())
+	}
+}
+
+func BenchmarkUnmarshalText(b *testing.B) {
+	pb := new(MyMessage)
+	for i := 0; i < b.N; i++ {
+		UnmarshalText(benchInput, pb)
+	}
+	b.SetBytes(int64(len(benchInput)))
+}