]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: add Value.IsZero
authorRomain Baugue <romain.baugue@elwinar.com>
Wed, 10 Apr 2019 14:20:43 +0000 (16:20 +0200)
committerIan Lance Taylor <iant@golang.org>
Sat, 13 Apr 2019 00:04:07 +0000 (00:04 +0000)
Fixes #7501

Change-Id: Iac7c79cd4b30a90b14ed84bf1eba758972232a6c
Reviewed-on: https://go-review.googlesource.com/c/go/+/171337
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/reflect/all_test.go
src/reflect/value.go

index 10b52456f34eecaaba881a01b72f6db26c735ddd..cbf0f5a93fe049296f189c89f7c38974c174d329 100644 (file)
@@ -1061,6 +1061,113 @@ func TestIsNil(t *testing.T) {
        NotNil(fi, t)
 }
 
+func TestIsZero(t *testing.T) {
+       for i, tt := range []struct {
+               x    interface{}
+               want bool
+       }{
+               // Booleans
+               {true, false},
+               {false, true},
+               // Numeric types
+               {int(0), true},
+               {int(1), false},
+               {int8(0), true},
+               {int8(1), false},
+               {int16(0), true},
+               {int16(1), false},
+               {int32(0), true},
+               {int32(1), false},
+               {int64(0), true},
+               {int64(1), false},
+               {uint(0), true},
+               {uint(1), false},
+               {uint8(0), true},
+               {uint8(1), false},
+               {uint16(0), true},
+               {uint16(1), false},
+               {uint32(0), true},
+               {uint32(1), false},
+               {uint64(0), true},
+               {uint64(1), false},
+               {float32(0), true},
+               {float32(1.2), false},
+               {float64(0), true},
+               {float64(1.2), false},
+               {math.Copysign(0, -1), false},
+               {complex64(0), true},
+               {complex64(1.2), false},
+               {complex128(0), true},
+               {complex128(1.2), false},
+               {complex(math.Copysign(0, -1), 0), false},
+               {complex(0, math.Copysign(0, -1)), false},
+               {complex(math.Copysign(0, -1), math.Copysign(0, -1)), false},
+               {uintptr(0), true},
+               {uintptr(128), false},
+               // Array
+               {Zero(TypeOf([5]string{})).Interface(), true},
+               {[5]string{"", "", "", "", ""}, true},
+               {[5]string{}, true},
+               {[5]string{"", "", "", "a", ""}, false},
+               // Chan
+               {(chan string)(nil), true},
+               {make(chan string), false},
+               {time.After(1), false},
+               // Func
+               {(func())(nil), true},
+               {New, false},
+               // Interface
+               {New(TypeOf(new(error)).Elem()).Elem(), true},
+               {(io.Reader)(strings.NewReader("")), false},
+               // Map
+               {(map[string]string)(nil), true},
+               {map[string]string{}, false},
+               {make(map[string]string), false},
+               // Ptr
+               {(*func())(nil), true},
+               {(*int)(nil), true},
+               {new(int), false},
+               // Slice
+               {[]string{}, false},
+               {([]string)(nil), true},
+               {make([]string, 0), false},
+               // Strings
+               {"", true},
+               {"not-zero", false},
+               // Structs
+               {T{}, true},
+               {T{123, 456.75, "hello", &_i}, false},
+               // UnsafePointer
+               {(unsafe.Pointer)(nil), true},
+               {(unsafe.Pointer)(new(int)), false},
+       } {
+               var x Value
+               if v, ok := tt.x.(Value); ok {
+                       x = v
+               } else {
+                       x = ValueOf(tt.x)
+               }
+
+               b := x.IsZero()
+               if b != tt.want {
+                       t.Errorf("%d: IsZero((%s)(%+v)) = %t, want %t", i, x.Kind(), tt.x, b, tt.want)
+               }
+
+               if !Zero(TypeOf(tt.x)).IsZero() {
+                       t.Errorf("%d: IsZero(Zero(TypeOf((%s)(%+v)))) is false", i, x.Kind(), tt.x)
+               }
+       }
+
+       func() {
+               defer func() {
+                       if r := recover(); r == nil {
+                               t.Error("should panic for invalid value")
+                       }
+               }()
+               (Value{}).IsZero()
+       }()
+}
+
 func TestInterfaceExtraction(t *testing.T) {
        var s struct {
                W io.Writer
index 5951b18b8c90a68ad8cf827e897524d54fbafcd8..75d817f8270d21bb056e520c1d6d742448d87090 100644 (file)
@@ -1071,6 +1071,46 @@ func (v Value) IsValid() bool {
        return v.flag != 0
 }
 
+// IsZero reports whether v is a 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 {