diff options
author | Ayke van Laethem <[email protected]> | 2023-07-06 13:00:18 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-07-07 08:10:47 +0200 |
commit | e98dfd6c4653a2fb1e3a64c0711808b06c5ae839 (patch) | |
tree | 1c5cacad7bd2584433023f6edb00fefbd369c86e /src/reflect | |
parent | 9126b9573711b1990f80ca1bca564c4886b8f8f2 (diff) | |
download | tinygo-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.go | 4 | ||||
-rw-r--r-- | src/reflect/value.go | 32 |
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) |