Optimize encoder

https://github.com/mailru/easyjson/issues/136
This commit is contained in:
Carlo Alberto Ferraris
2017-08-22 10:50:10 +09:00
parent 2f5df55504
commit 2a4ed8adb0
+45 -29
View File
@@ -81,7 +81,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()
@@ -102,12 +102,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.
@@ -128,16 +128,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+" }")
g.genTypeEncoder(elem, vVar, tags, indent+2)
g.genTypeEncoder(elem, vVar, tags, indent+2, false)
fmt.Fprintln(g.out, ws+" }")
fmt.Fprintln(g.out, ws+" out.RawByte(']')")
@@ -157,7 +161,7 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
fmt.Fprintln(g.out, ws+" out.RawByte(',')")
fmt.Fprintln(g.out, ws+" }")
g.genTypeEncoder(elem, in+"["+iVar+"]", tags, indent+1)
g.genTypeEncoder(elem, in+"["+iVar+"]", tags, indent+1, false)
fmt.Fprintln(g.out, ws+"}")
fmt.Fprintln(g.out, ws+"out.RawByte(']')")
@@ -170,13 +174,17 @@ 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 {")
}
g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1)
g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1, false)
fmt.Fprintln(g.out, ws+"}")
if !assumeNonEmpty {
fmt.Fprintln(g.out, ws+"}")
}
case reflect.Map:
key := t.Key()
@@ -185,18 +193,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+" out.String(string("+tmpVar+"Name))")
fmt.Fprintln(g.out, ws+" out.RawByte(':')")
g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2)
g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2, false)
fmt.Fprintln(g.out, ws+" }")
fmt.Fprintln(g.out, ws+" out.RawByte('}')")
@@ -255,18 +266,23 @@ func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField)
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)
fmt.Fprintln(g.out, " if first {")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
fmt.Fprintln(g.out, " } else {")
fmt.Fprintf(g.out, " out.RawString(%q)\n", ","+strconv.Quote(jsonName)+":")
fmt.Fprintln(g.out, " }")
return g.genTypeEncoder(f.Type, "in."+f.Name, tags, 1, false)
}
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 {
fmt.Fprintln(g.out, " if first {")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
fmt.Fprintln(g.out, " } else {")
fmt.Fprintf(g.out, " out.RawString(%q)\n", ","+strconv.Quote(jsonName)+":")
fmt.Fprintln(g.out, " }")
if err := g.genTypeEncoder(f.Type, "in."+f.Name, tags, 2, true); err != nil {
return err
}
fmt.Fprintln(g.out, " }")
@@ -293,7 +309,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
}