Specialize array unmarshal into []interface{}

This commit is contained in:
Thomas Pelletier
2021-11-11 00:35:50 -05:00
parent 64fe47161f
commit cf530eba46
+44 -1
View File
@@ -11,6 +11,7 @@ import (
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
"unsafe"
"github.com/pelletier/go-toml/v2/internal/ast" "github.com/pelletier/go-toml/v2/internal/ast"
"github.com/pelletier/go-toml/v2/internal/danger" "github.com/pelletier/go-toml/v2/internal/danger"
@@ -620,15 +621,57 @@ func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
} }
} }
func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Value) error {
ifaceType := v.Type().Elem()
sp := (*[]interface{})(unsafe.Pointer(v.UnsafeAddr()))
s := *sp
if s == nil {
s = make([]interface{}, 0, 16)
} else {
s = s[:0]
}
var x interface{}
it := array.Children()
for it.Next() {
n := it.Node()
idx := len(s)
s = append(s, x)
datap := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data)
elemP := danger.Stride(datap, unsafe.Sizeof(x), idx)
elem := reflect.NewAt(ifaceType, elemP).Elem()
err := d.handleValue(n, elem)
if err != nil {
return err
}
}
*sp = s
return nil
}
func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error { func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
var vt reflect.Type
switch v.Kind() { switch v.Kind() {
case reflect.Slice: case reflect.Slice:
vt = v.Type()
if vt == sliceInterfaceType {
return d.unmarshalArrayFastSliceInterface(array, v)
}
if v.IsNil() { if v.IsNil() {
v.Set(reflect.MakeSlice(v.Type(), 0, 16)) v.Set(reflect.MakeSlice(v.Type(), 0, 16))
} else { } else {
v.SetLen(0) v.SetLen(0)
} }
case reflect.Array: case reflect.Array:
vt = v.Type()
// arrays are always initialized // arrays are always initialized
case reflect.Interface: case reflect.Interface:
elem := v.Elem() elem := v.Elem()
@@ -658,7 +701,7 @@ func (d *decoder) unmarshalArray(array *ast.Node, v reflect.Value) error {
return fmt.Errorf("toml: cannot store array in Go type %s", v.Kind()) return fmt.Errorf("toml: cannot store array in Go type %s", v.Kind())
} }
elemType := v.Type().Elem() elemType := vt.Elem()
it := array.Children() it := array.Children()
idx := 0 idx := 0