From 5cc5f11b5815131693a22d558d236e69fef532da Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Sat, 25 Feb 2023 17:35:19 -0800 Subject: [PATCH] reflect: add MakeSlice() --- src/reflect/value.go | 34 +++++++++++++++++++++++++++++++++- src/reflect/value_test.go | 7 +++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/reflect/value.go b/src/reflect/value.go index d25b8bfa..dce08795 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -882,8 +882,40 @@ func (v Value) Convert(t Type) Value { panic("unimplemented: (reflect.Value).Convert()") } +//go:linkname slicePanic runtime.slicePanic +func slicePanic() + func MakeSlice(typ Type, len, cap int) Value { - panic("unimplemented: reflect.MakeSlice()") + if typ.Kind() != Slice { + panic("reflect.MakeSlice of non-slice type") + } + + rtype := typ.(*rawType) + + ulen := uint(len) + ucap := uint(cap) + maxSize := (^uintptr(0)) / 2 + elementSize := rtype.elem().Size() + if elementSize > 1 { + maxSize /= uintptr(elementSize) + } + if ulen > ucap || ucap > uint(maxSize) { + slicePanic() + } + + // This can't overflow because of the above checks. + size := uintptr(ucap) * elementSize + + var slice sliceHeader + slice.cap = uintptr(ucap) + slice.len = uintptr(ulen) + slice.data = alloc(size, nil) + + return Value{ + typecode: rtype, + value: unsafe.Pointer(&slice), + flags: valueFlagExported, + } } func Zero(typ Type) Value { diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index de55f8d6..0c6e43d0 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -132,6 +132,13 @@ func TestSlice(t *testing.T) { t.Errorf("s[%d]=%d, want %d", i, s[i], i*10) } } + + refs = MakeSlice(TypeOf(s), 5, 10) + s = refs.Interface().([]int) + + if len(s) != refs.Len() || cap(s) != refs.Cap() { + t.Errorf("len(s)=%v refs.Len()=%v cap(s)=%v refs.Cap()=%v", len(s), refs.Len(), cap(s), refs.Cap()) + } } func equal[T comparable](a, b []T) bool {