Caffe2 - C++ API
A deep learning, cross platform ML framework
murmur_hash3.cc
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 "caffe2/utils/murmur_hash3.h"
11 
12 //-----------------------------------------------------------------------------
13 // Platform-specific functions and macros
14 
15 // Microsoft Visual Studio
16 
17 #if defined(_MSC_VER)
18 
19 #define FORCE_INLINE __forceinline
20 
21 #define FALLTHROUGH_INTENDED
22 
23 #include <stdlib.h>
24 
25 #define ROTL32(x, y) _rotl(x, y)
26 #define ROTL64(x, y) _rotl64(x, y)
27 
28 #define BIG_CONSTANT(x) (x)
29 
30 // Other compilers
31 
32 #else // defined(_MSC_VER)
33 
34 #define FORCE_INLINE inline __attribute__((__always_inline__))
35 
36 #if defined(__clang__) && defined(__has_cpp_attribute)
37 #if __has_cpp_attribute(clang::fallthrough)
38 #define FALLTHROUGH_INTENDED [[clang::fallthrough]]
39 #endif
40 #elif defined(__GNUC__) && __GNUC__ > 6
41 #define FALLTHROUGH_INTENDED [[gnu::fallthrough]]
42 #endif
43 #ifndef FALLTHROUGH_INTENDED
44 #define FALLTHROUGH_INTENDED
45 #endif
46 
47 inline uint32_t rotl32(uint32_t x, int8_t r) {
48  return (x << r) | (x >> (32 - r));
49 }
50 
51 inline uint64_t rotl64(uint64_t x, int8_t r) {
52  return (x << r) | (x >> (64 - r));
53 }
54 
55 #define ROTL32(x, y) rotl32(x, y)
56 #define ROTL64(x, y) rotl64(x, y)
57 
58 #define BIG_CONSTANT(x) (x##LLU)
59 
60 #endif // !defined(_MSC_VER)
61 
62 //-----------------------------------------------------------------------------
63 // Block read - if your platform needs to do endian-swapping or can only
64 // handle aligned reads, do the conversion here
65 
66 FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) {
67  return p[i];
68 }
69 
70 FORCE_INLINE uint64_t getblock64(const uint64_t* p, int i) {
71  return p[i];
72 }
73 
74 //-----------------------------------------------------------------------------
75 // Finalization mix - force all bits of a hash block to avalanche
76 
77 FORCE_INLINE uint32_t fmix32(uint32_t h) {
78  h ^= h >> 16;
79  h *= 0x85ebca6b;
80  h ^= h >> 13;
81  h *= 0xc2b2ae35;
82  h ^= h >> 16;
83 
84  return h;
85 }
86 
87 //----------
88 
89 FORCE_INLINE uint64_t fmix64(uint64_t k) {
90  k ^= k >> 33;
91  k *= BIG_CONSTANT(0xff51afd7ed558ccd);
92  k ^= k >> 33;
93  k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
94  k ^= k >> 33;
95 
96  return k;
97 }
98 
99 namespace caffe2 {
100 
101 void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out) {
102  const uint8_t* data = (const uint8_t*)key;
103  const int nblocks = len / 4;
104 
105  uint32_t h1 = seed;
106 
107  const uint32_t c1 = 0xcc9e2d51;
108  const uint32_t c2 = 0x1b873593;
109 
110  //----------
111  // body
112 
113  const uint32_t* blocks = (const uint32_t*)(data + nblocks * 4);
114 
115  for (int i = -nblocks; i; i++) {
116  uint32_t k1 = getblock32(blocks, i);
117 
118  k1 *= c1;
119  k1 = ROTL32(k1, 15);
120  k1 *= c2;
121 
122  h1 ^= k1;
123  h1 = ROTL32(h1, 13);
124  h1 = h1 * 5 + 0xe6546b64;
125  }
126 
127  //----------
128  // tail
129 
130  const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
131 
132  uint32_t k1 = 0;
133 
134  switch (len & 3) {
135  case 3:
136  k1 ^= tail[2] << 16;
137  FALLTHROUGH_INTENDED;
138  case 2:
139  k1 ^= tail[1] << 8;
140  FALLTHROUGH_INTENDED;
141  case 1:
142  k1 ^= tail[0];
143  k1 *= c1;
144  k1 = ROTL32(k1, 15);
145  k1 *= c2;
146  h1 ^= k1;
147  };
148 
149  //----------
150  // finalization
151 
152  h1 ^= len;
153 
154  h1 = fmix32(h1);
155 
156  *(uint32_t*)out = h1;
157 }
158 
159 //-----------------------------------------------------------------------------
160 
161 void MurmurHash3_x86_128(
162  const void* key,
163  const int len,
164  uint32_t seed,
165  void* out) {
166  const uint8_t* data = (const uint8_t*)key;
167  const int nblocks = len / 16;
168 
169  uint32_t h1 = seed;
170  uint32_t h2 = seed;
171  uint32_t h3 = seed;
172  uint32_t h4 = seed;
173 
174  const uint32_t c1 = 0x239b961b;
175  const uint32_t c2 = 0xab0e9789;
176  const uint32_t c3 = 0x38b34ae5;
177  const uint32_t c4 = 0xa1e38b93;
178 
179  //----------
180  // body
181 
182  const uint32_t* blocks = (const uint32_t*)(data + nblocks * 16);
183 
184  for (int i = -nblocks; i; i++) {
185  uint32_t k1 = getblock32(blocks, i * 4 + 0);
186  uint32_t k2 = getblock32(blocks, i * 4 + 1);
187  uint32_t k3 = getblock32(blocks, i * 4 + 2);
188  uint32_t k4 = getblock32(blocks, i * 4 + 3);
189 
190  k1 *= c1;
191  k1 = ROTL32(k1, 15);
192  k1 *= c2;
193  h1 ^= k1;
194 
195  h1 = ROTL32(h1, 19);
196  h1 += h2;
197  h1 = h1 * 5 + 0x561ccd1b;
198 
199  k2 *= c2;
200  k2 = ROTL32(k2, 16);
201  k2 *= c3;
202  h2 ^= k2;
203 
204  h2 = ROTL32(h2, 17);
205  h2 += h3;
206  h2 = h2 * 5 + 0x0bcaa747;
207 
208  k3 *= c3;
209  k3 = ROTL32(k3, 17);
210  k3 *= c4;
211  h3 ^= k3;
212 
213  h3 = ROTL32(h3, 15);
214  h3 += h4;
215  h3 = h3 * 5 + 0x96cd1c35;
216 
217  k4 *= c4;
218  k4 = ROTL32(k4, 18);
219  k4 *= c1;
220  h4 ^= k4;
221 
222  h4 = ROTL32(h4, 13);
223  h4 += h1;
224  h4 = h4 * 5 + 0x32ac3b17;
225  }
226 
227  //----------
228  // tail
229 
230  const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
231 
232  uint32_t k1 = 0;
233  uint32_t k2 = 0;
234  uint32_t k3 = 0;
235  uint32_t k4 = 0;
236 
237  switch (len & 15) {
238  case 15:
239  k4 ^= tail[14] << 16;
240  FALLTHROUGH_INTENDED;
241  case 14:
242  k4 ^= tail[13] << 8;
243  FALLTHROUGH_INTENDED;
244  case 13:
245  k4 ^= tail[12] << 0;
246  k4 *= c4;
247  k4 = ROTL32(k4, 18);
248  k4 *= c1;
249  h4 ^= k4;
250  FALLTHROUGH_INTENDED;
251 
252  case 12:
253  k3 ^= tail[11] << 24;
254  FALLTHROUGH_INTENDED;
255  case 11:
256  k3 ^= tail[10] << 16;
257  FALLTHROUGH_INTENDED;
258  case 10:
259  k3 ^= tail[9] << 8;
260  FALLTHROUGH_INTENDED;
261  case 9:
262  k3 ^= tail[8] << 0;
263  k3 *= c3;
264  k3 = ROTL32(k3, 17);
265  k3 *= c4;
266  h3 ^= k3;
267  FALLTHROUGH_INTENDED;
268 
269  case 8:
270  k2 ^= tail[7] << 24;
271  FALLTHROUGH_INTENDED;
272  case 7:
273  k2 ^= tail[6] << 16;
274  FALLTHROUGH_INTENDED;
275  case 6:
276  k2 ^= tail[5] << 8;
277  FALLTHROUGH_INTENDED;
278  case 5:
279  k2 ^= tail[4] << 0;
280  k2 *= c2;
281  k2 = ROTL32(k2, 16);
282  k2 *= c3;
283  h2 ^= k2;
284  FALLTHROUGH_INTENDED;
285 
286  case 4:
287  k1 ^= tail[3] << 24;
288  FALLTHROUGH_INTENDED;
289  case 3:
290  k1 ^= tail[2] << 16;
291  FALLTHROUGH_INTENDED;
292  case 2:
293  k1 ^= tail[1] << 8;
294  FALLTHROUGH_INTENDED;
295  case 1:
296  k1 ^= tail[0] << 0;
297  k1 *= c1;
298  k1 = ROTL32(k1, 15);
299  k1 *= c2;
300  h1 ^= k1;
301  };
302 
303  //----------
304  // finalization
305 
306  h1 ^= len;
307  h2 ^= len;
308  h3 ^= len;
309  h4 ^= len;
310 
311  h1 += h2;
312  h1 += h3;
313  h1 += h4;
314  h2 += h1;
315  h3 += h1;
316  h4 += h1;
317 
318  h1 = fmix32(h1);
319  h2 = fmix32(h2);
320  h3 = fmix32(h3);
321  h4 = fmix32(h4);
322 
323  h1 += h2;
324  h1 += h3;
325  h1 += h4;
326  h2 += h1;
327  h3 += h1;
328  h4 += h1;
329 
330  ((uint32_t*)out)[0] = h1;
331  ((uint32_t*)out)[1] = h2;
332  ((uint32_t*)out)[2] = h3;
333  ((uint32_t*)out)[3] = h4;
334 }
335 
336 //-----------------------------------------------------------------------------
337 
338 void MurmurHash3_x64_128(
339  const void* key,
340  const int len,
341  const uint32_t seed,
342  void* out) {
343  const uint8_t* data = (const uint8_t*)key;
344  const int nblocks = len / 16;
345 
346  uint64_t h1 = seed;
347  uint64_t h2 = seed;
348 
349  const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
350  const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
351 
352  //----------
353  // body
354 
355  const uint64_t* blocks = (const uint64_t*)(data);
356 
357  for (int i = 0; i < nblocks; i++) {
358  uint64_t k1 = getblock64(blocks, i * 2 + 0);
359  uint64_t k2 = getblock64(blocks, i * 2 + 1);
360 
361  k1 *= c1;
362  k1 = ROTL64(k1, 31);
363  k1 *= c2;
364  h1 ^= k1;
365 
366  h1 = ROTL64(h1, 27);
367  h1 += h2;
368  h1 = h1 * 5 + 0x52dce729;
369 
370  k2 *= c2;
371  k2 = ROTL64(k2, 33);
372  k2 *= c1;
373  h2 ^= k2;
374 
375  h2 = ROTL64(h2, 31);
376  h2 += h1;
377  h2 = h2 * 5 + 0x38495ab5;
378  }
379 
380  //----------
381  // tail
382 
383  const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
384 
385  uint64_t k1 = 0;
386  uint64_t k2 = 0;
387 
388  switch (len & 15) {
389  case 15:
390  k2 ^= ((uint64_t)tail[14]) << 48;
391  FALLTHROUGH_INTENDED;
392  case 14:
393  k2 ^= ((uint64_t)tail[13]) << 40;
394  FALLTHROUGH_INTENDED;
395  case 13:
396  k2 ^= ((uint64_t)tail[12]) << 32;
397  FALLTHROUGH_INTENDED;
398  case 12:
399  k2 ^= ((uint64_t)tail[11]) << 24;
400  FALLTHROUGH_INTENDED;
401  case 11:
402  k2 ^= ((uint64_t)tail[10]) << 16;
403  FALLTHROUGH_INTENDED;
404  case 10:
405  k2 ^= ((uint64_t)tail[9]) << 8;
406  FALLTHROUGH_INTENDED;
407  case 9:
408  k2 ^= ((uint64_t)tail[8]) << 0;
409  k2 *= c2;
410  k2 = ROTL64(k2, 33);
411  k2 *= c1;
412  h2 ^= k2;
413  FALLTHROUGH_INTENDED;
414 
415  case 8:
416  k1 ^= ((uint64_t)tail[7]) << 56;
417  FALLTHROUGH_INTENDED;
418  case 7:
419  k1 ^= ((uint64_t)tail[6]) << 48;
420  FALLTHROUGH_INTENDED;
421  case 6:
422  k1 ^= ((uint64_t)tail[5]) << 40;
423  FALLTHROUGH_INTENDED;
424  case 5:
425  k1 ^= ((uint64_t)tail[4]) << 32;
426  FALLTHROUGH_INTENDED;
427  case 4:
428  k1 ^= ((uint64_t)tail[3]) << 24;
429  FALLTHROUGH_INTENDED;
430  case 3:
431  k1 ^= ((uint64_t)tail[2]) << 16;
432  FALLTHROUGH_INTENDED;
433  case 2:
434  k1 ^= ((uint64_t)tail[1]) << 8;
435  FALLTHROUGH_INTENDED;
436  case 1:
437  k1 ^= ((uint64_t)tail[0]) << 0;
438  k1 *= c1;
439  k1 = ROTL64(k1, 31);
440  k1 *= c2;
441  h1 ^= k1;
442  };
443 
444  //----------
445  // finalization
446 
447  h1 ^= len;
448  h2 ^= len;
449 
450  h1 += h2;
451  h2 += h1;
452 
453  h1 = fmix64(h1);
454  h2 = fmix64(h2);
455 
456  h1 += h2;
457  h2 += h1;
458 
459  ((uint64_t*)out)[0] = h1;
460  ((uint64_t*)out)[1] = h2;
461 }
462 
463 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13