mirror of https://github.com/golang/go.git
parent
d498867cf9
commit
1ce6954117
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue