Minimal shared cache for struct field paths

This commit is contained in:
Thomas Pelletier
2021-03-25 20:19:58 -04:00
parent 17299c937b
commit 1da2fc7e28
+32 -1
View File
@@ -5,6 +5,7 @@ import (
"math" "math"
"reflect" "reflect"
"strings" "strings"
"sync"
) )
type target interface { type target interface {
@@ -466,10 +467,37 @@ func scopeMap(v reflect.Value, name string) (target, bool, error) {
}, true, nil }, true, nil
} }
type fieldPathsMap = map[string][]int
type fieldPathsCache struct {
m map[reflect.Type]fieldPathsMap
l sync.RWMutex
}
func (c *fieldPathsCache) get(t reflect.Type) (fieldPathsMap, bool) {
c.l.RLock()
paths, ok := c.m[t]
c.l.RUnlock()
return paths, ok
}
func (c *fieldPathsCache) set(t reflect.Type, m fieldPathsMap) {
c.l.Lock()
c.m[t] = m
c.l.Unlock()
}
var globalFieldPathsCache = fieldPathsCache{
m: map[reflect.Type]fieldPathsMap{},
l: sync.RWMutex{},
}
func scopeStruct(v reflect.Value, name string) (target, bool, error) { func scopeStruct(v reflect.Value, name string) (target, bool, error) {
// TODO: cache this, and reduce allocations // TODO: cache this, and reduce allocations
fieldPaths := map[string][]int{} fieldPaths, ok := globalFieldPathsCache.get(v.Type())
if !ok {
fieldPaths = map[string][]int{}
path := make([]int, 0, 16) path := make([]int, 0, 16)
var walk func(reflect.Value) var walk func(reflect.Value)
@@ -502,6 +530,9 @@ func scopeStruct(v reflect.Value, name string) (target, bool, error) {
walk(v) walk(v)
globalFieldPathsCache.set(v.Type(), fieldPaths)
}
path, ok := fieldPaths[name] path, ok := fieldPaths[name]
if !ok { if !ok {
path, ok = fieldPaths[strings.ToLower(name)] path, ok = fieldPaths[strings.ToLower(name)]