aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/reflect
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2023-07-06 13:00:18 +0200
committerRon Evans <[email protected]>2023-07-07 08:10:47 +0200
commite98dfd6c4653a2fb1e3a64c0711808b06c5ae839 (patch)
tree1c5cacad7bd2584433023f6edb00fefbd369c86e /src/reflect
parent9126b9573711b1990f80ca1bca564c4886b8f8f2 (diff)
downloadtinygo-e98dfd6c4653a2fb1e3a64c0711808b06c5ae839.tar.gz
tinygo-e98dfd6c4653a2fb1e3a64c0711808b06c5ae839.zip
reflect: implement Value.Grow
This was added in Go 1.20 and becomes necessary for encoding/json in Go 1.21.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/all_test.go4
-rw-r--r--src/reflect/value.go32
2 files changed, 28 insertions, 8 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 4f9f223f1..cb7e4d2ac 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -790,6 +790,8 @@ func TestFunctionValue(t *testing.T) {
assert(t, v.Type().String(), "func()")
}
+*/
+
func TestGrow(t *testing.T) {
v := ValueOf([]int(nil))
shouldPanic("reflect.Value.Grow using unaddressable value", func() { v.Grow(0) })
@@ -857,8 +859,6 @@ func TestGrow(t *testing.T) {
})
}
-*/
-
var appendTests = []struct {
orig, extra []int
}{
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 5ee7e5fc1..60df82686 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1641,7 +1641,7 @@ func buflen(v Value) (unsafe.Pointer, uintptr) {
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) {
+func extendSlice(v Value, n int) sliceHeader {
if v.Kind() != Slice {
panic(&ValueError{Method: "extendSlice", Kind: v.Kind()})
}
@@ -1664,14 +1664,11 @@ func (v *Value) extendSlice(n int) {
ncap = old.cap
}
- newslice := sliceHeader{
+ return sliceHeader{
data: nbuf,
len: nlen + uintptr(n),
cap: ncap,
}
-
- v.flags = valueFlagExported
- v.value = (unsafe.Pointer)(&newslice)
}
// Append appends the values x to a slice s and returns the resulting slice.
@@ -1681,7 +1678,9 @@ func Append(v Value, x ...Value) Value {
panic(&ValueError{Method: "Append", Kind: v.Kind()})
}
oldLen := v.Len()
- v.extendSlice(len(x))
+ newslice := extendSlice(v, len(x))
+ v.flags = valueFlagExported
+ v.value = (unsafe.Pointer)(&newslice)
for i, xx := range x {
v.Index(oldLen + i).Set(xx)
}
@@ -1716,6 +1715,27 @@ func AppendSlice(s, t Value) Value {
}
}
+// Grow increases the slice's capacity, if necessary, to guarantee space for
+// another n elements. After Grow(n), at least n elements can be appended
+// to the slice without another allocation.
+//
+// It panics if v's Kind is not a Slice or if n is negative or too large to
+// allocate the memory.
+func (v Value) Grow(n int) {
+ v.checkAddressable()
+ if n < 0 {
+ panic("reflect.Grow: negative length")
+ }
+ if v.Kind() != Slice {
+ panic(&ValueError{Method: "Grow", Kind: v.Kind()})
+ }
+ slice := (*sliceHeader)(v.value)
+ newslice := extendSlice(v, n)
+ // Only copy the new data and cap: the len remains unchanged.
+ slice.data = newslice.data
+ slice.cap = newslice.cap
+}
+
//go:linkname hashmapStringSet runtime.hashmapStringSetUnsafePointer
func hashmapStringSet(m unsafe.Pointer, key string, value unsafe.Pointer)