diff --git a/src/reflect/value.go b/src/reflect/value.go index e8835806..d25b8bfa 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -958,10 +958,54 @@ func Copy(dst, src Value) int { panic("unimplemented: reflect.Copy()") } +//go:linkname sliceGrow runtime.sliceGrow +func sliceGrow(buf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr) + +// extend slice to hold n new elements +func (v *Value) extendSlice(n int) { + if v.Kind() != Slice { + panic(&ValueError{Method: "extendSlice", Kind: v.Kind()}) + } + + var old sliceHeader + if v.value != nil { + old = *(*sliceHeader)(v.value) + } + + var nbuf unsafe.Pointer + var nlen, ncap uintptr + + if old.len+uintptr(n) > old.cap { + // we need to grow the slice + nbuf, nlen, ncap = sliceGrow(old.data, old.len, old.cap, old.cap+uintptr(n), v.typecode.elem().Size()) + } else { + // we can reuse the slice we have + nbuf = old.data + nlen = old.len + ncap = old.cap + } + + newslice := sliceHeader{ + data: nbuf, + len: nlen + uintptr(n), + cap: ncap, + } + + v.value = (unsafe.Pointer)(&newslice) +} + // Append appends the values x to a slice s and returns the resulting slice. // As in Go, each x's value must be assignable to the slice's element type. -func Append(s Value, x ...Value) Value { - panic("unimplemented: reflect.Append()") +func Append(v Value, x ...Value) Value { + if v.Kind() != Slice { + panic(&ValueError{Method: "Append", Kind: v.Kind()}) + } + oldLen := v.Len() + v.extendSlice(len(x)) + for i, xx := range x { + v.Index(oldLen + i).Set(xx) + } + return v } // AppendSlice appends a slice t to a slice s and returns the resulting slice. diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index 668ffb01..de55f8d6 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -117,6 +117,23 @@ func TestMap(t *testing.T) { } } +func TestSlice(t *testing.T) { + s := []int{0, 10, 20} + refs := ValueOf(s) + + for i := 3; i < 10; i++ { + refs = Append(refs, ValueOf(i*10)) + } + + s = refs.Interface().([]int) + + for i := 0; i < 10; i++ { + if s[i] != i*10 { + t.Errorf("s[%d]=%d, want %d", i, s[i], i*10) + } + } +} + func equal[T comparable](a, b []T) bool { if len(a) != len(b) { return false