Use global cache to unmarshal all slice types

This commit is contained in:
Thomas Pelletier
2021-11-11 10:16:29 -05:00
parent 6430ee0bfa
commit 12244064bb
2 changed files with 55 additions and 35 deletions
-1
View File
@@ -321,7 +321,6 @@ type benchmarkDoc struct {
Key1 []int64
Key2 []string
Key3 [][]int64
// TODO: Key4 not supported by go-toml's Unmarshal
Key4 []interface{}
Key5 []int64
Key6 []int64
+34 -13
View File
@@ -621,12 +621,24 @@ func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
}
}
func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Value) error {
vt := v.Type()
type unmarshalArrayFn func(d *decoder, array *ast.Node, v reflect.Value) error
var globalUnmarshalArrayFnCache atomic.Value // map[danger.TypeID]unmarshalArrayFn
func unmarshalArrayFnFor(vt reflect.Type) unmarshalArrayFn {
tid := danger.MakeTypeID(vt)
cache, _ := globalUnmarshalArrayFnCache.Load().(map[danger.TypeID]unmarshalArrayFn)
fn, ok := cache[tid]
if ok {
return fn
}
elemType := vt.Elem()
elemSize := elemType.Size()
fn = func(d *decoder, array *ast.Node, v reflect.Value) error {
sp := (*danger.Slice)(unsafe.Pointer(v.UnsafeAddr()))
sp.Len = 0
@@ -640,7 +652,7 @@ func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Va
if sp.Len == sp.Cap {
c := sp.Cap
if c == 0 {
c = 10
c = 16
} else {
c *= 2
}
@@ -659,22 +671,30 @@ func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Va
sp.Len++
}
if sp.Data == nil {
*sp = danger.ExtendSlice(vt, sp, 0)
}
return nil
}
newCache := make(map[danger.TypeID]unmarshalArrayFn, len(cache)+1)
newCache[tid] = fn
for k, v := range cache {
newCache[k] = v
}
globalUnmarshalArrayFnCache.Store(newCache)
return fn
}
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
var vt reflect.Type
switch v.Kind() {
case reflect.Slice:
vt = v.Type()
if vt == sliceInterfaceType {
return d.unmarshalArrayFastSliceInterface(array, v)
}
if v.IsNil() {
v.Set(reflect.MakeSlice(v.Type(), 0, 16))
} else {
v.SetLen(0)
}
fn := unmarshalArrayFnFor(vt)
return fn(d, array, v)
case reflect.Array:
vt = v.Type()
// arrays are always initialized
@@ -1126,9 +1146,10 @@ var globalFieldPathsCache atomic.Value // map[danger.TypeID]fieldPathsMap
func structField(v reflect.Value, name string) (reflect.Value, bool) {
t := v.Type()
tid := danger.MakeTypeID(t)
cache, _ := globalFieldPathsCache.Load().(map[danger.TypeID]fieldPathsMap)
fieldPaths, ok := cache[danger.MakeTypeID(t)]
fieldPaths, ok := cache[tid]
if !ok {
fieldPaths = map[string][]int{}
@@ -1140,7 +1161,7 @@ func structField(v reflect.Value, name string) (reflect.Value, bool) {
})
newCache := make(map[danger.TypeID]fieldPathsMap, len(cache)+1)
newCache[danger.MakeTypeID(t)] = fieldPaths
newCache[tid] = fieldPaths
for k, v := range cache {
newCache[k] = v
}