Change-Id: I930518778b9a29e5722d0fc149d54f8443605398
This commit is contained in:
qiulaidongfeng 2024-09-01 19:55:16 +08:00
parent d498867cf9
commit 1ce6954117
3 changed files with 51 additions and 38 deletions

View File

@ -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()))
}

View File

@ -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)
}

View File

@ -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))
}