Add new -disable_members_unescape option to avoid unescaping of member names, ints, ...

Improves performance for about 15% on BenchmarkEJ_Unmarshal_M-8
This commit is contained in:
Kirill Korotaev
2020-04-11 19:11:39 +03:00
parent 3a0ce97e28
commit 9a01c9afdb
6 changed files with 49 additions and 31 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ generate: build
bin/easyjson -all ./tests/html.go
bin/easyjson -snake_case ./tests/snake.go
bin/easyjson -omit_empty ./tests/omitempty.go
bin/easyjson -build_tags=use_easyjson ./benchmark/data.go
bin/easyjson -build_tags=use_easyjson -disable_members_unescape ./benchmark/data.go
bin/easyjson ./tests/nested_easy.go
bin/easyjson ./tests/named_type.go
bin/easyjson ./tests/custom_map_key_type.go
+12 -8
View File
@@ -23,18 +23,19 @@ type Generator struct {
PkgPath, PkgName string
Types []string
NoStdMarshalers bool
SnakeCase bool
LowerCamelCase bool
OmitEmpty bool
DisallowUnknownFields bool
NoStdMarshalers bool
SnakeCase bool
LowerCamelCase bool
OmitEmpty bool
DisallowUnknownFields bool
SkipMemberNameUnescaping bool
OutName string
BuildTags string
StubsOnly bool
LeaveTemps bool
NoFormat bool
StubsOnly bool
LeaveTemps bool
NoFormat bool
SimpleBytes bool
}
@@ -129,6 +130,9 @@ func (g *Generator) writeMain() (path string, err error) {
if g.SimpleBytes {
fmt.Fprintln(f, " g.SimpleBytes()")
}
if g.SkipMemberNameUnescaping {
fmt.Fprintln(f, " g.SkipMemberNameUnescaping()")
}
sort.Strings(g.Types)
for _, v := range g.Types {
+16 -14
View File
@@ -29,6 +29,7 @@ var noformat = flag.Bool("noformat", false, "do not run 'gofmt -w' on output fil
var specifiedName = flag.String("output_filename", "", "specify the filename of the output")
var processPkg = flag.Bool("pkg", false, "process the whole package instead of just the given file")
var disallowUnknownFields = flag.Bool("disallow_unknown_fields", false, "return error if any unknown field in json appeared")
var skipMemberNameUnescaping = flag.Bool("disable_members_unescape", false, "don't perform unescaping of member names to improve performance")
func generate(fname string) (err error) {
fInfo, err := os.Stat(fname)
@@ -62,20 +63,21 @@ func generate(fname string) (err error) {
}
g := bootstrap.Generator{
BuildTags: trimmedBuildTags,
PkgPath: p.PkgPath,
PkgName: p.PkgName,
Types: p.StructNames,
SnakeCase: *snakeCase,
LowerCamelCase: *lowerCamelCase,
NoStdMarshalers: *noStdMarshalers,
DisallowUnknownFields: *disallowUnknownFields,
OmitEmpty: *omitEmpty,
LeaveTemps: *leaveTemps,
OutName: outName,
StubsOnly: *stubs,
NoFormat: *noformat,
SimpleBytes: *simpleBytes,
BuildTags: trimmedBuildTags,
PkgPath: p.PkgPath,
PkgName: p.PkgName,
Types: p.StructNames,
SnakeCase: *snakeCase,
LowerCamelCase: *lowerCamelCase,
NoStdMarshalers: *noStdMarshalers,
DisallowUnknownFields: *disallowUnknownFields,
SkipMemberNameUnescaping: *skipMemberNameUnescaping,
OmitEmpty: *omitEmpty,
LeaveTemps: *leaveTemps,
OutName: outName,
StubsOnly: *stubs,
NoFormat: *noformat,
SimpleBytes: *simpleBytes,
}
if err := g.Run(); err != nil {
+3
View File
@@ -457,6 +457,9 @@ func (g *Generator) genStructDecoder(t reflect.Type) error {
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(in *jlexer.Lexer, out *"+typ+") {")
if g.skipMemberNameUnescaping {
fmt.Fprintln(g.out, " in.SkipUnescape = true")
}
fmt.Fprintln(g.out, " isTopLevel := in.IsStart()")
fmt.Fprintln(g.out, " if in.IsNull() {")
fmt.Fprintln(g.out, " if isTopLevel {")
+11 -5
View File
@@ -33,11 +33,12 @@ type Generator struct {
varCounter int
noStdMarshalers bool
omitEmpty bool
disallowUnknownFields bool
fieldNamer FieldNamer
simpleBytes bool
noStdMarshalers bool
omitEmpty bool
disallowUnknownFields bool
fieldNamer FieldNamer
simpleBytes bool
skipMemberNameUnescaping bool
// package path to local alias map for tracking imports
imports map[string]string
@@ -117,6 +118,11 @@ func (g *Generator) DisallowUnknownFields() {
g.disallowUnknownFields = true
}
// SkipMemberNameUnescaping instructs to skip member names unescaping to improve performance
func (g *Generator) SkipMemberNameUnescaping() {
g.skipMemberNameUnescaping = true
}
// OmitEmpty triggers `json=",omitempty"` behaviour by default.
func (g *Generator) OmitEmpty() {
g.omitEmpty = true
+6 -3
View File
@@ -49,6 +49,7 @@ type Lexer struct {
firstElement bool // Whether current element is the first in array or an object.
wantSep byte // A comma or a colon character, which need to occur before a token.
SkipUnescape bool // Skip unescaping on all but user returned strings (i.e. member names, numbers, bytes etc.)
UseMultipleErrors bool // If we want to use multiple errors.
fatalError error // Fatal error occurred during lexing. It is usually a syntax error.
@@ -606,9 +607,11 @@ func (r *Lexer) unsafeString() (string, []byte) {
r.errInvalidToken("string")
return "", nil
}
if err := r.unescapeStringToken(); err != nil {
r.errInvalidToken("string")
return "", nil
if !r.SkipUnescape {
if err := r.unescapeStringToken(); err != nil {
r.errInvalidToken("string")
return "", nil
}
}
bytes := r.token.byteValue