Use global cache to unmarshal all slice types
This commit is contained in:
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user