github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/kv/hasher.go (about) 1 //go:build go1.22 2 // +build go1.22 3 4 package kv 5 6 import ( 7 randv2 "math/rand/v2" 8 "unsafe" 9 ) 10 11 type hashFn func(unsafe.Pointer, uintptr) uintptr 12 13 // Copy from go1.22.1 14 // go/src/internal/abi/type.go 15 type _mapType struct { 16 _ [9]uint64 // go/src/internal/abi/type.go Type: size 48, 6 bytes; key, elem, bucket: size 8 * 3, 3 bytes 17 hasher func(unsafe.Pointer, uintptr) uintptr // function for hashing keys (ptr to key, seed) -> hash 18 _ uint64 // key size, value size, bucket size, flags 19 } 20 21 type _mapIface struct { 22 typ *_mapType 23 _ uint64 // go/src/runtime/map.go, hmap pointer, size 8, 1 byte 24 } 25 26 //go:nosplit 27 //go:nocheckptr 28 func noescape(p unsafe.Pointer) unsafe.Pointer { 29 x := uintptr(p) 30 return unsafe.Pointer(x ^ 0) 31 } 32 33 func newHashSeed() uintptr { 34 return uintptr(randv2.Int()) 35 } 36 37 type Hasher[K comparable] struct { 38 hash hashFn 39 seed uintptr 40 } 41 42 func (h Hasher[K]) Hash(key K) uint64 { 43 // Promise the key no escapes to the heap. 44 p := noescape(unsafe.Pointer(&key)) 45 return uint64(h.hash(p, h.seed)) 46 } 47 48 func getRuntimeHasher[K comparable]() (fn hashFn) { 49 i := (any)(make(map[K]struct{})) 50 iface := (*_mapIface)(unsafe.Pointer(&i)) 51 fn = iface.typ.hasher 52 return 53 } 54 55 func newHasher[K comparable]() Hasher[K] { 56 return Hasher[K]{ 57 hash: getRuntimeHasher[K](), 58 seed: newHashSeed(), 59 } 60 } 61 62 func newSeedHasher[K comparable](hasher Hasher[K]) Hasher[K] { 63 return Hasher[K]{ 64 hash: hasher.hash, 65 seed: newHashSeed(), 66 } 67 }