Merge pull request #137 from CAFxX/opts

Optimize generated encoders
This commit is contained in:
Vasily Romanov
2017-11-20 11:03:33 +03:00
committed by GitHub
+44 -31
View File
@@ -83,7 +83,7 @@ func parseFieldTags(f reflect.StructField) fieldTags {
}
// genTypeEncoder generates code that encodes in of type t into the writer, but uses marshaler interface if implemented by t.
func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, indent int) error {
func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, indent int, assumeNonEmpty bool) error {
ws := strings.Repeat(" ", indent)
marshalerIface := reflect.TypeOf((*easyjson.Marshaler)(nil)).Elem()
@@ -104,12 +104,12 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, in
return nil
}
err := g.genTypeEncoderNoCheck(t, in, tags, indent)
err := g.genTypeEncoderNoCheck(t, in, tags, indent, assumeNonEmpty)
return err
}
// genTypeEncoderNoCheck generates code that encodes in of type t into the writer.
func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldTags, indent int) error {
func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldTags, indent int, assumeNonEmpty bool) error {
ws := strings.Repeat(" ", indent)
// Check whether type is primitive, needs to be done after interface check.
@@ -130,16 +130,20 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
if t.Elem().Kind() == reflect.Uint8 {
fmt.Fprintln(g.out, ws+"out.Base64Bytes("+in+")")
} else {
fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilSliceAsEmpty) == 0 {")
fmt.Fprintln(g.out, ws+` out.RawString("null")`)
fmt.Fprintln(g.out, ws+"} else {")
if !assumeNonEmpty {
fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilSliceAsEmpty) == 0 {")
fmt.Fprintln(g.out, ws+` out.RawString("null")`)
fmt.Fprintln(g.out, ws+"} else {")
} else {
fmt.Fprintln(g.out, ws+"{")
}
fmt.Fprintln(g.out, ws+" out.RawByte('[')")
fmt.Fprintln(g.out, ws+" for "+iVar+", "+vVar+" := range "+in+" {")
fmt.Fprintln(g.out, ws+" if "+iVar+" > 0 {")
fmt.Fprintln(g.out, ws+" out.RawByte(',')")
fmt.Fprintln(g.out, ws+" }")
if err := g.genTypeEncoder(elem, vVar, tags, indent+2); err != nil {
if err := g.genTypeEncoder(elem, vVar, tags, indent+2, false); err != nil {
return err
}
@@ -161,7 +165,7 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
fmt.Fprintln(g.out, ws+" out.RawByte(',')")
fmt.Fprintln(g.out, ws+" }")
if err := g.genTypeEncoder(elem, in+"["+iVar+"]", tags, indent+1); err != nil {
if err := g.genTypeEncoder(elem, in+"["+iVar+"]", tags, indent+1, false); err != nil {
return err
}
@@ -176,15 +180,19 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
fmt.Fprintln(g.out, ws+enc+"(out, "+in+")")
case reflect.Ptr:
fmt.Fprintln(g.out, ws+"if "+in+" == nil {")
fmt.Fprintln(g.out, ws+` out.RawString("null")`)
fmt.Fprintln(g.out, ws+"} else {")
if !assumeNonEmpty {
fmt.Fprintln(g.out, ws+"if "+in+" == nil {")
fmt.Fprintln(g.out, ws+` out.RawString("null")`)
fmt.Fprintln(g.out, ws+"} else {")
}
if err := g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1); err != nil {
if err := g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1, false); err != nil {
return err
}
fmt.Fprintln(g.out, ws+"}")
if !assumeNonEmpty {
fmt.Fprintln(g.out, ws+"}")
}
case reflect.Map:
key := t.Key()
@@ -194,18 +202,21 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
}
tmpVar := g.uniqueVarName()
fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilMapAsEmpty) == 0 {")
fmt.Fprintln(g.out, ws+" out.RawString(`null`)")
fmt.Fprintln(g.out, ws+"} else {")
if !assumeNonEmpty {
fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilMapAsEmpty) == 0 {")
fmt.Fprintln(g.out, ws+" out.RawString(`null`)")
fmt.Fprintln(g.out, ws+"} else {")
} else {
fmt.Fprintln(g.out, ws+"{")
}
fmt.Fprintln(g.out, ws+" out.RawByte('{')")
fmt.Fprintln(g.out, ws+" "+tmpVar+"First := true")
fmt.Fprintln(g.out, ws+" for "+tmpVar+"Name, "+tmpVar+"Value := range "+in+" {")
fmt.Fprintln(g.out, ws+" if !"+tmpVar+"First { out.RawByte(',') }")
fmt.Fprintln(g.out, ws+" "+tmpVar+"First = false")
fmt.Fprintln(g.out, ws+" if "+tmpVar+"First { "+tmpVar+"First = false } else { out.RawByte(',') }")
fmt.Fprintln(g.out, ws+" "+fmt.Sprintf(keyEnc, tmpVar+"Name"))
fmt.Fprintln(g.out, ws+" out.RawByte(':')")
if err := g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2); err != nil {
if err := g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2, false); err != nil {
return err
}
@@ -265,19 +276,21 @@ func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField)
if tags.omit {
return nil
}
if !tags.omitEmpty && !g.omitEmpty || tags.noOmitEmpty {
fmt.Fprintln(g.out, " if !first { out.RawByte(',') }")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
return g.genTypeEncoder(f.Type, "in."+f.Name, tags, 1)
noOmitEmpty := (!tags.omitEmpty && !g.omitEmpty) || tags.noOmitEmpty
if noOmitEmpty {
fmt.Fprintln(g.out, " {")
} else {
fmt.Fprintln(g.out, " if", g.notEmptyCheck(f.Type, "in."+f.Name), "{")
}
fmt.Fprintf(g.out, " const prefix string = %q\n", ","+strconv.Quote(jsonName)+":")
fmt.Fprintln(g.out, " if first {")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintln(g.out, " out.RawString(prefix[1:])")
fmt.Fprintln(g.out, " } else {")
fmt.Fprintln(g.out, " out.RawString(prefix)")
fmt.Fprintln(g.out, " }")
fmt.Fprintln(g.out, " if", g.notEmptyCheck(f.Type, "in."+f.Name), "{")
fmt.Fprintln(g.out, " if !first { out.RawByte(',') }")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
if err := g.genTypeEncoder(f.Type, "in."+f.Name, tags, 2); err != nil {
if err := g.genTypeEncoder(f.Type, "in."+f.Name, tags, 2, !noOmitEmpty); err != nil {
return err
}
fmt.Fprintln(g.out, " }")
@@ -304,7 +317,7 @@ func (g *Generator) genSliceArrayMapEncoder(t reflect.Type) error {
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(out *jwriter.Writer, in "+typ+") {")
err := g.genTypeEncoderNoCheck(t, "in", fieldTags{}, 1)
err := g.genTypeEncoderNoCheck(t, "in", fieldTags{}, 1, false)
if err != nil {
return err
}