diff options
| author | Michael Schurter <michael.schurter@gmail.com> | 2017-06-03 13:36:54 -0700 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2017-11-22 03:36:29 +0000 |
| commit | 7eb7f8f5a75fcff520b5b93a7831fa7044d86887 (patch) | |
| tree | 00ea6c56bd13dc3983ad52658eb42afc72a82935 /src/encoding | |
| parent | 71aee2a190e6a26858b16a0974afdf976f2b0905 (diff) | |
| download | go-7eb7f8f5a75fcff520b5b93a7831fa7044d86887.tar.xz | |
encoding/json: reduce allocations by Decoder for \uXXXX
Manually convert hex escape sequence to rune instead of calling
strconv.ParseUint.
This inlines the unhex func from docs (and many other packages).
name old time/op new time/op delta
UnicodeDecoder-4 468ns ± 1% 402ns ± 1% -14.26% (p=0.000
n=10+10)
name old speed new speed delta
UnicodeDecoder-4 29.9MB/s ± 1% 34.8MB/s ± 1% +16.59% (p=0.000
n=10+10)
name old alloc/op new alloc/op delta
UnicodeDecoder-4 44.0B ± 0% 36.0B ± 0% -18.18% (p=0.000
n=10+10)
name old allocs/op new allocs/op delta
UnicodeDecoder-4 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.000
n=10+10)
Fixes #20567
Change-Id: If350978d5bb98ff517485752184d02249f5d1f3a
Reviewed-on: https://go-review.googlesource.com/44738
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/encoding')
| -rw-r--r-- | src/encoding/json/bench_test.go | 15 | ||||
| -rw-r--r-- | src/encoding/json/decode.go | 18 |
2 files changed, 29 insertions, 4 deletions
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go index 85d7ae043b..42439eb705 100644 --- a/src/encoding/json/bench_test.go +++ b/src/encoding/json/bench_test.go @@ -133,6 +133,21 @@ func BenchmarkCodeDecoder(b *testing.B) { b.SetBytes(int64(len(codeJSON))) } +func BenchmarkUnicodeDecoder(b *testing.B) { + j := []byte(`"\uD83D\uDE01"`) + b.SetBytes(int64(len(j))) + r := bytes.NewReader(j) + dec := NewDecoder(r) + var out string + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := dec.Decode(&out); err != nil { + b.Fatal("Decode:", err) + } + r.Seek(0, 0) + } +} + func BenchmarkDecoderStream(b *testing.B) { b.StopTimer() var buf bytes.Buffer diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 70179e60ac..4f98916105 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -1148,11 +1148,21 @@ func getu4(s []byte) rune { if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { return -1 } - r, err := strconv.ParseUint(string(s[2:6]), 16, 64) - if err != nil { - return -1 + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) } - return rune(r) + return r } // unquote converts a quoted JSON string literal s into an actual string t. |
