From 43a4b256bd216345cdf23ce47d520eba90353091 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Sat, 25 Feb 2023 17:42:51 -0800 Subject: [PATCH] reflect: add Slice() --- src/reflect/value.go | 47 ++++++++++++++++++++++++++++++++++++++- src/reflect/value_test.go | 14 ++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/reflect/value.go b/src/reflect/value.go index dce08795..3216ada5 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -382,7 +382,52 @@ func (v Value) Bytes() []byte { } func (v Value) Slice(i, j int) Value { - panic("unimplemented: (reflect.Value).Slice()") + switch v.Kind() { + case Slice: + hdr := *(*sliceHeader)(v.value) + i, j := uintptr(i), uintptr(j) + + if j < i || hdr.cap < j { + slicePanic() + } + + elemSize := v.typecode.underlying().elem().Size() + + hdr.len = j - i + hdr.cap = hdr.cap - i + hdr.data = unsafe.Add(hdr.data, i*elemSize) + + return Value{ + typecode: v.typecode, + value: unsafe.Pointer(&hdr), + flags: v.flags, + } + + case Array: + // TODO(dgryski): can't do this yet because the resulting value needs type slice of v.elem(), not array of v.elem(). + // need to be able to look up this "new" type so pointer equality of types still works + + case String: + i, j := uintptr(i), uintptr(j) + str := *(*stringHeader)(v.value) + + if j < i || str.len < j { + slicePanic() + } + + hdr := stringHeader{ + data: unsafe.Add(str.data, i), + len: j - i, + } + + return Value{ + typecode: v.typecode, + value: unsafe.Pointer(&hdr), + flags: v.flags, + } + } + + panic(&ValueError{"Slice", v.Kind()}) } func (v Value) Slice3(i, j, k int) Value { diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index 0c6e43d0..d70984d9 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -133,6 +133,20 @@ func TestSlice(t *testing.T) { } } + s28 := s[2:8] + s28ref := refs.Slice(2, 8) + + if len(s28) != s28ref.Len() || cap(s28) != s28ref.Cap() { + t.Errorf("len(s28)=%d s28ref.Len()=%d cap(s28)=%d s28ref.Cap()=%d\n", len(s28), s28ref.Len(), cap(s28), s28ref.Cap()) + } + + for i, got := range s28 { + want := int(s28ref.Index(i).Int()) + if got != want { + t.Errorf("s28[%d]=%d, want %d", i, got, want) + } + } + refs = MakeSlice(TypeOf(s), 5, 10) s = refs.Interface().([]int)