Specialize navigating map[string]interface{}
This is a common type. Specializing it to reduce the use of reflection yields better performance. Similar to https://github.com/pelletier/go-toml/pull/669, there is a lot to explore there. name old time/op new time/op delta UnmarshalDataset/config-8 13.3ms ± 0% 12.3ms ± 0% -7.45% (p=0.008 n=5+5) UnmarshalDataset/canada-8 55.7ms ± 0% 55.2ms ± 0% -0.88% (p=0.008 n=5+5) UnmarshalDataset/citm_catalog-8 16.6ms ± 1% 16.5ms ± 1% -0.97% (p=0.008 n=5+5) UnmarshalDataset/twitter-8 7.10ms ± 1% 7.01ms ± 1% -1.28% (p=0.016 n=5+5) UnmarshalDataset/code-8 63.8ms ± 0% 52.0ms ± 0% -18.45% (p=0.008 n=5+5) UnmarshalDataset/example-8 121µs ± 0% 119µs ± 0% -2.13% (p=0.008 n=5+5) Unmarshal/SimpleDocument/struct-8 438ns ± 1% 432ns ± 1% -1.40% (p=0.008 n=5+5) Unmarshal/SimpleDocument/map-8 594ns ± 2% 573ns ± 1% -3.56% (p=0.008 n=5+5) Unmarshal/ReferenceFile/struct-8 34.3µs ± 1% 33.7µs ± 0% -1.95% (p=0.008 n=5+5) Unmarshal/ReferenceFile/map-8 48.6µs ± 0% 44.2µs ± 1% -9.22% (p=0.008 n=5+5) Unmarshal/HugoFrontMatter-8 7.88µs ± 1% 7.28µs ± 1% -7.66% (p=0.008 n=5+5) name old speed new speed delta UnmarshalDataset/config-8 78.9MB/s ± 0% 85.2MB/s ± 0% +8.05% (p=0.008 n=5+5) UnmarshalDataset/canada-8 39.5MB/s ± 0% 39.9MB/s ± 0% +0.89% (p=0.008 n=5+5) UnmarshalDataset/citm_catalog-8 33.6MB/s ± 1% 33.9MB/s ± 1% +0.98% (p=0.008 n=5+5) UnmarshalDataset/twitter-8 62.3MB/s ± 1% 63.1MB/s ± 1% +1.30% (p=0.016 n=5+5) UnmarshalDataset/code-8 42.1MB/s ± 0% 51.6MB/s ± 0% +22.62% (p=0.008 n=5+5) UnmarshalDataset/example-8 66.9MB/s ± 0% 68.3MB/s ± 0% +2.18% (p=0.008 n=5+5) Unmarshal/SimpleDocument/struct-8 25.1MB/s ± 1% 25.4MB/s ± 1% +1.43% (p=0.008 n=5+5) Unmarshal/SimpleDocument/map-8 18.5MB/s ± 2% 19.2MB/s ± 1% +3.70% (p=0.008 n=5+5) Unmarshal/ReferenceFile/struct-8 153MB/s ± 1% 156MB/s ± 0% +1.99% (p=0.008 n=5+5) Unmarshal/ReferenceFile/map-8 108MB/s ± 0% 119MB/s ± 1% +10.16% (p=0.008 n=5+5) Unmarshal/HugoFrontMatter-8 69.3MB/s ± 1% 75.0MB/s ± 1% +8.30% (p=0.008 n=5+5) name old alloc/op new alloc/op delta UnmarshalDataset/config-8 5.86MB ± 0% 5.26MB ± 0% -10.36% (p=0.008 n=5+5) UnmarshalDataset/canada-8 83.0MB ± 0% 83.0MB ± 0% -0.00% (p=0.008 n=5+5) UnmarshalDataset/citm_catalog-8 34.7MB ± 0% 34.7MB ± 0% -0.04% (p=0.008 n=5+5) UnmarshalDataset/twitter-8 12.7MB ± 0% 12.7MB ± 0% ~ (p=0.548 n=5+5) UnmarshalDataset/code-8 22.2MB ± 0% 15.3MB ± 0% -30.76% (p=0.008 n=5+5) UnmarshalDataset/example-8 186kB ± 0% 186kB ± 0% -0.04% (p=0.008 n=5+5) Unmarshal/SimpleDocument/struct-8 805B ± 0% 805B ± 0% ~ (all equal) Unmarshal/SimpleDocument/map-8 1.13kB ± 0% 1.13kB ± 0% ~ (all equal) Unmarshal/ReferenceFile/struct-8 20.9kB ± 0% 20.9kB ± 0% ~ (all equal) Unmarshal/ReferenceFile/map-8 38.2kB ± 0% 36.4kB ± 0% -4.86% (p=0.029 n=4+4) Unmarshal/HugoFrontMatter-8 7.44kB ± 0% 7.20kB ± 0% -3.23% (p=0.008 n=5+5) name old allocs/op new allocs/op delta UnmarshalDataset/config-8 227k ± 0% 189k ± 0% -16.74% (p=0.029 n=4+4) UnmarshalDataset/canada-8 782k ± 0% 782k ± 0% -0.00% (p=0.008 n=5+5) UnmarshalDataset/citm_catalog-8 192k ± 0% 191k ± 0% -0.49% (p=0.000 n=5+4) UnmarshalDataset/twitter-8 56.9k ± 0% 56.9k ± 0% -0.00% (p=0.032 n=5+5) UnmarshalDataset/code-8 1.05M ± 0% 0.63M ± 0% -40.52% (p=0.008 n=5+5) UnmarshalDataset/example-8 1.36k ± 0% 1.36k ± 0% -0.15% (p=0.008 n=5+5) Unmarshal/SimpleDocument/struct-8 9.00 ± 0% 9.00 ± 0% ~ (all equal) Unmarshal/SimpleDocument/map-8 13.0 ± 0% 13.0 ± 0% ~ (all equal) Unmarshal/ReferenceFile/struct-8 183 ± 0% 183 ± 0% ~ (all equal) Unmarshal/ReferenceFile/map-8 642 ± 0% 526 ± 0% -18.07% (p=0.008 n=5+5) Unmarshal/HugoFrontMatter-8 141 ± 0% 126 ± 0% -10.64% (p=0.008 n=5+5)
This commit is contained in:
+45
-9
@@ -230,15 +230,6 @@ func (d *decoder) fromParser(root reflect.Value) error {
|
||||
return d.p.Error()
|
||||
}
|
||||
|
||||
/*
|
||||
Rules for the unmarshal code:
|
||||
|
||||
- The stack is used to keep track of which values need to be set where.
|
||||
- handle* functions <=> switch on a given ast.Kind.
|
||||
- unmarshalX* functions need to unmarshal a node of kind X.
|
||||
- An "object" is either a struct or a map.
|
||||
*/
|
||||
|
||||
func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
|
||||
var x reflect.Value
|
||||
var err error
|
||||
@@ -400,6 +391,46 @@ func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value)
|
||||
return d.handleArrayTable(key, v)
|
||||
}
|
||||
|
||||
func (d *decoder) handleKeyPartMapStringInterface(key ast.Iterator, m map[string]interface{}, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
||||
newMap := false
|
||||
|
||||
k := string(key.Node().Data)
|
||||
if m == nil {
|
||||
newMap = true
|
||||
m = make(map[string]interface{}, 8)
|
||||
}
|
||||
|
||||
v, ok := m[k]
|
||||
set := false
|
||||
|
||||
if !ok || v == nil {
|
||||
set = true
|
||||
v = makeFn().Interface()
|
||||
}
|
||||
|
||||
mv := reflect.ValueOf(v)
|
||||
|
||||
x, err := nextFn(key, mv)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
if x.IsValid() {
|
||||
mv = x
|
||||
set = true
|
||||
}
|
||||
|
||||
if set {
|
||||
m[k] = mv.Interface()
|
||||
}
|
||||
|
||||
if newMap {
|
||||
return reflect.ValueOf(m), nil
|
||||
}
|
||||
|
||||
return reflect.Value{}, nil
|
||||
}
|
||||
|
||||
func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
||||
var rv reflect.Value
|
||||
|
||||
@@ -416,6 +447,11 @@ func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handle
|
||||
case reflect.Map:
|
||||
vt := v.Type()
|
||||
|
||||
if vt == mapStringInterfaceType {
|
||||
m := v.Interface().(map[string]interface{})
|
||||
return d.handleKeyPartMapStringInterface(key, m, nextFn, makeFn)
|
||||
}
|
||||
|
||||
// Create the key for the map element. Convert to key type.
|
||||
mk := reflect.ValueOf(string(key.Node().Data)).Convert(vt.Key())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user