From 0e811c236176febacff78541718c7844f7ff5e06 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 6 Sep 2023 10:04:59 -0700 Subject: [PATCH] Optimize Marshal for string values (#311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Performance: name old time/op new time/op delta Testdata/CanadaGeometry/Marshal/Concrete 1.38ms ± 1% 1.39ms ± 1% ~ (p=0.052 n=10+10) Testdata/CitmCatalog/Marshal/Concrete 1.45ms ± 0% 1.46ms ± 1% +0.82% (p=0.013 n=9+10) Testdata/GolangSource/Marshal/Concrete 5.61ms ± 3% 5.48ms ± 1% -2.38% (p=0.001 n=10+10) Testdata/StringEscaped/Marshal/Concrete 31.1µs ± 5% 26.8µs ± 1% -13.84% (p=0.000 n=10+10) Testdata/StringUnicode/Marshal/Concrete 30.9µs ± 3% 26.7µs ± 0% -13.62% (p=0.000 n=10+10) Testdata/SyntheaFhir/Marshal/Concrete 8.77ms ± 1% 8.50ms ± 3% -3.11% (p=0.000 n=10+10) Testdata/TwitterStatus/Marshal/Concrete 965µs ± 4% 926µs ± 2% -4.01% (p=0.002 n=10+10) --- arshal_default.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arshal_default.go b/arshal_default.go index ba7790b..502e073 100644 --- a/arshal_default.go +++ b/arshal_default.go @@ -167,7 +167,24 @@ func makeStringArshaler(t reflect.Type) *arshaler { if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { return newInvalidFormatError("marshal", t, mo.Format) } - return enc.WriteToken(jsontext.String(va.String())) + + // Optimize for marshaling without preceding whitespace or string escaping. + s := va.String() + if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() && !jsonwire.NeedEscape(s, xe.EscapeRunes) { + b := xe.Buf + b = xe.Tokens.MayAppendDelim(b, '"') + b = append(b, '"') + b = append(b, s...) + b = append(b, '"') + xe.Buf = b + xe.Tokens.Last.Increment() + if xe.NeedFlush() { + return xe.Flush() + } + return nil + } + + return enc.WriteToken(jsontext.String(s)) } fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec)