reflect: support Len and Cap on pointer-to-array Value

Fixes #52411

Change-Id: I2fd13a453622992c52d49aade7cd058cfc8a77ca
GitHub-Last-Rev: d5987c2ec8
GitHub-Pull-Request: golang/go#52423
Reviewed-on: https://go-review.googlesource.com/c/go/+/400954
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Keith Randall <khr@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
cuiweixie 2022-04-25 05:21:35 +00:00 committed by Gopher Robot
parent 35f2aba283
commit 892cd0b636
2 changed files with 78 additions and 2 deletions

View File

@ -7913,3 +7913,69 @@ func BenchmarkSliceCap(b *testing.B) {
sinkAll.RawInt = sourceAll.SliceAny.Cap() sinkAll.RawInt = sourceAll.SliceAny.Cap()
} }
} }
func TestValue_Cap(t *testing.T) {
a := &[3]int{1, 2, 3}
v := ValueOf(a)
if v.Cap() != cap(a) {
t.Errorf("Cap = %d want %d", v.Cap(), cap(a))
}
a = nil
v = ValueOf(a)
if v.Cap() != cap(a) {
t.Errorf("Cap = %d want %d", v.Cap(), cap(a))
}
getError := func(f func()) (errorStr string) {
defer func() {
e := recover()
if str, ok := e.(string); ok {
errorStr = str
}
}()
f()
return
}
e := getError(func() {
var ptr *int
ValueOf(ptr).Cap()
})
wantStr := "reflect: call of reflect.Value.Cap on ptr to non-array Value"
if e != wantStr {
t.Errorf("error is %q, want %q", e, wantStr)
}
}
func TestValue_Len(t *testing.T) {
a := &[3]int{1, 2, 3}
v := ValueOf(a)
if v.Len() != len(a) {
t.Errorf("Len = %d want %d", v.Len(), len(a))
}
a = nil
v = ValueOf(a)
if v.Len() != len(a) {
t.Errorf("Len = %d want %d", v.Len(), len(a))
}
getError := func(f func()) (errorStr string) {
defer func() {
e := recover()
if str, ok := e.(string); ok {
errorStr = str
}
}()
f()
return
}
e := getError(func() {
var ptr *int
ValueOf(ptr).Len()
})
wantStr := "reflect: call of reflect.Value.Len on ptr to non-array Value"
if e != wantStr {
t.Errorf("error is %q, want %q", e, wantStr)
}
}

View File

@ -1144,7 +1144,7 @@ func funcName(f func([]Value) []Value) string {
} }
// Cap returns v's capacity. // Cap returns v's capacity.
// It panics if v's Kind is not Array, Chan, or Slice. // It panics if v's Kind is not Array, Chan, Slice or pointer to Array.
func (v Value) Cap() int { func (v Value) Cap() int {
// capNonSlice is split out to keep Cap inlineable for slice kinds. // capNonSlice is split out to keep Cap inlineable for slice kinds.
if v.kind() == Slice { if v.kind() == Slice {
@ -1160,6 +1160,11 @@ func (v Value) capNonSlice() int {
return v.typ.Len() return v.typ.Len()
case Chan: case Chan:
return chancap(v.pointer()) return chancap(v.pointer())
case Ptr:
if v.typ.Elem().Kind() == Array {
return v.typ.Elem().Len()
}
panic("reflect: call of reflect.Value.Cap on ptr to non-array Value")
} }
panic(&ValueError{"reflect.Value.Cap", v.kind()}) panic(&ValueError{"reflect.Value.Cap", v.kind()})
} }
@ -1600,7 +1605,7 @@ func (v Value) Kind() Kind {
} }
// Len returns v's length. // Len returns v's length.
// It panics if v's Kind is not Array, Chan, Map, Slice, or String. // It panics if v's Kind is not Array, Chan, Map, Slice, String, or pointer to Array.
func (v Value) Len() int { func (v Value) Len() int {
// lenNonSlice is split out to keep Len inlineable for slice kinds. // lenNonSlice is split out to keep Len inlineable for slice kinds.
if v.kind() == Slice { if v.kind() == Slice {
@ -1621,6 +1626,11 @@ func (v Value) lenNonSlice() int {
case String: case String:
// String is bigger than a word; assume flagIndir. // String is bigger than a word; assume flagIndir.
return (*unsafeheader.String)(v.ptr).Len return (*unsafeheader.String)(v.ptr).Len
case Ptr:
if v.typ.Elem().Kind() == Array {
return v.typ.Elem().Len()
}
panic("reflect: call of reflect.Value.Len on ptr to non-array Value")
} }
panic(&ValueError{"reflect.Value.Len", v.kind()}) panic(&ValueError{"reflect.Value.Len", v.kind()})
} }