reflect: make sure to clear unusable hash/equal function
Otherwise we wind up copying the one from the prototype, which is wrong.
Also rewrite the hash/equal functions to look like the ones in Go 1.8,
mainly a matter of changing names and using arrayAt.
Change-Id: I92f5c45efb53528d87124d04bef31bdb822f16f4
Reviewed-on: https://go-review.googlesource.com/41133
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 00349ba..905c867 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -2074,9 +2074,11 @@
// This limitation may be lifted in a future version.
func StructOf(fields []StructField) Type {
var (
- hash = uint32(0)
- size uintptr
- typalign int8
+ hash = uint32(0)
+ size uintptr
+ typalign int8
+ comparable = true
+ hashable = true
fs = make([]structField, len(fields))
repr = make([]byte, 0, 64)
@@ -2157,6 +2159,9 @@
repr = append(repr, ';')
}
+ comparable = comparable && (ft.equalfn != nil)
+ hashable = hashable && (ft.hashfn != nil)
+
f.offset = align(size, uintptr(ft.fieldAlign))
if int8(ft.fieldAlign) > typalign {
typalign = int8(ft.fieldAlign)
@@ -2241,24 +2246,32 @@
typ.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
}
- typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
- ret := seed
- for _, ft := range typ.fields {
- o := unsafe.Pointer(uintptr(p) + ft.offset)
- ret = ft.typ.hashfn(o, ret)
+ if hashable {
+ typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
+ o := seed
+ for _, ft := range typ.fields {
+ pi := unsafe.Pointer(uintptr(p) + ft.offset)
+ o = ft.typ.hashfn(pi, o)
+ }
+ return o
}
- return ret
+ } else {
+ typ.hashfn = nil
}
- typ.equalfn = func(p, q unsafe.Pointer) bool {
- for _, ft := range typ.fields {
- pi := unsafe.Pointer(uintptr(p) + ft.offset)
- qi := unsafe.Pointer(uintptr(q) + ft.offset)
- if !ft.typ.equalfn(pi, qi) {
- return false
+ if comparable {
+ typ.equalfn = func(p, q unsafe.Pointer) bool {
+ for _, ft := range typ.fields {
+ pi := unsafe.Pointer(uintptr(p) + ft.offset)
+ qi := unsafe.Pointer(uintptr(q) + ft.offset)
+ if !ft.typ.equalfn(pi, qi) {
+ return false
+ }
}
+ return true
}
- return true
+ } else {
+ typ.equalfn = nil
}
typ.kind &^= kindDirectIface
@@ -2382,24 +2395,35 @@
array.kind &^= kindDirectIface
- array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
- ret := seed
- for i := 0; i < count; i++ {
- ret = typ.hashfn(p, ret)
- p = unsafe.Pointer(uintptr(p) + typ.size)
+ esize := typ.size
+
+ if typ.equalfn == nil {
+ array.equalfn = nil
+ } else {
+ eequal := typ.equalfn
+ array.equalfn = func(p, q unsafe.Pointer) bool {
+ for i := 0; i < count; i++ {
+ pi := arrayAt(p, i, esize)
+ qi := arrayAt(q, i, esize)
+ if !eequal(pi, qi) {
+ return false
+ }
+ }
+ return true
}
- return ret
}
- array.equalfn = func(p1, p2 unsafe.Pointer) bool {
- for i := 0; i < count; i++ {
- if !typ.equalfn(p1, p2) {
- return false
+ if typ.hashfn == nil {
+ array.hashfn = nil
+ } else {
+ ehash := typ.hashfn
+ array.hashfn = func(ptr unsafe.Pointer, seed uintptr) uintptr {
+ o := seed
+ for i := 0; i < count; i++ {
+ o = ehash(arrayAt(ptr, i, esize), o)
}
- p1 = unsafe.Pointer(uintptr(p1) + typ.size)
- p2 = unsafe.Pointer(uintptr(p2) + typ.size)
+ return o
}
- return true
}
return cachePut(ckey, &array.rtype)