Source file
src/hash/maphash/maphash_purego.go
1
2
3
4
5
6
7 package maphash
8
9 import (
10 "crypto/rand"
11 "internal/byteorder"
12 "math/bits"
13 "reflect"
14 )
15
16 var hashkey [4]uint64
17
18 func init() {
19 for i := range hashkey {
20 hashkey[i] = randUint64()
21 }
22 }
23
24 func rthash(buf []byte, seed uint64) uint64 {
25 if len(buf) == 0 {
26 return seed
27 }
28 return wyhash(buf, seed, uint64(len(buf)))
29 }
30
31 func rthashString(s string, state uint64) uint64 {
32 return rthash([]byte(s), state)
33 }
34
35 func randUint64() uint64 {
36 buf := make([]byte, 8)
37 _, _ = rand.Read(buf)
38 return byteorder.LeUint64(buf)
39 }
40
41
42
43
44 const m5 = 0x1d8e4e27c47d124f
45
46 func wyhash(key []byte, seed, len uint64) uint64 {
47 p := key
48 i := len
49 var a, b uint64
50 seed ^= hashkey[0]
51
52 if i > 16 {
53 if i > 48 {
54 seed1 := seed
55 seed2 := seed
56 for ; i > 48; i -= 48 {
57 seed = mix(r8(p)^hashkey[1], r8(p[8:])^seed)
58 seed1 = mix(r8(p[16:])^hashkey[2], r8(p[24:])^seed1)
59 seed2 = mix(r8(p[32:])^hashkey[3], r8(p[40:])^seed2)
60 p = p[48:]
61 }
62 seed ^= seed1 ^ seed2
63 }
64 for ; i > 16; i -= 16 {
65 seed = mix(r8(p)^hashkey[1], r8(p[8:])^seed)
66 p = p[16:]
67 }
68 }
69 switch {
70 case i == 0:
71 return seed
72 case i < 4:
73 a = r3(p, i)
74 default:
75 n := (i >> 3) << 2
76 a = r4(p)<<32 | r4(p[n:])
77 b = r4(p[i-4:])<<32 | r4(p[i-4-n:])
78 }
79 return mix(m5^len, mix(a^hashkey[1], b^seed))
80 }
81
82 func r3(p []byte, k uint64) uint64 {
83 return (uint64(p[0]) << 16) | (uint64(p[k>>1]) << 8) | uint64(p[k-1])
84 }
85
86 func r4(p []byte) uint64 {
87 return uint64(byteorder.LeUint32(p))
88 }
89
90 func r8(p []byte) uint64 {
91 return byteorder.LeUint64(p)
92 }
93
94 func mix(a, b uint64) uint64 {
95 hi, lo := bits.Mul64(a, b)
96 return hi ^ lo
97 }
98
99 func comparableF[T comparable](h *Hash, v T) {
100 vv := reflect.ValueOf(v)
101 appendT(h, vv)
102 }
103
View as plain text