reflect: implement AppendSlice
This implementation of AppendSlice simply calls through to the version used in the runtime: runtime.sliceAppend.
Этот коммит содержится в:
родитель
c8742e2b96
коммит
541d8dcd2e
2 изменённых файлов: 87 добавлений и 0 удалений
|
@ -780,6 +780,9 @@ func memcpy(dst, src unsafe.Pointer, size uintptr)
|
|||
//go:linkname alloc runtime.alloc
|
||||
func alloc(size uintptr) unsafe.Pointer
|
||||
|
||||
//go:linkname sliceAppend runtime.sliceAppend
|
||||
func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen uintptr, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr)
|
||||
|
||||
// Copy copies the contents of src into dst until either
|
||||
// dst has been filled or src has been exhausted.
|
||||
func Copy(dst, src Value) int {
|
||||
|
@ -792,6 +795,34 @@ func Append(s Value, x ...Value) Value {
|
|||
panic("unimplemented: reflect.Append()")
|
||||
}
|
||||
|
||||
// AppendSlice appends a slice t to a slice s and returns the resulting slice.
|
||||
// The slices s and t must have the same element type.
|
||||
func AppendSlice(s, t Value) Value {
|
||||
if s.typecode.Kind() != Slice || t.typecode.Kind() != Slice || s.typecode != t.typecode {
|
||||
// Not a very helpful error message, but shortened to just one error to
|
||||
// keep code size down.
|
||||
panic("reflect.AppendSlice: invalid types")
|
||||
}
|
||||
if !s.isExported() || !t.isExported() {
|
||||
// One of the sides was not exported, so can't access the data.
|
||||
panic("reflect.AppendSlice: unexported")
|
||||
}
|
||||
sSlice := (*sliceHeader)(s.value)
|
||||
tSlice := (*sliceHeader)(t.value)
|
||||
elemSize := s.typecode.elem().Size()
|
||||
ptr, len, cap := sliceAppend(sSlice.data, tSlice.data, sSlice.len, sSlice.cap, tSlice.len, elemSize)
|
||||
result := &sliceHeader{
|
||||
data: ptr,
|
||||
len: len,
|
||||
cap: cap,
|
||||
}
|
||||
return Value{
|
||||
typecode: s.typecode,
|
||||
value: unsafe.Pointer(result),
|
||||
flags: valueFlagExported,
|
||||
}
|
||||
}
|
||||
|
||||
func (v Value) SetMapIndex(key, elem Value) {
|
||||
panic("unimplemented: (reflect.Value).SetMapIndex()")
|
||||
}
|
||||
|
|
56
testdata/reflect.go
предоставленный
56
testdata/reflect.go
предоставленный
|
@ -280,6 +280,8 @@ func main() {
|
|||
panic("slice was changed while setting part of it")
|
||||
}
|
||||
|
||||
testAppendSlice()
|
||||
|
||||
// Test types that are created in reflect and never created elsewhere in a
|
||||
// value-to-interface conversion.
|
||||
v := reflect.ValueOf(new(unreferencedType))
|
||||
|
@ -409,6 +411,45 @@ func assertSize(ok bool, typ string) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test whether appending to a slice is equivalent between reflect and native
|
||||
// slice append.
|
||||
func testAppendSlice() {
|
||||
for i := 0; i < 100; i++ {
|
||||
dst := makeRandomSlice(i)
|
||||
src := makeRandomSlice(i)
|
||||
result1 := append(dst, src...)
|
||||
result2 := reflect.AppendSlice(reflect.ValueOf(dst), reflect.ValueOf(src)).Interface().([]uint32)
|
||||
if !sliceEqual(result1, result2) {
|
||||
println("slice: mismatch after runtime.SliceAppend with", len(dst), cap(dst), len(src), cap(src))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeRandomSlice(max int) []uint32 {
|
||||
cap := randuint32() % uint32(max+1)
|
||||
len := randuint32() % (cap + 1)
|
||||
s := make([]uint32, len, cap)
|
||||
for i := uint32(0); i < len; i++ {
|
||||
s[i] = randuint32()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sliceEqual(s1, s2 []uint32) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i, val := range s1 {
|
||||
if s2[i] != val {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Note: can't compare cap because the Go implementation has a different
|
||||
// behavior between the built-in append function and
|
||||
// reflect.AppendSlice.
|
||||
return true
|
||||
}
|
||||
|
||||
type unreferencedType int
|
||||
|
||||
type totallyUnreferencedType int
|
||||
|
@ -427,3 +468,18 @@ func TestStructTag() {
|
|||
field := st.Field(0)
|
||||
println(field.Tag.Get("color"), field.Tag.Get("species"))
|
||||
}
|
||||
|
||||
var xorshift32State uint32 = 1
|
||||
|
||||
func xorshift32(x uint32) uint32 {
|
||||
// Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs"
|
||||
x ^= x << 13
|
||||
x ^= x >> 17
|
||||
x ^= x << 5
|
||||
return x
|
||||
}
|
||||
|
||||
func randuint32() uint32 {
|
||||
xorshift32State = xorshift32(xorshift32State)
|
||||
return xorshift32State
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче