NeoPZ
MurmurHash3.cpp
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // MurmurHash3 was written by Austin Appleby, and is placed in the public
3 // domain. The author hereby disclaims copyright to this source code.
4 
5 // Note - The x86 and x64 versions do _not_ produce the same results, as the
6 // algorithms are optimized for their respective platforms. You can still
7 // compile and run any of them on any platform, but your performance with the
8 // non-native version will be less than optimal.
9 
10 #include "MurmurHash3.h"
11 #include <string>
12 
13 //-----------------------------------------------------------------------------
14 // Platform-specific functions and macros
15 
16 // Microsoft Visual Studio
17 
18 #if defined(_MSC_VER)
19 
20 #define FORCE_INLINE __forceinline
21 
22 #include <stdlib.h>
23 
24 #define ROTL32(x,y) _rotl(x,y)
25 #define ROTL64(x,y) _rotl64(x,y)
26 
27 #define BIG_CONSTANT(x) (x)
28 
29 // Other compilers
30 
31 #else // defined(_MSC_VER)
32 
33 #define FORCE_INLINE inline __attribute__((always_inline))
34 
35 inline uint32_t rotl32(uint32_t x, int8_t r) {
36  return (x << r) | (x >> (32 - r));
37 }
38 
39 inline uint64_t rotl64(uint64_t x, int8_t r) {
40  return (x << r) | (x >> (64 - r));
41 }
42 
43 #define ROTL32(x,y) rotl32(x,y)
44 #define ROTL64(x,y) rotl64(x,y)
45 
46 #define BIG_CONSTANT(x) (x##LLU)
47 
48 #endif // !defined(_MSC_VER)
49 
50 //-----------------------------------------------------------------------------
51 // Block read - if your platform needs to do endian-swapping or can only
52 // handle aligned reads, do the conversion here
53 
54 FORCE_INLINE uint32_t getblock32(const uint32_t * p, int i) {
55  return p[i];
56 }
57 
58 FORCE_INLINE uint64_t getblock64(const uint64_t * p, int i) {
59  return p[i];
60 }
61 
62 //-----------------------------------------------------------------------------
63 // Finalization mix - force all bits of a hash block to avalanche
64 
65 FORCE_INLINE uint32_t fmix32(uint32_t h) {
66  h ^= h >> 16;
67  h *= 0x85ebca6b;
68  h ^= h >> 13;
69  h *= 0xc2b2ae35;
70  h ^= h >> 16;
71 
72  return h;
73 }
74 
75 //----------
76 
77 FORCE_INLINE uint64_t fmix64(uint64_t k) {
78  k ^= k >> 33;
79  k *= BIG_CONSTANT(0xff51afd7ed558ccd);
80  k ^= k >> 33;
81  k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
82  k ^= k >> 33;
83 
84  return k;
85 }
86 
87 //-----------------------------------------------------------------------------
88 
89 void MurmurHash3_x86_32(const void * key, int len,
90  uint32_t seed, void * out) {
91  const uint8_t * data = (const uint8_t*) key;
92  const int nblocks = len / 4;
93 
94  uint32_t h1 = seed;
95 
96  const uint32_t c1 = 0xcc9e2d51;
97  const uint32_t c2 = 0x1b873593;
98 
99  //----------
100  // body
101 
102  const uint32_t * blocks = (const uint32_t *) (data + nblocks * 4);
103 
104  for (int i = -nblocks; i; i++) {
105  uint32_t k1 = getblock32(blocks, i);
106 
107  k1 *= c1;
108  k1 = ROTL32(k1, 15);
109  k1 *= c2;
110 
111  h1 ^= k1;
112  h1 = ROTL32(h1, 13);
113  h1 = h1 * 5 + 0xe6546b64;
114  }
115 
116  //----------
117  // tail
118 
119  const uint8_t * tail = (const uint8_t*) (data + nblocks * 4);
120 
121  uint32_t k1 = 0;
122 
123  switch (len & 3) {
124  case 3: k1 ^= tail[2] << 16;
125  case 2: k1 ^= tail[1] << 8;
126  case 1: k1 ^= tail[0];
127  k1 *= c1;
128  k1 = ROTL32(k1, 15);
129  k1 *= c2;
130  h1 ^= k1;
131  };
132 
133  //----------
134  // finalization
135 
136  h1 ^= len;
137 
138  h1 = fmix32(h1);
139 
140  *(uint32_t*) out = h1;
141 }
142 
143 //-----------------------------------------------------------------------------
144 
145 void MurmurHash3_x86_128(const void * key, const int len,
146  uint32_t seed, void * out) {
147  const uint8_t * data = (const uint8_t*) key;
148  const int nblocks = len / 16;
149 
150  uint32_t h1 = seed;
151  uint32_t h2 = seed;
152  uint32_t h3 = seed;
153  uint32_t h4 = seed;
154 
155  const uint32_t c1 = 0x239b961b;
156  const uint32_t c2 = 0xab0e9789;
157  const uint32_t c3 = 0x38b34ae5;
158  const uint32_t c4 = 0xa1e38b93;
159 
160  //----------
161  // body
162 
163  const uint32_t * blocks = (const uint32_t *) (data + nblocks * 16);
164 
165  for (int i = -nblocks; i; i++) {
166  uint32_t k1 = getblock32(blocks, i * 4 + 0);
167  uint32_t k2 = getblock32(blocks, i * 4 + 1);
168  uint32_t k3 = getblock32(blocks, i * 4 + 2);
169  uint32_t k4 = getblock32(blocks, i * 4 + 3);
170 
171  k1 *= c1;
172  k1 = ROTL32(k1, 15);
173  k1 *= c2;
174  h1 ^= k1;
175 
176  h1 = ROTL32(h1, 19);
177  h1 += h2;
178  h1 = h1 * 5 + 0x561ccd1b;
179 
180  k2 *= c2;
181  k2 = ROTL32(k2, 16);
182  k2 *= c3;
183  h2 ^= k2;
184 
185  h2 = ROTL32(h2, 17);
186  h2 += h3;
187  h2 = h2 * 5 + 0x0bcaa747;
188 
189  k3 *= c3;
190  k3 = ROTL32(k3, 17);
191  k3 *= c4;
192  h3 ^= k3;
193 
194  h3 = ROTL32(h3, 15);
195  h3 += h4;
196  h3 = h3 * 5 + 0x96cd1c35;
197 
198  k4 *= c4;
199  k4 = ROTL32(k4, 18);
200  k4 *= c1;
201  h4 ^= k4;
202 
203  h4 = ROTL32(h4, 13);
204  h4 += h1;
205  h4 = h4 * 5 + 0x32ac3b17;
206  }
207 
208  //----------
209  // tail
210 
211  const uint8_t * tail = (const uint8_t*) (data + nblocks * 16);
212 
213  uint32_t k1 = 0;
214  uint32_t k2 = 0;
215  uint32_t k3 = 0;
216  uint32_t k4 = 0;
217 
218  switch (len & 15) {
219  case 15: k4 ^= tail[14] << 16;
220  case 14: k4 ^= tail[13] << 8;
221  case 13: k4 ^= tail[12] << 0;
222  k4 *= c4;
223  k4 = ROTL32(k4, 18);
224  k4 *= c1;
225  h4 ^= k4;
226 
227  case 12: k3 ^= tail[11] << 24;
228  case 11: k3 ^= tail[10] << 16;
229  case 10: k3 ^= tail[ 9] << 8;
230  case 9: k3 ^= tail[ 8] << 0;
231  k3 *= c3;
232  k3 = ROTL32(k3, 17);
233  k3 *= c4;
234  h3 ^= k3;
235 
236  case 8: k2 ^= tail[ 7] << 24;
237  case 7: k2 ^= tail[ 6] << 16;
238  case 6: k2 ^= tail[ 5] << 8;
239  case 5: k2 ^= tail[ 4] << 0;
240  k2 *= c2;
241  k2 = ROTL32(k2, 16);
242  k2 *= c3;
243  h2 ^= k2;
244 
245  case 4: k1 ^= tail[ 3] << 24;
246  case 3: k1 ^= tail[ 2] << 16;
247  case 2: k1 ^= tail[ 1] << 8;
248  case 1: k1 ^= tail[ 0] << 0;
249  k1 *= c1;
250  k1 = ROTL32(k1, 15);
251  k1 *= c2;
252  h1 ^= k1;
253  };
254 
255  //----------
256  // finalization
257 
258  h1 ^= len;
259  h2 ^= len;
260  h3 ^= len;
261  h4 ^= len;
262 
263  h1 += h2;
264  h1 += h3;
265  h1 += h4;
266  h2 += h1;
267  h3 += h1;
268  h4 += h1;
269 
270  h1 = fmix32(h1);
271  h2 = fmix32(h2);
272  h3 = fmix32(h3);
273  h4 = fmix32(h4);
274 
275  h1 += h2;
276  h1 += h3;
277  h1 += h4;
278  h2 += h1;
279  h3 += h1;
280  h4 += h1;
281 
282  ((uint32_t*) out)[0] = h1;
283  ((uint32_t*) out)[1] = h2;
284  ((uint32_t*) out)[2] = h3;
285  ((uint32_t*) out)[3] = h4;
286 }
287 
288 //-----------------------------------------------------------------------------
289 
290 void MurmurHash3_x64_128(const void * key, const int len,
291  const uint32_t seed, void * out) {
292  const uint8_t * data = (const uint8_t*) key;
293  const int nblocks = len / 16;
294 
295  uint64_t h1 = seed;
296  uint64_t h2 = seed;
297 
298  const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
299  const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
300 
301  //----------
302  // body
303 
304  const uint64_t * blocks = (const uint64_t *) (data);
305 
306  for (int i = 0; i < nblocks; i++) {
307  uint64_t k1 = getblock64(blocks, i * 2 + 0);
308  uint64_t k2 = getblock64(blocks, i * 2 + 1);
309 
310  k1 *= c1;
311  k1 = ROTL64(k1, 31);
312  k1 *= c2;
313  h1 ^= k1;
314 
315  h1 = ROTL64(h1, 27);
316  h1 += h2;
317  h1 = h1 * 5 + 0x52dce729;
318 
319  k2 *= c2;
320  k2 = ROTL64(k2, 33);
321  k2 *= c1;
322  h2 ^= k2;
323 
324  h2 = ROTL64(h2, 31);
325  h2 += h1;
326  h2 = h2 * 5 + 0x38495ab5;
327  }
328 
329  //----------
330  // tail
331 
332  const uint8_t * tail = (const uint8_t*) (data + nblocks * 16);
333 
334  uint64_t k1 = 0;
335  uint64_t k2 = 0;
336 
337  switch (len & 15) {
338  case 15: k2 ^= ((uint64_t) tail[14]) << 48;
339  case 14: k2 ^= ((uint64_t) tail[13]) << 40;
340  case 13: k2 ^= ((uint64_t) tail[12]) << 32;
341  case 12: k2 ^= ((uint64_t) tail[11]) << 24;
342  case 11: k2 ^= ((uint64_t) tail[10]) << 16;
343  case 10: k2 ^= ((uint64_t) tail[ 9]) << 8;
344  case 9: k2 ^= ((uint64_t) tail[ 8]) << 0;
345  k2 *= c2;
346  k2 = ROTL64(k2, 33);
347  k2 *= c1;
348  h2 ^= k2;
349 
350  case 8: k1 ^= ((uint64_t) tail[ 7]) << 56;
351  case 7: k1 ^= ((uint64_t) tail[ 6]) << 48;
352  case 6: k1 ^= ((uint64_t) tail[ 5]) << 40;
353  case 5: k1 ^= ((uint64_t) tail[ 4]) << 32;
354  case 4: k1 ^= ((uint64_t) tail[ 3]) << 24;
355  case 3: k1 ^= ((uint64_t) tail[ 2]) << 16;
356  case 2: k1 ^= ((uint64_t) tail[ 1]) << 8;
357  case 1: k1 ^= ((uint64_t) tail[ 0]) << 0;
358  k1 *= c1;
359  k1 = ROTL64(k1, 31);
360  k1 *= c2;
361  h1 ^= k1;
362  };
363 
364  //----------
365  // finalization
366 
367  h1 ^= len;
368  h2 ^= len;
369 
370  h1 += h2;
371  h2 += h1;
372 
373  h1 = fmix64(h1);
374  h2 = fmix64(h2);
375 
376  h1 += h2;
377  h2 += h1;
378 
379  ((uint64_t*) out)[0] = h1;
380  ((uint64_t*) out)[1] = h2;
381 }
382 
383 //-----------------------------------------------------------------------------
FORCE_INLINE uint32_t getblock32(const uint32_t *p, int i)
Definition: MurmurHash3.cpp:54
#define FORCE_INLINE
Definition: MurmurHash3.cpp:33
FORCE_INLINE uint32_t fmix32(uint32_t h)
Definition: MurmurHash3.cpp:65
void MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, void *out)
void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
Definition: MurmurHash3.cpp:89
clarg::argBool h("-h", "help message", false)
FORCE_INLINE uint64_t getblock64(const uint64_t *p, int i)
Definition: MurmurHash3.cpp:58
uint64_t rotl64(uint64_t x, int8_t r)
Definition: MurmurHash3.cpp:39
#define BIG_CONSTANT(x)
Definition: MurmurHash3.cpp:46
FORCE_INLINE uint64_t fmix64(uint64_t k)
Definition: MurmurHash3.cpp:77
#define ROTL64(x, y)
Definition: MurmurHash3.cpp:44
#define ROTL32(x, y)
Definition: MurmurHash3.cpp:43
void MurmurHash3_x64_128(const void *key, const int len, const uint32_t seed, void *out)
uint32_t rotl32(uint32_t x, int8_t r)
Definition: MurmurHash3.cpp:35