diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 3a360b6c71..3ba6cc2d51 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -47,6 +47,8 @@ type T struct { d *int } +var _ = T{} == T{} // tests depend on T being comparable + type pair struct { i any s string @@ -1364,9 +1366,14 @@ func TestIsZero(t *testing.T) { {uintptr(128), false}, // Array {Zero(TypeOf([5]string{})).Interface(), true}, - {[5]string{"", "", "", "", ""}, true}, - {[5]string{}, true}, - {[5]string{"", "", "", "a", ""}, false}, + {[5]string{}, true}, // comparable array + {[5]string{"", "", "", "a", ""}, false}, // comparable array + {[1]*int{}, true}, // direct pointer array + {[1]*int{new(int)}, false}, // direct pointer array + {[3][]int{}, true}, // incomparable array + {[3][]int{{1}}, false}, // incomparable array + {[1 << 12]byte{}, true}, + {[1 << 12]byte{1}, false}, // Chan {(chan string)(nil), true}, {make(chan string), false}, @@ -1393,8 +1400,12 @@ func TestIsZero(t *testing.T) { {"", true}, {"not-zero", false}, // Structs - {T{}, true}, - {T{123, 456.75, "hello", &_i}, false}, + {T{}, true}, // comparable struct + {T{123, 456.75, "hello", &_i}, false}, // comparable struct + {struct{ p *int }{}, true}, // direct pointer struct + {struct{ p *int }{new(int)}, false}, // direct pointer struct + {struct{ s []int }{}, true}, // incomparable struct + {struct{ s []int }{[]int{1}}, false}, // incomparable struct // UnsafePointer {(unsafe.Pointer)(nil), true}, {(unsafe.Pointer)(new(int)), false}, @@ -1426,6 +1437,25 @@ func TestIsZero(t *testing.T) { }() } +func BenchmarkIsZero(b *testing.B) { + source := ValueOf(struct { + ArrayComparable [4]T + ArrayIncomparable [4]_Complex + StructComparable T + StructIncomparable _Complex + }{}) + + for i := 0; i < source.NumField(); i++ { + name := source.Type().Field(i).Name + value := source.Field(i) + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + sink = value.IsZero() + } + }) + } +} + func TestInterfaceExtraction(t *testing.T) { var s struct { W io.Writer diff --git a/src/reflect/value.go b/src/reflect/value.go index 02add5a768..95bf4682aa 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1579,7 +1579,16 @@ func (v Value) IsZero() bool { c := v.Complex() return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 case Array: - for i := 0; i < v.Len(); i++ { + // If the type is comparable, then compare directly with zero. + if v.typ.equal != nil && v.typ.size <= maxZero { + if v.flag&flagIndir == 0 { + return v.ptr == nil + } + return v.typ.equal(v.ptr, unsafe.Pointer(&zeroVal[0])) + } + + n := v.Len() + for i := 0; i < n; i++ { if !v.Index(i).IsZero() { return false } @@ -1590,7 +1599,16 @@ func (v Value) IsZero() bool { case String: return v.Len() == 0 case Struct: - for i := 0; i < v.NumField(); i++ { + // If the type is comparable, then compare directly with zero. + if v.typ.equal != nil && v.typ.size <= maxZero { + if v.flag&flagIndir == 0 { + return v.ptr == nil + } + return v.typ.equal(v.ptr, unsafe.Pointer(&zeroVal[0])) + } + + n := v.NumField() + for i := 0; i < n; i++ { if !v.Field(i).IsZero() { return false }