util/deephash: simplify canMemHash (#5384)

Put the t.Size() == 0 check first since this is applicable in all cases.
Drop the last struct field conditional since this is covered by the
sumFieldSize check at the end.

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai 2022-08-15 22:22:18 -07:00 committed by GitHub
parent 766ea96adf
commit c200229f9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 22 deletions

View File

@ -722,10 +722,15 @@ func typeIsRecursive(t reflect.Type) bool {
// canMemHash reports whether a slice of t can be hashed by looking at its // canMemHash reports whether a slice of t can be hashed by looking at its
// contiguous bytes in memory alone. (e.g. structs with gaps aren't memhashable) // contiguous bytes in memory alone. (e.g. structs with gaps aren't memhashable)
func canMemHash(t reflect.Type) bool { func canMemHash(t reflect.Type) bool {
if t.Size() == 0 {
return true
}
switch t.Kind() { switch t.Kind() {
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, case reflect.Bool,
reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float64, reflect.Float32, reflect.Complex128, reflect.Complex64: reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64,
reflect.Complex64, reflect.Complex128:
return true return true
case reflect.Array: case reflect.Array:
return canMemHash(t.Elem()) return canMemHash(t.Elem())
@ -734,15 +739,11 @@ func canMemHash(t reflect.Type) bool {
for i, numField := 0, t.NumField(); i < numField; i++ { for i, numField := 0, t.NumField(); i < numField; i++ {
sf := t.Field(i) sf := t.Field(i)
if !canMemHash(sf.Type) { if !canMemHash(sf.Type) {
// Special case for 0-width fields that aren't at the end.
if sf.Type.Size() == 0 && i < numField-1 {
continue
}
return false return false
} }
sumFieldSize += sf.Type.Size() sumFieldSize += sf.Type.Size()
} }
return sumFieldSize == t.Size() // else there are gaps return sumFieldSize == t.Size() // ensure no gaps
} }
return false return false
} }

View File

@ -379,20 +379,18 @@ func TestCanMemHash(t *testing.T) {
_ uint8 _ uint8
_ int _ int
}{}, false}, // gap }{}, false}, // gap
{ {struct {
struct { _ structs.Incomparable // if not last, zero-width
_ structs.Incomparable // if not last, zero-width x int
x int }{}, true},
}{}, {struct {
true, x int
}, _ structs.Incomparable // zero-width last: has space, can't memhash
{ }{},
struct { false},
x int {[0]chan bool{}, true},
_ structs.Incomparable // zero-width last: has space, can't memhash {struct{ f [0]func() }{}, true},
}{}, }
false,
}}
for _, tt := range tests { for _, tt := range tests {
got := canMemHash(reflect.TypeOf(tt.val)) got := canMemHash(reflect.TypeOf(tt.val))
if got != tt.want { if got != tt.want {