78 lines
2 KiB
Go
78 lines
2 KiB
Go
|
package xsync
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
// makeSeed creates a random seed.
|
||
|
func makeSeed() uint64 {
|
||
|
var s1 uint32
|
||
|
for {
|
||
|
s1 = runtime_fastrand()
|
||
|
// We use seed 0 to indicate an uninitialized seed/hash,
|
||
|
// so keep trying until we get a non-zero seed.
|
||
|
if s1 != 0 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
s2 := runtime_fastrand()
|
||
|
return uint64(s1)<<32 | uint64(s2)
|
||
|
}
|
||
|
|
||
|
// hashString calculates a hash of s with the given seed.
|
||
|
func hashString(s string, seed uint64) uint64 {
|
||
|
if s == "" {
|
||
|
return seed
|
||
|
}
|
||
|
strh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||
|
return uint64(runtime_memhash(unsafe.Pointer(strh.Data), uintptr(seed), uintptr(strh.Len)))
|
||
|
}
|
||
|
|
||
|
//go:noescape
|
||
|
//go:linkname runtime_memhash runtime.memhash
|
||
|
func runtime_memhash(p unsafe.Pointer, h, s uintptr) uintptr
|
||
|
|
||
|
// defaultHasher creates a fast hash function for the given comparable type.
|
||
|
// The only limitation is that the type should not contain interfaces inside
|
||
|
// based on runtime.typehash.
|
||
|
func defaultHasher[T comparable]() func(T, uint64) uint64 {
|
||
|
var zero T
|
||
|
|
||
|
if reflect.TypeOf(&zero).Elem().Kind() == reflect.Interface {
|
||
|
return func(value T, seed uint64) uint64 {
|
||
|
iValue := any(value)
|
||
|
i := (*iface)(unsafe.Pointer(&iValue))
|
||
|
return runtime_typehash64(i.typ, i.word, seed)
|
||
|
}
|
||
|
} else {
|
||
|
var iZero any = zero
|
||
|
i := (*iface)(unsafe.Pointer(&iZero))
|
||
|
return func(value T, seed uint64) uint64 {
|
||
|
return runtime_typehash64(i.typ, unsafe.Pointer(&value), seed)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// how interface is represented in memory
|
||
|
type iface struct {
|
||
|
typ uintptr
|
||
|
word unsafe.Pointer
|
||
|
}
|
||
|
|
||
|
// same as runtime_typehash, but always returns a uint64
|
||
|
// see: maphash.rthash function for details
|
||
|
func runtime_typehash64(t uintptr, p unsafe.Pointer, seed uint64) uint64 {
|
||
|
if unsafe.Sizeof(uintptr(0)) == 8 {
|
||
|
return uint64(runtime_typehash(t, p, uintptr(seed)))
|
||
|
}
|
||
|
|
||
|
lo := runtime_typehash(t, p, uintptr(seed))
|
||
|
hi := runtime_typehash(t, p, uintptr(seed>>32))
|
||
|
return uint64(hi)<<32 | uint64(lo)
|
||
|
}
|
||
|
|
||
|
//go:noescape
|
||
|
//go:linkname runtime_typehash runtime.typehash
|
||
|
func runtime_typehash(t uintptr, p unsafe.Pointer, h uintptr) uintptr
|