aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json
diff options
context:
space:
mode:
authorMichael Schurter <michael.schurter@gmail.com>2017-06-03 13:36:54 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2017-11-22 03:36:29 +0000
commit7eb7f8f5a75fcff520b5b93a7831fa7044d86887 (patch)
tree00ea6c56bd13dc3983ad52658eb42afc72a82935 /src/encoding/json
parent71aee2a190e6a26858b16a0974afdf976f2b0905 (diff)
downloadgo-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/json')
-rw-r--r--src/encoding/json/bench_test.go15
-rw-r--r--src/encoding/json/decode.go18
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.