aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding/json')
-rw-r--r--src/encoding/json/decode.go23
-rw-r--r--src/encoding/json/encode.go27
2 files changed, 31 insertions, 19 deletions
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 3c40eb9cef..3ca3d7803e 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -8,7 +8,6 @@
package json
import (
- "bytes"
"encoding"
"encoding/base64"
"fmt"
@@ -691,7 +690,7 @@ func (d *decodeState) object(v reflect.Value) error {
return nil
}
- var fields []field
+ var fields structFields
// Check type of target:
// struct or
@@ -761,14 +760,18 @@ func (d *decodeState) object(v reflect.Value) error {
subv = mapElem
} else {
var f *field
- for i := range fields {
- ff := &fields[i]
- if bytes.Equal(ff.nameBytes, key) {
- f = ff
- break
- }
- if f == nil && ff.equalFold(ff.nameBytes, key) {
- f = ff
+ if i, ok := fields.nameIndex[string(key)]; ok {
+ // Found an exact name match.
+ f = &fields.list[i]
+ } else {
+ // Fall back to the expensive case-insensitive
+ // linear search.
+ for i := range fields.list {
+ ff := &fields.list[i]
+ if ff.equalFold(ff.nameBytes, key) {
+ f = ff
+ break
+ }
}
}
if f != nil {
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index e3c5ffc9cb..197c0cba03 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -621,14 +621,19 @@ func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {
}
type structEncoder struct {
- fields []field
+ fields structFields
+}
+
+type structFields struct {
+ list []field
+ nameIndex map[string]int
}
func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
next := byte('{')
FieldLoop:
- for i := range se.fields {
- f := &se.fields[i]
+ for i := range se.fields.list {
+ f := &se.fields.list[i]
// Find the nested struct field by following f.index.
fv := v
@@ -1063,7 +1068,7 @@ func (x byIndex) Less(i, j int) bool {
// typeFields returns a list of fields that JSON should recognize for the given type.
// The algorithm is breadth-first search over the set of structs to include - the top struct
// and then any reachable anonymous structs.
-func typeFields(t reflect.Type) []field {
+func typeFields(t reflect.Type) structFields {
// Anonymous fields to explore at the current level and the next.
current := []field{}
next := []field{{typ: t}}
@@ -1237,7 +1242,11 @@ func typeFields(t reflect.Type) []field {
f := &fields[i]
f.encoder = typeEncoder(typeByIndex(t, f.index))
}
- return fields
+ nameIndex := make(map[string]int, len(fields))
+ for i, field := range fields {
+ nameIndex[field.name] = i
+ }
+ return structFields{fields, nameIndex}
}
// dominantField looks through the fields, all of which are known to
@@ -1256,13 +1265,13 @@ func dominantField(fields []field) (field, bool) {
return fields[0], true
}
-var fieldCache sync.Map // map[reflect.Type][]field
+var fieldCache sync.Map // map[reflect.Type]structFields
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
-func cachedTypeFields(t reflect.Type) []field {
+func cachedTypeFields(t reflect.Type) structFields {
if f, ok := fieldCache.Load(t); ok {
- return f.([]field)
+ return f.(structFields)
}
f, _ := fieldCache.LoadOrStore(t, typeFields(t))
- return f.([]field)
+ return f.(structFields)
}