]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: make Index and Slice accept strings
authorEvan Shaw <chickencha@gmail.com>
Sun, 21 Oct 2012 21:02:10 +0000 (17:02 -0400)
committerRuss Cox <rsc@golang.org>
Sun, 21 Oct 2012 21:02:10 +0000 (17:02 -0400)
Fixes #3284.

R=golang-dev, r, rsc
CC=golang-dev
https://golang.org/cl/6643043

src/pkg/reflect/all_test.go
src/pkg/reflect/value.go

index 5ddd6bef18c1d559ec547f59e1b6adbb02fc0792..842b5075072c0997d3f2c4c4e980ab2a343d59e8 100644 (file)
@@ -2036,6 +2036,24 @@ func TestSmallNegativeInt(t *testing.T) {
        }
 }
 
+func TestIndex(t *testing.T) {
+       xs := []byte{1, 2, 3, 4, 5, 6, 7, 8}
+       v := ValueOf(xs).Index(3).Interface().(byte)
+       if v != xs[3] {
+               t.Errorf("xs.Index(3) = %v; expected %v", v, xs[3])
+       }
+       xa := [8]byte{10, 20, 30, 40, 50, 60, 70, 80}
+       v = ValueOf(xa).Index(2).Interface().(byte)
+       if v != xa[2] {
+               t.Errorf("xa.Index(2) = %v; expected %v", v, xa[2])
+       }
+       s := "0123456789"
+       v = ValueOf(s).Index(3).Interface().(byte)
+       if v != s[3] {
+               t.Errorf("s.Index(3) = %v; expected %v", v, s[3])
+       }
+}
+
 func TestSlice(t *testing.T) {
        xs := []int{1, 2, 3, 4, 5, 6, 7, 8}
        v := ValueOf(xs).Slice(3, 5).Interface().([]int)
@@ -2048,7 +2066,6 @@ func TestSlice(t *testing.T) {
        if !DeepEqual(v[0:5], xs[3:]) {
                t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5])
        }
-
        xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80}
        v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int)
        if len(v) != 3 {
@@ -2060,6 +2077,11 @@ func TestSlice(t *testing.T) {
        if !DeepEqual(v[0:6], xa[2:]) {
                t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6])
        }
+       s := "0123456789"
+       vs := ValueOf(s).Slice(3, 5).Interface().(string)
+       if vs != s[3:5] {
+               t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5])
+       }
 }
 
 func TestVariadic(t *testing.T) {
index 74addd19530c34a3f38c0ec983d24b6811f7ead9..be5d03504ed9e755730c57ca69ea6c34986ec7d1 100644 (file)
@@ -810,8 +810,10 @@ func (v Value) Float() float64 {
        panic(&ValueError{"reflect.Value.Float", k})
 }
 
+var uint8Type = TypeOf(uint8(0)).(*commonType)
+
 // Index returns v's i'th element.
-// It panics if v's Kind is not Array or Slice or i is out of range.
+// It panics if v's Kind is not Array, Slice, or String or i is out of range.
 func (v Value) Index(i int) Value {
        k := v.kind()
        switch k {
@@ -852,6 +854,15 @@ func (v Value) Index(i int) Value {
                fl |= flag(typ.Kind()) << flagKindShift
                val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
                return Value{typ, val, fl}
+
+       case String:
+               fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
+               s := (*StringHeader)(v.val)
+               if i < 0 || i >= s.Len {
+                       panic("reflect: string index out of range")
+               }
+               val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
+               return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
        }
        panic(&ValueError{"reflect.Value.Index", k})
 }
@@ -1437,7 +1448,7 @@ func (v Value) SetString(x string) {
 }
 
 // Slice returns a slice of v.
-// It panics if v's Kind is not Array or Slice.
+// It panics if v's Kind is not Array, Slice, or String.
 func (v Value) Slice(beg, end int) Value {
        var (
                cap  int
@@ -1447,6 +1458,7 @@ func (v Value) Slice(beg, end int) Value {
        switch k := v.kind(); k {
        default:
                panic(&ValueError{"reflect.Value.Slice", k})
+
        case Array:
                if v.flag&flagAddr == 0 {
                        panic("reflect.Value.Slice: slice of unaddressable array")
@@ -1455,13 +1467,25 @@ func (v Value) Slice(beg, end int) Value {
                cap = int(tt.len)
                typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice)))
                base = v.val
+
        case Slice:
                typ = (*sliceType)(unsafe.Pointer(v.typ))
                s := (*SliceHeader)(v.val)
                base = unsafe.Pointer(s.Data)
                cap = s.Cap
 
+       case String:
+               s := (*StringHeader)(v.val)
+               if beg < 0 || end < beg || end > s.Len {
+                       panic("reflect.Value.Slice: string slice index out of bounds")
+               }
+               var x string
+               val := (*StringHeader)(unsafe.Pointer(&x))
+               val.Data = s.Data + uintptr(beg)
+               val.Len = end - beg
+               return Value{v.typ, unsafe.Pointer(&x), v.flag}
        }
+
        if beg < 0 || end < beg || end > cap {
                panic("reflect.Value.Slice: slice index out of bounds")
        }