1 package xxh3
2
3 import (
4 "math/bits"
5 )
6
7
8 func Hash128Seed(b []byte, seed uint64) Uint128 {
9 return hashAny128Seed(*(*str)(ptr(&b)), seed)
10 }
11
12
13 func HashString128Seed(s string, seed uint64) Uint128 {
14 return hashAny128Seed(*(*str)(ptr(&s)), seed)
15 }
16
17 func hashAny128Seed(s str, seed uint64) (acc u128) {
18 p, l := s.p, s.l
19
20 switch {
21 case l <= 16:
22 switch {
23 case l > 8:
24 bitflipl := (key64_032 ^ key64_040) - seed
25 bitfliph := (key64_048 ^ key64_056) + seed
26
27 input_lo := readU64(p, 0)
28 input_hi := readU64(p, ui(l)-8)
29
30 m128_h, m128_l := bits.Mul64(input_lo^input_hi^bitflipl, prime64_1)
31
32 m128_l += uint64(l-1) << 54
33 input_hi ^= bitfliph
34
35 m128_h += input_hi + uint64(uint32(input_hi))*(prime32_2-1)
36
37 m128_l ^= bits.ReverseBytes64(m128_h)
38
39 acc.Hi, acc.Lo = bits.Mul64(m128_l, prime64_2)
40 acc.Hi += m128_h * prime64_2
41
42 acc.Lo = xxh3Avalanche(acc.Lo)
43 acc.Hi = xxh3Avalanche(acc.Hi)
44
45 return acc
46
47 case l > 3:
48 seed ^= u64(bits.ReverseBytes32(u32(seed))) << 32
49 bitflip := (key64_016 ^ key64_024) + seed
50 input_lo := readU32(p, 0)
51 input_hi := readU32(p, ui(l)-4)
52 input_64 := u64(input_lo) + u64(input_hi)<<32
53 keyed := input_64 ^ bitflip
54
55 acc.Hi, acc.Lo = bits.Mul64(keyed, prime64_1+(uint64(l)<<2))
56
57 acc.Hi += acc.Lo << 1
58 acc.Lo ^= acc.Hi >> 3
59
60 acc.Lo ^= acc.Lo >> 35
61 acc.Lo *= 0x9fb21c651e98df25
62 acc.Lo ^= acc.Lo >> 28
63 acc.Hi = xxh3Avalanche(acc.Hi)
64
65 return acc
66
67 case l == 3:
68 c12 := u64(readU16(p, 0))
69 c3 := u64(readU8(p, 2))
70 acc.Lo = c12<<16 + c3 + 3<<8
71
72 case l > 1:
73 c12 := u64(readU16(p, 0))
74 acc.Lo = c12*(1<<24+1)>>8 + 2<<8
75
76 case l == 1:
77 c1 := u64(readU8(p, 0))
78 acc.Lo = c1*(1<<24+1<<16+1) + 1<<8
79
80 default:
81 bitflipl := key64_064 ^ key64_072 ^ seed
82 bitfliph := key64_080 ^ key64_088 ^ seed
83 return u128{Lo: xxh64AvalancheFull(bitflipl), Hi: xxh64AvalancheFull(bitfliph)}
84 }
85
86 acc.Hi = uint64(bits.RotateLeft32(bits.ReverseBytes32(uint32(acc.Lo)), 13))
87 acc.Lo ^= uint64(key32_000^key32_004) + seed
88 acc.Hi ^= uint64(key32_008^key32_012) - seed
89
90 acc.Lo = xxh64AvalancheFull(acc.Lo)
91 acc.Hi = xxh64AvalancheFull(acc.Hi)
92
93 return acc
94
95 case l <= 128:
96 acc.Lo = u64(l) * prime64_1
97
98 if l > 32 {
99 if l > 64 {
100 if l > 96 {
101 in8, in7 := readU64(p, ui(l)-8*8), readU64(p, ui(l)-7*8)
102 i6, i7 := readU64(p, 6*8), readU64(p, 7*8)
103
104 acc.Hi += mulFold64(in8^(key64_112+seed), in7^(key64_120-seed))
105 acc.Hi ^= i6 + i7
106 acc.Lo += mulFold64(i6^(key64_096+seed), i7^(key64_104-seed))
107 acc.Lo ^= in8 + in7
108
109 }
110
111 in6, in5 := readU64(p, ui(l)-6*8), readU64(p, ui(l)-5*8)
112 i4, i5 := readU64(p, 4*8), readU64(p, 5*8)
113
114 acc.Hi += mulFold64(in6^(key64_080+seed), in5^(key64_088-seed))
115 acc.Hi ^= i4 + i5
116 acc.Lo += mulFold64(i4^(key64_064+seed), i5^(key64_072-seed))
117 acc.Lo ^= in6 + in5
118
119 }
120
121 in4, in3 := readU64(p, ui(l)-4*8), readU64(p, ui(l)-3*8)
122 i2, i3 := readU64(p, 2*8), readU64(p, 3*8)
123
124 acc.Hi += mulFold64(in4^(key64_048+seed), in3^(key64_056-seed))
125 acc.Hi ^= i2 + i3
126 acc.Lo += mulFold64(i2^(key64_032+seed), i3^(key64_040-seed))
127 acc.Lo ^= in4 + in3
128
129 }
130
131 in2, in1 := readU64(p, ui(l)-2*8), readU64(p, ui(l)-1*8)
132 i0, i1 := readU64(p, 0*8), readU64(p, 1*8)
133
134 acc.Hi += mulFold64(in2^(key64_016+seed), in1^(key64_024-seed))
135 acc.Hi ^= i0 + i1
136 acc.Lo += mulFold64(i0^(key64_000+seed), i1^(key64_008-seed))
137 acc.Lo ^= in2 + in1
138
139 acc.Hi, acc.Lo = (acc.Lo*prime64_1)+(acc.Hi*prime64_4)+((u64(l)-seed)*prime64_2), acc.Hi+acc.Lo
140
141 acc.Hi = -xxh3Avalanche(acc.Hi)
142 acc.Lo = xxh3Avalanche(acc.Lo)
143
144 return acc
145
146 case l <= 240:
147 acc.Lo = u64(l) * prime64_1
148
149 {
150 i0, i1, i2, i3 := readU64(p, 0*8), readU64(p, 1*8), readU64(p, 2*8), readU64(p, 3*8)
151
152 acc.Hi += mulFold64(i2^(key64_016+seed), i3^(key64_024-seed))
153 acc.Hi ^= i0 + i1
154 acc.Lo += mulFold64(i0^(key64_000+seed), i1^(key64_008-seed))
155 acc.Lo ^= i2 + i3
156 }
157
158 {
159 i0, i1, i2, i3 := readU64(p, 4*8), readU64(p, 5*8), readU64(p, 6*8), readU64(p, 7*8)
160
161 acc.Hi += mulFold64(i2^(key64_048+seed), i3^(key64_056-seed))
162 acc.Hi ^= i0 + i1
163 acc.Lo += mulFold64(i0^(key64_032+seed), i1^(key64_040-seed))
164 acc.Lo ^= i2 + i3
165 }
166
167 {
168 i0, i1, i2, i3 := readU64(p, 8*8), readU64(p, 9*8), readU64(p, 10*8), readU64(p, 11*8)
169
170 acc.Hi += mulFold64(i2^(key64_080+seed), i3^(key64_088-seed))
171 acc.Hi ^= i0 + i1
172 acc.Lo += mulFold64(i0^(key64_064+seed), i1^(key64_072-seed))
173 acc.Lo ^= i2 + i3
174 }
175
176 {
177 i0, i1, i2, i3 := readU64(p, 12*8), readU64(p, 13*8), readU64(p, 14*8), readU64(p, 15*8)
178
179 acc.Hi += mulFold64(i2^(key64_112+seed), i3^(key64_120-seed))
180 acc.Hi ^= i0 + i1
181 acc.Lo += mulFold64(i0^(key64_096+seed), i1^(key64_104-seed))
182 acc.Lo ^= i2 + i3
183 }
184
185
186 acc.Hi = xxh3Avalanche(acc.Hi)
187 acc.Lo = xxh3Avalanche(acc.Lo)
188
189
190 top := ui(l) &^ 31
191 for i := ui(4 * 32); i < top; i += 32 {
192 i0, i1, i2, i3 := readU64(p, i+0), readU64(p, i+8), readU64(p, i+16), readU64(p, i+24)
193 k0, k1, k2, k3 := readU64(key, i-125)+seed, readU64(key, i-117)-seed, readU64(key, i-109)+seed, readU64(key, i-101)-seed
194
195 acc.Hi += mulFold64(i2^k2, i3^k3)
196 acc.Hi ^= i0 + i1
197 acc.Lo += mulFold64(i0^k0, i1^k1)
198 acc.Lo ^= i2 + i3
199 }
200
201
202 {
203 i0, i1, i2, i3 := readU64(p, ui(l)-32), readU64(p, ui(l)-24), readU64(p, ui(l)-16), readU64(p, ui(l)-8)
204
205 seed := 0 - seed
206 acc.Hi += mulFold64(i0^(key64_119+seed), i1^(key64_127-seed))
207 acc.Hi ^= i2 + i3
208 acc.Lo += mulFold64(i2^(key64_103+seed), i3^(key64_111-seed))
209 acc.Lo ^= i0 + i1
210 }
211
212 acc.Hi, acc.Lo = (acc.Lo*prime64_1)+(acc.Hi*prime64_4)+((u64(l)-seed)*prime64_2), acc.Hi+acc.Lo
213
214 acc.Hi = -xxh3Avalanche(acc.Hi)
215 acc.Lo = xxh3Avalanche(acc.Lo)
216
217 return acc
218
219 default:
220 acc.Lo = u64(l) * prime64_1
221 acc.Hi = ^(u64(l) * prime64_2)
222
223 secret := key
224 if seed != 0 {
225 secret = ptr(&[secretSize]byte{})
226 initSecret(secret, seed)
227 }
228
229 accs := [8]u64{
230 prime32_3, prime64_1, prime64_2, prime64_3,
231 prime64_4, prime32_2, prime64_5, prime32_1,
232 }
233
234 if hasAVX512 && l >= avx512Switch {
235 accumAVX512(&accs, p, secret, u64(l))
236 } else if hasAVX2 {
237 accumAVX2(&accs, p, secret, u64(l))
238 } else if hasSSE2 {
239 accumSSE(&accs, p, secret, u64(l))
240 } else {
241 accumScalar(&accs, p, secret, u64(l))
242 }
243
244
245 const hi_off = 117 - 11
246
247 acc.Lo += mulFold64(accs[0]^readU64(secret, 11), accs[1]^readU64(secret, 19))
248 acc.Hi += mulFold64(accs[0]^readU64(secret, 11+hi_off), accs[1]^readU64(secret, 19+hi_off))
249
250 acc.Lo += mulFold64(accs[2]^readU64(secret, 27), accs[3]^readU64(secret, 35))
251 acc.Hi += mulFold64(accs[2]^readU64(secret, 27+hi_off), accs[3]^readU64(secret, 35+hi_off))
252
253 acc.Lo += mulFold64(accs[4]^readU64(secret, 43), accs[5]^readU64(secret, 51))
254 acc.Hi += mulFold64(accs[4]^readU64(secret, 43+hi_off), accs[5]^readU64(secret, 51+hi_off))
255
256 acc.Lo += mulFold64(accs[6]^readU64(secret, 59), accs[7]^readU64(secret, 67))
257 acc.Hi += mulFold64(accs[6]^readU64(secret, 59+hi_off), accs[7]^readU64(secret, 67+hi_off))
258
259 acc.Lo = xxh3Avalanche(acc.Lo)
260 acc.Hi = xxh3Avalanche(acc.Hi)
261
262 return acc
263 }
264 }
265
View as plain text