aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect/value.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r--libgo/go/reflect/value.go85
1 files changed, 69 insertions, 16 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 298fbac..c4a62c3 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -201,7 +201,8 @@ type nonEmptyInterface struct {
// v.flag.mustBe(Bool), which will only bother to copy the
// single important word for the receiver.
func (f flag) mustBe(expected Kind) {
- if f.kind() != expected {
+ // TODO(mvdan): use f.kind() again once mid-stack inlining gets better
+ if Kind(f&flagKindMask) != expected {
panic(&ValueError{methodName(), f.kind()})
}
}
@@ -209,8 +210,14 @@ func (f flag) mustBe(expected Kind) {
// mustBeExported panics if f records that the value was obtained using
// an unexported field.
func (f flag) mustBeExported() {
+ if f == 0 || f&flagRO != 0 {
+ f.mustBeExportedSlow()
+ }
+}
+
+func (f flag) mustBeExportedSlow() {
if f == 0 {
- panic(&ValueError{methodName(), 0})
+ panic(&ValueError{methodName(), Invalid})
}
if f&flagRO != 0 {
panic("reflect: " + methodName() + " using value obtained using unexported field")
@@ -221,6 +228,12 @@ func (f flag) mustBeExported() {
// which is to say that either it was obtained using an unexported field
// or it is not addressable.
func (f flag) mustBeAssignable() {
+ if f&flagRO != 0 || f&flagAddr == 0 {
+ f.mustBeAssignableSlow()
+ }
+}
+
+func (f flag) mustBeAssignableSlow() {
if f == 0 {
panic(&ValueError{methodName(), Invalid})
}
@@ -790,7 +803,7 @@ func (v Value) Interface() (i interface{}) {
func valueInterface(v Value, safe bool) interface{} {
if v.flag == 0 {
- panic(&ValueError{"reflect.Value.Interface", 0})
+ panic(&ValueError{"reflect.Value.Interface", Invalid})
}
if safe && v.flag&flagRO != 0 {
// Do not allow access to unexported values via Interface,
@@ -877,6 +890,46 @@ func (v Value) IsValid() bool {
return v.flag != 0
}
+// IsZero reports whether v is the zero value for its type.
+// It panics if the argument is invalid.
+func (v Value) IsZero() bool {
+ switch v.kind() {
+ case Bool:
+ return !v.Bool()
+ case Int, Int8, Int16, Int32, Int64:
+ return v.Int() == 0
+ case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+ return v.Uint() == 0
+ case Float32, Float64:
+ return math.Float64bits(v.Float()) == 0
+ case Complex64, Complex128:
+ c := v.Complex()
+ return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
+ case Array:
+ for i := 0; i < v.Len(); i++ {
+ if !v.Index(i).IsZero() {
+ return false
+ }
+ }
+ return true
+ case Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer:
+ return v.IsNil()
+ case String:
+ return v.Len() == 0
+ case Struct:
+ for i := 0; i < v.NumField(); i++ {
+ if !v.Field(i).IsZero() {
+ return false
+ }
+ }
+ return true
+ default:
+ // This should never happens, but will act as a safeguard for
+ // later, as a default value doesn't makes sense here.
+ panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
+ }
+}
+
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
@@ -1003,7 +1056,7 @@ func (it *MapIter) Value() Value {
t := (*mapType)(unsafe.Pointer(it.m.typ))
vtype := t.elem
- return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapitervalue(it.it))
+ return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it))
}
// Next advances the map iterator and reports whether there is another
@@ -1391,13 +1444,13 @@ func (v Value) SetCap(n int) {
s.Cap = n
}
-// SetMapIndex sets the value associated with key in the map v to val.
+// SetMapIndex sets the element associated with key in the map v to elem.
// It panics if v's Kind is not Map.
-// If val is the zero Value, SetMapIndex deletes the key from the map.
+// If elem is the zero Value, SetMapIndex deletes the key from the map.
// Otherwise if v holds a nil map, SetMapIndex will panic.
-// As in Go, key's value must be assignable to the map's key type,
-// and val's value must be assignable to the map's value type.
-func (v Value) SetMapIndex(key, val Value) {
+// As in Go, key's elem must be assignable to the map's key type,
+// and elem's value must be assignable to the map's elem type.
+func (v Value) SetMapIndex(key, elem Value) {
v.mustBe(Map)
v.mustBeExported()
key.mustBeExported()
@@ -1409,17 +1462,17 @@ func (v Value) SetMapIndex(key, val Value) {
} else {
k = unsafe.Pointer(&key.ptr)
}
- if val.typ == nil {
+ if elem.typ == nil {
mapdelete(v.typ, v.pointer(), k)
return
}
- val.mustBeExported()
- val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ elem.mustBeExported()
+ elem = elem.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
var e unsafe.Pointer
- if val.flag&flagIndir != 0 {
- e = val.ptr
+ if elem.flag&flagIndir != 0 {
+ e = elem.ptr
} else {
- e = unsafe.Pointer(&val.ptr)
+ e = unsafe.Pointer(&elem.ptr)
}
mapassign(v.typ, v.pointer(), k, e)
}
@@ -2464,7 +2517,7 @@ func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
//go:noescape
-func mapitervalue(it unsafe.Pointer) (value unsafe.Pointer)
+func mapiterelem(it unsafe.Pointer) (elem unsafe.Pointer)
//go:noescape
func mapiternext(it unsafe.Pointer)