Generic slice unmarshal fn
This commit is contained in:
@@ -63,3 +63,14 @@ func Stride(ptr unsafe.Pointer, size uintptr, offset int) unsafe.Pointer {
|
|||||||
// https://github.com/golang/go/issues/40481
|
// https://github.com/golang/go/issues/40481
|
||||||
return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
|
return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Slice struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
Cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
type iface struct {
|
||||||
|
typ unsafe.Pointer
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package danger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExtendSlice(t reflect.Type, s *Slice, n int) Slice {
|
||||||
|
arrayType := reflect.ArrayOf(n, t.Elem())
|
||||||
|
arrayData := reflect.New(arrayType)
|
||||||
|
reflect.Copy(arrayData.Elem(), reflect.NewAt(t, unsafe.Pointer(s)).Elem())
|
||||||
|
return Slice{
|
||||||
|
Data: unsafe.Pointer(arrayData.Pointer()),
|
||||||
|
Len: s.Len,
|
||||||
|
Cap: n,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package danger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||||
|
func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname typedslicecopy reflect.typedslicecopy
|
||||||
|
//go:noescape
|
||||||
|
func typedslicecopy(elemType unsafe.Pointer, dst, src Slice) int
|
||||||
|
|
||||||
|
func ExtendSlice(t reflect.Type, s *Slice, n int) Slice {
|
||||||
|
elemTypeRef := t.Elem()
|
||||||
|
elemTypePtr := ((*iface)(unsafe.Pointer(&elemTypeRef))).ptr
|
||||||
|
|
||||||
|
d := Slice{
|
||||||
|
Data: unsafe_NewArray(elemTypePtr, n),
|
||||||
|
Len: s.Len,
|
||||||
|
Cap: n,
|
||||||
|
}
|
||||||
|
|
||||||
|
typedslicecopy(elemTypePtr, d, *s)
|
||||||
|
return d
|
||||||
|
}
|
||||||
+21
-16
@@ -622,37 +622,42 @@ func (d *decoder) handleValue(value *ast.Node, v reflect.Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Value) error {
|
func (d *decoder) unmarshalArrayFastSliceInterface(array *ast.Node, v reflect.Value) error {
|
||||||
ifaceType := v.Type().Elem()
|
vt := v.Type()
|
||||||
|
|
||||||
sp := (*[]interface{})(unsafe.Pointer(v.UnsafeAddr()))
|
elemType := vt.Elem()
|
||||||
s := *sp
|
elemSize := elemType.Size()
|
||||||
|
|
||||||
if s == nil {
|
sp := (*danger.Slice)(unsafe.Pointer(v.UnsafeAddr()))
|
||||||
s = make([]interface{}, 0, 16)
|
|
||||||
} else {
|
|
||||||
s = s[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
var x interface{}
|
sp.Len = 0
|
||||||
|
|
||||||
it := array.Children()
|
it := array.Children()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
n := it.Node()
|
n := it.Node()
|
||||||
|
|
||||||
idx := len(s)
|
idx := sp.Len
|
||||||
s = append(s, x)
|
|
||||||
|
|
||||||
datap := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data)
|
if sp.Len == sp.Cap {
|
||||||
elemP := danger.Stride(datap, unsafe.Sizeof(x), idx)
|
c := sp.Cap
|
||||||
elem := reflect.NewAt(ifaceType, elemP).Elem()
|
if c == 0 {
|
||||||
|
c = 10
|
||||||
|
} else {
|
||||||
|
c *= 2
|
||||||
|
}
|
||||||
|
*sp = danger.ExtendSlice(vt, sp, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
datap := unsafe.Pointer(sp.Data)
|
||||||
|
elemp := danger.Stride(datap, elemSize, idx)
|
||||||
|
elem := reflect.NewAt(elemType, elemp).Elem()
|
||||||
|
|
||||||
err := d.handleValue(n, elem)
|
err := d.handleValue(n, elem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
*sp = s
|
sp.Len++
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user