diff options
Diffstat (limited to 'src/reflect/value.go')
-rw-r--r-- | src/reflect/value.go | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index 6fe3cee017..f92fa16fe6 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -281,14 +281,31 @@ func (v Value) Addr() Value { // Bool returns v's underlying value. // It panics if v's kind is not Bool. func (v Value) Bool() bool { - v.mustBe(Bool) + // panicNotBool is split out to keep Bool inlineable. + if v.kind() != Bool { + v.panicNotBool() + } return *(*bool)(v.ptr) } +func (v Value) panicNotBool() { + v.mustBe(Bool) +} + +var bytesType = TypeOf(([]byte)(nil)).(*rtype) + // Bytes returns v's underlying value. // It panics if v's underlying value is not a slice of bytes or // an addressable array of bytes. func (v Value) Bytes() []byte { + // bytesSlow is split out to keep Bytes inlineable for unnamed []byte. + if v.typ == bytesType { + return *(*[]byte)(v.ptr) + } + return v.bytesSlow() +} + +func (v Value) bytesSlow() []byte { switch v.kind() { case Slice: if v.typ.Elem().Kind() != Uint8 { @@ -1127,17 +1144,27 @@ func funcName(f func([]Value) []Value) string { } // 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 { + // capNonSlice is split out to keep Cap inlineable for slice kinds. + if v.kind() == Slice { + return (*unsafeheader.Slice)(v.ptr).Cap + } + return v.capNonSlice() +} + +func (v Value) capNonSlice() int { k := v.kind() switch k { case Array: return v.typ.Len() case Chan: return chancap(v.pointer()) - case Slice: - // Slice is always bigger than a word; assume flagIndir. - return (*unsafeheader.Slice)(v.ptr).Cap + 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()}) } @@ -1578,10 +1605,17 @@ func (v Value) Kind() Kind { } // 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 { - k := v.kind() - switch k { + // lenNonSlice is split out to keep Len inlineable for slice kinds. + if v.kind() == Slice { + return (*unsafeheader.Slice)(v.ptr).Len + } + return v.lenNonSlice() +} + +func (v Value) lenNonSlice() int { + switch k := v.kind(); k { case Array: tt := (*arrayType)(unsafe.Pointer(v.typ)) return int(tt.len) @@ -1589,12 +1623,14 @@ func (v Value) Len() int { return chanlen(v.pointer()) case Map: return maplen(v.pointer()) - case Slice: - // Slice is bigger than a word; assume flagIndir. - return (*unsafeheader.Slice)(v.ptr).Len case String: // String is bigger than a word; assume flagIndir. 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()}) } @@ -2441,12 +2477,17 @@ func (v Value) Slice3(i, j, k int) Value { // The fmt package treats Values specially. It does not call their String // method implicitly but instead prints the concrete values they hold. func (v Value) String() string { - switch k := v.kind(); k { - case Invalid: - return "<invalid Value>" - case String: + // stringNonString is split out to keep String inlineable for string kinds. + if v.kind() == String { return *(*string)(v.ptr) } + return v.stringNonString() +} + +func (v Value) stringNonString() string { + if v.kind() == Invalid { + return "<invalid Value>" + } // If you call String on a reflect.Value of other type, it's better to // print something than to panic. Useful in debugging. return "<" + v.Type().String() + " Value>" @@ -3056,9 +3097,10 @@ func NewAt(typ Type, p unsafe.Pointer) Value { return Value{t.ptrTo(), p, fl} } -// assignTo returns a value v that can be assigned directly to typ. -// It panics if v is not assignable to typ. -// For a conversion to an interface type, target is a suggested scratch space to use. +// assignTo returns a value v that can be assigned directly to dst. +// It panics if v is not assignable to dst. +// For a conversion to an interface type, target, if not nil, +// is a suggested scratch space to use. // target must be initialized memory (or nil). func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value { if v.flag&flagMethod != 0 { @@ -3074,9 +3116,6 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value return Value{dst, v.ptr, fl} case implements(dst, v.typ): - if target == nil { - target = unsafe_New(dst) - } if v.Kind() == Interface && v.IsNil() { // A nil ReadWriter passed to nil Reader is OK, // but using ifaceE2I below will panic. @@ -3084,6 +3123,9 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value return Value{dst, nil, flag(Interface)} } x := valueInterface(v, false) + if target == nil { + target = unsafe_New(dst) + } if dst.NumMethod() == 0 { *(*any)(target) = x } else { |