diff --git a/src/hash/maphash/maphash.go b/src/hash/maphash/maphash.go index d7cf4a57a0..5df080fd9a 100644 --- a/src/hash/maphash/maphash.go +++ b/src/hash/maphash/maphash.go @@ -293,47 +293,68 @@ func Comparable[T comparable](seed Seed, v T) uint64 { if len == 0 { return seed.s } - return comparableF(seed.s, v, t) + var h Hash + h.SetSeed(seed) + comparableF(&h, v, t) + return h.Sum64() } // WriteComparable adds x to the data hashed by h. func WriteComparable[T comparable](h *Hash, x T) { - v := Comparable(h.seed, x) - var buf [8]byte - byteorder.LePutUint64(buf[:], v) - h.Write(buf[:]) + comparableF(h, x, abi.TypeFor[T]()) } -func appendT(buf []byte, v reflect.Value) []byte { +func appendT(h *Hash, v reflect.Value) { switch v.Kind() { case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - return byteorder.LeAppendUint64(buf, uint64(v.Int())) + var buf [8]byte + byteorder.LePutUint64(buf[:], uint64(v.Int())) + h.Write(buf[:]) + return case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: - return byteorder.LeAppendUint64(buf, v.Uint()) + var buf [8]byte + byteorder.LePutUint64(buf[:], v.Uint()) + h.Write(buf[:]) + return case reflect.Array: for i := range v.Len() { - buf = appendT(buf, v.Index(i)) + appendT(h, v.Index(i)) } - return buf + return case reflect.String: - return append(buf, v.String()...) + h.WriteString(v.String()) + return case reflect.Struct: for i := range v.NumField() { - buf = appendT(buf, v.Field(i)) + appendT(h, v.Field(i)) } - return buf + return case reflect.Complex64, reflect.Complex128: c := v.Complex() - buf = byteorder.LeAppendUint64(buf, uint64(real(c))) - return byteorder.LeAppendUint64(buf, uint64(imag(c))) + var buf [8]byte + byteorder.LePutUint64(buf[:], uint64(real(c))) + h.Write(buf[:]) + byteorder.LePutUint64(buf[:], uint64(imag(c))) + h.Write(buf[:]) + return case reflect.Float32, reflect.Float64: - return byteorder.LeAppendUint64(buf, uint64(v.Float())) + var buf [8]byte + byteorder.LePutUint64(buf[:], uint64(v.Float())) + h.Write(buf[:]) + return case reflect.Bool: - return byteorder.LeAppendUint16(buf, btoi(v.Bool())) + var buf [8]byte + byteorder.LePutUint16(buf[:], btoi(v.Bool())) + h.Write(buf[:]) + return case reflect.UnsafePointer, reflect.Pointer: - return byteorder.LeAppendUint64(buf, uint64(v.Pointer())) + var buf [8]byte + byteorder.LePutUint64(buf[:], uint64(v.Pointer())) + h.Write(buf[:]) + return case reflect.Interface: - return appendT(buf, v.Elem()) + appendT(h, v.Elem()) + return } panic(fmt.Errorf("hash/maphash: %s not comparable", v.Type().String())) } diff --git a/src/hash/maphash/maphash_purego.go b/src/hash/maphash/maphash_purego.go index 7000c86914..7e56794736 100644 --- a/src/hash/maphash/maphash_purego.go +++ b/src/hash/maphash/maphash_purego.go @@ -97,13 +97,12 @@ func mix(a, b uint64) uint64 { var strTyp = reflect.TypeFor[string]() -func comparableF[T comparable](seed uint64, v T, t *abi.Type) uint64 { +func comparableF[T comparable](h *Hash, v T, t *abi.Type) { vv := reflect.ValueOf(v) typ := vv.Type() if typ == strTyp { - return rthashString(vv.String(), seed) + h.WriteString(vv.String()) + return } - buf := make([]byte, 0, typ.Size()) - buf = appendT(buf, vv) - return wyhash(buf, seed, uint64(len(buf))) + appendT(h, vv) } diff --git a/src/hash/maphash/maphash_runtime.go b/src/hash/maphash/maphash_runtime.go index 2305f56653..65d8a1878e 100644 --- a/src/hash/maphash/maphash_runtime.go +++ b/src/hash/maphash/maphash_runtime.go @@ -8,7 +8,6 @@ package maphash import ( "internal/abi" - "internal/unsafeheader" "reflect" "unsafe" ) @@ -45,13 +44,14 @@ func randUint64() uint64 { return runtime_rand() } -func comparableF[T comparable](seed uint64, v T, t *abi.Type) uint64 { +func comparableF[T comparable](h *Hash, v T, t *abi.Type) { ptr := unsafe.Pointer(&v) l := t.Size() k := t.Kind() if k == abi.String { - l = uintptr(((*unsafeheader.String)(unsafe.Pointer(&v))).Len) - ptr = ((*unsafeheader.String)(unsafe.Pointer(&v))).Data + s := ((*string)(unsafe.Pointer(&v))) + h.WriteString(*s) + return } else if t.TFlag&abi.TFlagRegularMemory == 0 { // Note: if T like struct {s string} // str value equal but ptr not equal, @@ -59,15 +59,8 @@ func comparableF[T comparable](seed uint64, v T, t *abi.Type) uint64 { // hash it, that happen v1 == v2 // Comparable(s, v1) != Comparable(s, v2). vv := reflect.ValueOf(v) - buf := make([]byte, 0, vv.Type().Size()) - buf = appendT(buf, vv) - ptr = unsafe.Pointer(&buf[0]) - l = uintptr(len(buf)) + appendT(h, vv) + return } - if unsafe.Sizeof(uintptr(0)) == 8 { - return uint64(runtime_memhash(ptr, uintptr(seed), l)) - } - lo := runtime_memhash(ptr, uintptr(seed), l) - hi := runtime_memhash(ptr, uintptr(seed>>32), l) - return uint64(hi)<<32 | uint64(lo) + h.Write(unsafe.Slice((*byte)(ptr), l)) }