The Pedigree Project 0.1
MurmurHash3.cpp
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20//-----------------------------------------------------------------------------
21// MurmurHash3 was written by Austin Appleby, and is placed in the public
22// domain. The author hereby disclaims copyright to this source code.
23
24// Note - The x86 and x64 versions do _not_ produce the same results, as the
25// algorithms are optimized for their respective platforms. You can still
26// compile and run any of them on any platform, but your performance with the
27// non-native version will be less than optimal.
28
29#include "pedigree/kernel/utilities/smhasher/MurmurHash3.h"
30
31//-----------------------------------------------------------------------------
32// Platform-specific functions and macros
33
34// Microsoft Visual Studio
35
36#if defined(_MSC_VER)
37
38#define FORCE_INLINE __forceinline
39
40#include <stdlib.h>
41
42#define ROTL32(x, y) _rotl(x, y)
43#define ROTL64(x, y) _rotl64(x, y)
44
45#define BIG_CONSTANT(x) (x)
46
47// Other compilers
48
49#else // defined(_MSC_VER)
50
51#define FORCE_INLINE inline __attribute__((always_inline))
52
53inline uint32_t rotl32(uint32_t x, int8_t r) {
54 return (x << r) | (x >> (32 - r));
55}
56
57inline uint64_t rotl64(uint64_t x, int8_t r) {
58 return (x << r) | (x >> (64 - r));
59}
60
61#define ROTL32(x, y) rotl32(x, y)
62#define ROTL64(x, y) rotl64(x, y)
63
64#define BIG_CONSTANT(x) (x##LLU)
65
66#endif // !defined(_MSC_VER)
67
68//-----------------------------------------------------------------------------
69// Block read - if your platform needs to do endian-swapping or can only
70// handle aligned reads, do the conversion here
71
72FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) {
73 return p[i];
74}
75
76FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i) {
77 return p[i];
78}
79
80//-----------------------------------------------------------------------------
81// Finalization mix - force all bits of a hash block to avalanche
82
83FORCE_INLINE uint32_t fmix32(uint32_t h) {
84 h ^= h >> 16;
85 h *= 0x85ebca6b;
86 h ^= h >> 13;
87 h *= 0xc2b2ae35;
88 h ^= h >> 16;
89
90 return h;
91}
92
93//----------
94
95FORCE_INLINE uint64_t fmix64(uint64_t k) {
96 k ^= k >> 33;
97 k *= BIG_CONSTANT(0xff51afd7ed558ccd);
98 k ^= k >> 33;
99 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
100 k ^= k >> 33;
101
102 return k;
103}
104
105//-----------------------------------------------------------------------------
106
107void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out) {
108 const uint8_t* data = (const uint8_t*)key;
109 const int nblocks = len / 4;
110
111 uint32_t h1 = seed;
112
113 const uint32_t c1 = 0xcc9e2d51;
114 const uint32_t c2 = 0x1b873593;
115
116 //----------
117 // body
118
119 const uint32_t* blocks = ((const uint32_t*)key) + nblocks;
120
121 for (int i = -nblocks; i; i++) {
122 uint32_t k1 = getblock32(blocks, i);
123
124 k1 *= c1;
125 k1 = ROTL32(k1, 15);
126 k1 *= c2;
127
128 h1 ^= k1;
129 h1 = ROTL32(h1, 13);
130 h1 = h1 * 5 + 0xe6546b64;
131 }
132
133 //----------
134 // tail
135
136 const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
137
138 uint32_t k1 = 0;
139
140 switch (len & 3) {
141 case 3:
142 k1 ^= tail[2] << 16;
143 [[fallthrough]];
144 case 2:
145 k1 ^= tail[1] << 8;
146 [[fallthrough]];
147 case 1:
148 k1 ^= tail[0];
149 k1 *= c1;
150 k1 = ROTL32(k1, 15);
151 k1 *= c2;
152 h1 ^= k1;
153 };
154
155 //----------
156 // finalization
157
158 h1 ^= len;
159
160 h1 = fmix32(h1);
161
162 *(uint32_t*)out = h1;
163}
164
165//-----------------------------------------------------------------------------
166
167void MurmurHash3_x86_128(const void* key, const int len, uint32_t seed, void* out) {
168 const uint8_t* data = (const uint8_t*)key;
169 const int nblocks = len / 16;
170
171 uint32_t h1 = seed;
172 uint32_t h2 = seed;
173 uint32_t h3 = seed;
174 uint32_t h4 = seed;
175
176 const uint32_t c1 = 0x239b961b;
177 const uint32_t c2 = 0xab0e9789;
178 const uint32_t c3 = 0x38b34ae5;
179 const uint32_t c4 = 0xa1e38b93;
180
181 //----------
182 // body
183
184 const uint32_t* blocks = ((const uint32_t*)key) + nblocks * 4;
185
186 for (int i = -nblocks; i; i++) {
187 uint32_t k1 = getblock32(blocks, i * 4 + 0);
188 uint32_t k2 = getblock32(blocks, i * 4 + 1);
189 uint32_t k3 = getblock32(blocks, i * 4 + 2);
190 uint32_t k4 = getblock32(blocks, i * 4 + 3);
191
192 k1 *= c1;
193 k1 = ROTL32(k1, 15);
194 k1 *= c2;
195 h1 ^= k1;
196
197 h1 = ROTL32(h1, 19);
198 h1 += h2;
199 h1 = h1 * 5 + 0x561ccd1b;
200
201 k2 *= c2;
202 k2 = ROTL32(k2, 16);
203 k2 *= c3;
204 h2 ^= k2;
205
206 h2 = ROTL32(h2, 17);
207 h2 += h3;
208 h2 = h2 * 5 + 0x0bcaa747;
209
210 k3 *= c3;
211 k3 = ROTL32(k3, 17);
212 k3 *= c4;
213 h3 ^= k3;
214
215 h3 = ROTL32(h3, 15);
216 h3 += h4;
217 h3 = h3 * 5 + 0x96cd1c35;
218
219 k4 *= c4;
220 k4 = ROTL32(k4, 18);
221 k4 *= c1;
222 h4 ^= k4;
223
224 h4 = ROTL32(h4, 13);
225 h4 += h1;
226 h4 = h4 * 5 + 0x32ac3b17;
227 }
228
229 //----------
230 // tail
231
232 const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
233
234 uint32_t k1 = 0;
235 uint32_t k2 = 0;
236 uint32_t k3 = 0;
237 uint32_t k4 = 0;
238
239 switch (len & 15) {
240 case 15:
241 k4 ^= tail[14] << 16;
242 [[fallthrough]];
243 case 14:
244 k4 ^= tail[13] << 8;
245 [[fallthrough]];
246 case 13:
247 k4 ^= tail[12] << 0;
248 k4 *= c4;
249 k4 = ROTL32(k4, 18);
250 k4 *= c1;
251 h4 ^= k4;
252 [[fallthrough]];
253
254 case 12:
255 k3 ^= tail[11] << 24;
256 [[fallthrough]];
257 case 11:
258 k3 ^= tail[10] << 16;
259 [[fallthrough]];
260 case 10:
261 k3 ^= tail[9] << 8;
262 [[fallthrough]];
263 case 9:
264 k3 ^= tail[8] << 0;
265 k3 *= c3;
266 k3 = ROTL32(k3, 17);
267 k3 *= c4;
268 h3 ^= k3;
269 [[fallthrough]];
270
271 case 8:
272 k2 ^= tail[7] << 24;
273 [[fallthrough]];
274 case 7:
275 k2 ^= tail[6] << 16;
276 [[fallthrough]];
277 case 6:
278 k2 ^= tail[5] << 8;
279 [[fallthrough]];
280 case 5:
281 k2 ^= tail[4] << 0;
282 k2 *= c2;
283 k2 = ROTL32(k2, 16);
284 k2 *= c3;
285 h2 ^= k2;
286 [[fallthrough]];
287
288 case 4:
289 k1 ^= tail[3] << 24;
290 [[fallthrough]];
291 case 3:
292 k1 ^= tail[2] << 16;
293 [[fallthrough]];
294 case 2:
295 k1 ^= tail[1] << 8;
296 [[fallthrough]];
297 case 1:
298 k1 ^= tail[0] << 0;
299 k1 *= c1;
300 k1 = ROTL32(k1, 15);
301 k1 *= c2;
302 h1 ^= k1;
303 };
304
305 //----------
306 // finalization
307
308 h1 ^= len;
309 h2 ^= len;
310 h3 ^= len;
311 h4 ^= len;
312
313 h1 += h2;
314 h1 += h3;
315 h1 += h4;
316 h2 += h1;
317 h3 += h1;
318 h4 += h1;
319
320 h1 = fmix32(h1);
321 h2 = fmix32(h2);
322 h3 = fmix32(h3);
323 h4 = fmix32(h4);
324
325 h1 += h2;
326 h1 += h3;
327 h1 += h4;
328 h2 += h1;
329 h3 += h1;
330 h4 += h1;
331
332 ((uint32_t*)out)[0] = h1;
333 ((uint32_t*)out)[1] = h2;
334 ((uint32_t*)out)[2] = h3;
335 ((uint32_t*)out)[3] = h4;
336}
337
338//-----------------------------------------------------------------------------
339
340void MurmurHash3_x64_128(const void* key, const int len, const uint32_t seed, void* out) {
341 const uint8_t* data = (const uint8_t*)key;
342 const int nblocks = len / 16;
343
344 uint64_t h1 = seed;
345 uint64_t h2 = seed;
346
347 const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
348 const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
349
350 //----------
351 // body
352
353 const uint64_t* blocks = (const uint64_t*)(key);
354
355 for (int i = 0; i < nblocks; i++) {
356 uint64_t k1 = getblock64(blocks, i * 2 + 0);
357 uint64_t k2 = getblock64(blocks, i * 2 + 1);
358
359 k1 *= c1;
360 k1 = ROTL64(k1, 31);
361 k1 *= c2;
362 h1 ^= k1;
363
364 h1 = ROTL64(h1, 27);
365 h1 += h2;
366 h1 = h1 * 5 + 0x52dce729;
367
368 k2 *= c2;
369 k2 = ROTL64(k2, 33);
370 k2 *= c1;
371 h2 ^= k2;
372
373 h2 = ROTL64(h2, 31);
374 h2 += h1;
375 h2 = h2 * 5 + 0x38495ab5;
376 }
377
378 //----------
379 // tail
380
381 const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
382
383 uint64_t k1 = 0;
384 uint64_t k2 = 0;
385
386 switch (len & 15) {
387 case 15:
388 k2 ^= ((uint64_t)tail[14]) << 48;
389 [[fallthrough]];
390 case 14:
391 k2 ^= ((uint64_t)tail[13]) << 40;
392 [[fallthrough]];
393 case 13:
394 k2 ^= ((uint64_t)tail[12]) << 32;
395 [[fallthrough]];
396 case 12:
397 k2 ^= ((uint64_t)tail[11]) << 24;
398 [[fallthrough]];
399 case 11:
400 k2 ^= ((uint64_t)tail[10]) << 16;
401 [[fallthrough]];
402 case 10:
403 k2 ^= ((uint64_t)tail[9]) << 8;
404 [[fallthrough]];
405 case 9:
406 k2 ^= ((uint64_t)tail[8]) << 0;
407 k2 *= c2;
408 k2 = ROTL64(k2, 33);
409 k2 *= c1;
410 h2 ^= k2;
411 [[fallthrough]];
412
413 case 8:
414 k1 ^= ((uint64_t)tail[7]) << 56;
415 [[fallthrough]];
416 case 7:
417 k1 ^= ((uint64_t)tail[6]) << 48;
418 [[fallthrough]];
419 case 6:
420 k1 ^= ((uint64_t)tail[5]) << 40;
421 [[fallthrough]];
422 case 5:
423 k1 ^= ((uint64_t)tail[4]) << 32;
424 [[fallthrough]];
425 case 4:
426 k1 ^= ((uint64_t)tail[3]) << 24;
427 [[fallthrough]];
428 case 3:
429 k1 ^= ((uint64_t)tail[2]) << 16;
430 [[fallthrough]];
431 case 2:
432 k1 ^= ((uint64_t)tail[1]) << 8;
433 [[fallthrough]];
434 case 1:
435 k1 ^= ((uint64_t)tail[0]) << 0;
436 k1 *= c1;
437 k1 = ROTL64(k1, 31);
438 k1 *= c2;
439 h1 ^= k1;
440 };
441
442 //----------
443 // finalization
444
445 h1 ^= len;
446 h2 ^= len;
447
448 h1 += h2;
449 h2 += h1;
450
451 h1 = fmix64(h1);
452 h2 = fmix64(h2);
453
454 h1 += h2;
455 h2 += h1;
456
457 ((uint64_t*)out)[0] = h1;
458 ((uint64_t*)out)[1] = h2;
459}
460
461//-----------------------------------------------------------------------------