]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: reduce allocations by Decoder for \uXXXX
authorMichael Schurter <michael.schurter@gmail.com>
Sat, 3 Jun 2017 20:36:54 +0000 (13:36 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 22 Nov 2017 03:36:29 +0000 (03:36 +0000)
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>

src/encoding/json/bench_test.go
src/encoding/json/decode.go

index 85d7ae043b8caa77ca263e37ac11bd91c6b7fff2..42439eb7054e9498df916d8d692032f737e85621 100644 (file)
@@ -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
index 70179e60ac3dd56357d2433c85db43cd8ae44b60..4f98916105b9d9470365e65f8f6ea140f684ca2a 100644 (file)
@@ -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.