Source file
src/hash/maphash/maphash_purego.go
1
2
3
4
5
6
7 package maphash
8
9 import (
10 "crypto/rand"
11 "errors"
12 "internal/byteorder"
13 "math"
14 "math/bits"
15 "reflect"
16 )
17
18 const purego = true
19
20 var hashkey [4]uint64
21
22 func init() {
23 for i := range hashkey {
24 hashkey[i] = randUint64()
25 }
26 }
27
28 func rthash(buf []byte, seed uint64) uint64 {
29 if len(buf) == 0 {
30 return seed
31 }
32 return wyhash(buf, seed, uint64(len(buf)))
33 }
34
35 func rthashString(s string, state uint64) uint64 {
36 return rthash([]byte(s), state)
37 }
38
39 func randUint64() uint64 {
40 buf := make([]byte, 8)
41 _, _ = rand.Read(buf)
42 return byteorder.LEUint64(buf)
43 }
44
45
46
47
48 const m5 = 0x1d8e4e27c47d124f
49
50 func wyhash(key []byte, seed, len uint64) uint64 {
51 p := key
52 i := len
53 var a, b uint64
54 seed ^= hashkey[0]
55
56 if i > 16 {
57 if i > 48 {
58 seed1 := seed
59 seed2 := seed
60 for ; i > 48; i -= 48 {
61 seed = mix(r8(p)^hashkey[1], r8(p[8:])^seed)
62 seed1 = mix(r8(p[16:])^hashkey[2], r8(p[24:])^seed1)
63 seed2 = mix(r8(p[32:])^hashkey[3], r8(p[40:])^seed2)
64 p = p[48:]
65 }
66 seed ^= seed1 ^ seed2
67 }
68 for ; i > 16; i -= 16 {
69 seed = mix(r8(p)^hashkey[1], r8(p[8:])^seed)
70 p = p[16:]
71 }
72 }
73 switch {
74 case i == 0:
75 return seed
76 case i < 4:
77 a = r3(p, i)
78 default:
79 n := (i >> 3) << 2
80 a = r4(p)<<32 | r4(p[n:])
81 b = r4(p[i-4:])<<32 | r4(p[i-4-n:])
82 }
83 return mix(m5^len, mix(a^hashkey[1], b^seed))
84 }
85
86 func r3(p []byte, k uint64) uint64 {
87 return (uint64(p[0]) << 16) | (uint64(p[k>>1]) << 8) | uint64(p[k-1])
88 }
89
90 func r4(p []byte) uint64 {
91 return uint64(byteorder.LEUint32(p))
92 }
93
94 func r8(p []byte) uint64 {
95 return byteorder.LEUint64(p)
96 }
97
98 func mix(a, b uint64) uint64 {
99 hi, lo := bits.Mul64(a, b)
100 return hi ^ lo
101 }
102
103 func comparableHash[T comparable](v T, seed Seed) uint64 {
104 var h Hash
105 h.SetSeed(seed)
106 writeComparable(&h, v)
107 return h.Sum64()
108 }
109
110 func writeComparable[T comparable](h *Hash, v T) {
111 vv := reflect.ValueOf(v)
112 appendT(h, vv)
113 }
114
115
116 func appendT(h *Hash, v reflect.Value) {
117 h.WriteString(v.Type().String())
118 switch v.Kind() {
119 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
120 var buf [8]byte
121 byteorder.LEPutUint64(buf[:], uint64(v.Int()))
122 h.Write(buf[:])
123 return
124 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
125 var buf [8]byte
126 byteorder.LEPutUint64(buf[:], v.Uint())
127 h.Write(buf[:])
128 return
129 case reflect.Array:
130 var buf [8]byte
131 for i := range uint64(v.Len()) {
132 byteorder.LEPutUint64(buf[:], i)
133
134
135 h.Write(buf[:])
136 appendT(h, v.Index(int(i)))
137 }
138 return
139 case reflect.String:
140 h.WriteString(v.String())
141 return
142 case reflect.Struct:
143 var buf [8]byte
144 for i := range v.NumField() {
145 f := v.Field(i)
146 byteorder.LEPutUint64(buf[:], uint64(i))
147
148
149
150 h.Write(buf[:])
151 appendT(h, f)
152 }
153 return
154 case reflect.Complex64, reflect.Complex128:
155 c := v.Complex()
156 h.float64(real(c))
157 h.float64(imag(c))
158 return
159 case reflect.Float32, reflect.Float64:
160 h.float64(v.Float())
161 return
162 case reflect.Bool:
163 h.WriteByte(btoi(v.Bool()))
164 return
165 case reflect.UnsafePointer, reflect.Pointer, reflect.Chan:
166 var buf [8]byte
167
168
169
170 byteorder.LEPutUint64(buf[:], uint64(v.Pointer()))
171 h.Write(buf[:])
172 return
173 case reflect.Interface:
174 appendT(h, v.Elem())
175 return
176 }
177 panic(errors.New("maphash: hash of unhashable type " + v.Type().String()))
178 }
179
180 func (h *Hash) float64(f float64) {
181 if f == 0 {
182 h.WriteByte(0)
183 return
184 }
185 var buf [8]byte
186 if f != f {
187 byteorder.LEPutUint64(buf[:], randUint64())
188 h.Write(buf[:])
189 return
190 }
191 byteorder.LEPutUint64(buf[:], math.Float64bits(f))
192 h.Write(buf[:])
193 }
194
195 func btoi(b bool) byte {
196 if b {
197 return 1
198 }
199 return 0
200 }
201
View as plain text