From 3bac16a6bf8ed0df6592d179ee17960d0688a071 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 18 Apr 2011 20:00:42 -0400 Subject: [PATCH] reflect: allow Slice of arrays R=r CC=golang-dev https://golang.org/cl/4444049 --- src/cmd/gc/reflect.c | 28 +++++++++++++++++++--------- src/pkg/reflect/all_test.go | 14 ++++++++++++++ src/pkg/reflect/type.go | 1 + src/pkg/reflect/value.go | 24 ++++++++++++++++++------ src/pkg/runtime/type.go | 5 +++-- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index fe9c6ac9fd6..4b0de95c26e 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -690,7 +690,7 @@ dtypesym(Type *t) int ot, xt, n, isddd, dupok; Sym *s, *s1, *s2; Sig *a, *m; - Type *t1, *tbase; + Type *t1, *tbase, *t2; if(isideal(t)) fatal("dtypesym %T", t); @@ -727,15 +727,25 @@ ok: break; case TARRAY: - // ../../pkg/runtime/type.go:/ArrayType - s1 = dtypesym(t->type); - ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; - ot = dsymptr(s, ot, s1, 0); - if(t->bound < 0) - ot = duintptr(s, ot, -1); - else + if(t->bound >= 0) { + // ../../pkg/runtime/type.go:/ArrayType + s1 = dtypesym(t->type); + t2 = typ(TARRAY); + t2->type = t->type; + t2->bound = -1; // slice + s2 = dtypesym(t2); + ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; + ot = dsymptr(s, ot, s1, 0); + ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); + } else { + // ../../pkg/runtime/type.go:/SliceType + s1 = dtypesym(t->type); + ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; + ot = dsymptr(s, ot, s1, 0); + } break; case TCHAN: diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go index 8529c62ae53..79fef902a00 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -1435,3 +1435,17 @@ func TestSmallNegativeInt(t *testing.T) { t.Errorf("int16(-1).Int() returned %v", v.Int()) } } + +func TestSlice(t *testing.T) { + xs := []int{1, 2, 3, 4, 5, 6, 7, 8} + v := NewValue(xs).Slice(3, 5).Interface().([]int) + if len(v) != 2 || v[0] != 4 || v[1] != 5 { + t.Errorf("xs.Slice(3, 5) = %v", v) + } + + xa := [7]int{10, 20, 30, 40, 50, 60, 70} + v = NewValue(&xa).Elem().Slice(2, 5).Interface().([]int) + if len(v) != 3 || v[0] != 30 || v[1] != 40 || v[2] != 50 { + t.Errorf("xa.Slice(2, 5) = %v", v) + } +} diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go index 4801731bbe2..5e3051cab51 100644 --- a/src/pkg/reflect/type.go +++ b/src/pkg/reflect/type.go @@ -260,6 +260,7 @@ const ( type arrayType struct { commonType "array" elem *runtime.Type + slice *runtime.Type len uintptr } diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index b31aa5a211e..44aaebd50a0 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -1244,20 +1244,32 @@ func (v Value) SetString(x string) { *(*string)(iv.addr) = x } -// BUG(rsc): Value.Slice should allow slicing arrays. - // Slice returns a slice of v. -// It panics if v's Kind is not Slice. +// It panics if v's Kind is not Array or Slice. func (v Value) Slice(beg, end int) Value { iv := v.internal() - iv.mustBe(Slice) + if iv.kind != Array && iv.kind != Slice { + panic(&ValueError{"reflect.Value.Slice", iv.kind}) + } cap := v.Cap() if beg < 0 || end < beg || end > cap { panic("reflect.Value.Slice: slice index out of bounds") } - typ := iv.typ.toType() + var typ Type + var base uintptr + switch iv.kind { + case Array: + if iv.flag&flagAddr == 0 { + panic("reflect.Value.Slice: slice of unaddressable array") + } + typ = toType((*arrayType)(unsafe.Pointer(iv.typ)).slice) + base = uintptr(iv.addr) + case Slice: + typ = iv.typ.toType() + base = (*SliceHeader)(iv.addr).Data + } s := new(SliceHeader) - s.Data = uintptr((*SliceHeader)(iv.addr).Data) + uintptr(beg)*typ.Elem().Size() + s.Data = base + uintptr(beg)*typ.Elem().Size() s.Len = end - beg s.Cap = cap - beg return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(s)) diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go index 71ad4e7a546..30f3ec6423d 100644 --- a/src/pkg/runtime/type.go +++ b/src/pkg/runtime/type.go @@ -117,8 +117,9 @@ type UnsafePointerType commonType // ArrayType represents a fixed array type. type ArrayType struct { commonType - elem *Type // array element type - len uintptr + elem *Type // array element type + slice *Type // slice type + len uintptr } // SliceType represents a slice type.