ATLAS Offline Software
Loading...
Searching...
No Matches
MurmurHash2.cxx
Go to the documentation of this file.
1/*
2 * Public domain; see below.
3 */
12
13
14//-----------------------------------------------------------------------------
15// MurmurHash2 was written by Austin Appleby, and is placed in the public
16// domain. The author hereby disclaims copyright to this source code.
17
18// Note - This code makes a few assumptions about how your machine behaves -
19
20// 1. We can read a 4-byte value from any address without crashing
21// 2. sizeof(int) == 4
22
23// And it has a few limitations -
24
25// 1. It will not work incrementally.
26// 2. It will not produce the same results on little-endian and big-endian
27// machines.
28
30
31//-----------------------------------------------------------------------------
32// Platform-specific functions and macros
33
34#define BIG_CONSTANT(x) (x##LLU)
35
36//-----------------------------------------------------------------------------
37
38
39namespace CxxUtils {
40
41
42uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
43{
44 // 'm' and 'r' are mixing constants generated offline.
45 // They're not really 'magic', they just happen to work well.
46
47 const uint32_t m = 0x5bd1e995;
48 const int r = 24;
49
50 // Initialize the hash to a 'random' value
51
52 uint32_t h = seed ^ len;
53
54 // Mix 4 bytes at a time into the hash
55
56 const unsigned char * data = (const unsigned char *)key;
57
58 while(len >= 4)
59 {
60 uint32_t k = *reinterpret_cast<const uint32_t*>(data);
61
62 k *= m;
63 k ^= k >> r;
64 k *= m;
65
66 h *= m;
67 h ^= k;
68
69 data += 4;
70 len -= 4;
71 }
72
73 // Handle the last few bytes of the input array
74
75 switch(len)
76 {
77 case 3: h ^= data[2] << 16;
78 // FALLTHROUGH
79 case 2: h ^= data[1] << 8;
80 // FALLTHROUGH
81 case 1: h ^= data[0];
82 h *= m;
83 };
84
85 // Do a few final mixes of the hash to ensure the last few
86 // bytes are well-incorporated.
87
88 h ^= h >> 13;
89 h *= m;
90 h ^= h >> 15;
91
92 return h;
93}
94
95//-----------------------------------------------------------------------------
96// MurmurHash2, 64-bit versions, by Austin Appleby
97
98// The same caveats as 32-bit MurmurHash2 apply here - beware of alignment
99// and endian-ness issues if used across multiple platforms.
100
101// 64-bit hash for 64-bit platforms
102
103uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed )
104{
105 const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995);
106 const int r = 47;
107
108 uint64_t h = seed ^ (len * m);
109
110 const uint64_t * data = (const uint64_t *)key;
111 const uint64_t * end = data + (len/8);
112
113 while(data != end)
114 {
115 uint64_t k = *data++;
116
117 k *= m;
118 k ^= k >> r;
119 k *= m;
120
121 h ^= k;
122 h *= m;
123 }
124
125 const unsigned char * data2 = reinterpret_cast<const unsigned char*>(data);
126
127 switch(len & 7)
128 {
129 case 7: h ^= uint64_t(data2[6]) << 48;
130 // FALLTHROUGH
131 case 6: h ^= uint64_t(data2[5]) << 40;
132 // FALLTHROUGH
133 case 5: h ^= uint64_t(data2[4]) << 32;
134 // FALLTHROUGH
135 case 4: h ^= uint64_t(data2[3]) << 24;
136 // FALLTHROUGH
137 case 3: h ^= uint64_t(data2[2]) << 16;
138 // FALLTHROUGH
139 case 2: h ^= uint64_t(data2[1]) << 8;
140 // FALLTHROUGH
141 case 1: h ^= uint64_t(data2[0]);
142 h *= m;
143 };
144
145 h ^= h >> r;
146 h *= m;
147 h ^= h >> r;
148
149 return h;
150}
151
152
153// 64-bit hash for 32-bit platforms
154
155uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed )
156{
157 const uint32_t m = 0x5bd1e995;
158 const int r = 24;
159
160 uint32_t h1 = uint32_t(seed) ^ len;
161 uint32_t h2 = uint32_t(seed >> 32);
162
163 const uint32_t * data = (const uint32_t *)key;
164
165 while(len >= 8)
166 {
167 uint32_t k1 = *data++;
168 k1 *= m; k1 ^= k1 >> r; k1 *= m;
169 h1 *= m; h1 ^= k1;
170 len -= 4;
171
172 uint32_t k2 = *data++;
173 k2 *= m; k2 ^= k2 >> r; k2 *= m;
174 h2 *= m; h2 ^= k2;
175 len -= 4;
176 }
177
178 if(len >= 4)
179 {
180 uint32_t k1 = *data++;
181 k1 *= m; k1 ^= k1 >> r; k1 *= m;
182 h1 *= m; h1 ^= k1;
183 len -= 4;
184 }
185
186 switch(len)
187 {
188 case 3: h2 ^= (reinterpret_cast<unsigned const char*>(data))[2] << 16;
189 // FALLTHROUGH
190 case 2: h2 ^= (reinterpret_cast<unsigned const char*>(data))[1] << 8;
191 // FALLTHROUGH
192 case 1: h2 ^= (reinterpret_cast<unsigned const char*>(data))[0];
193 h2 *= m;
194 };
195
196 h1 ^= h2 >> 18; h1 *= m;
197 h2 ^= h1 >> 22; h2 *= m;
198 h1 ^= h2 >> 17; h1 *= m;
199 h2 ^= h1 >> 19; h2 *= m;
200
201 uint64_t h = h1;
202
203 h = (h << 32) | h2;
204
205 return h;
206}
207
208//-----------------------------------------------------------------------------
209// MurmurHash2A, by Austin Appleby
210
211// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
212// construction. Bulk speed should be identical to Murmur2, small-key speed
213// will be 10%-20% slower due to the added overhead at the end of the hash.
214
215// This variant fixes a minor issue where null keys were more likely to
216// collide with each other than expected, and also makes the function
217// more amenable to incremental implementations.
218
219
220uint32_t MurmurHash2A ( const void * key, int len, uint32_t seed )
221{
222 const uint32_t M = 0x5bd1e995;
223 const int R = 24;
224 uint32_t l = len;
225
226 const unsigned char * data = (const unsigned char *)key;
227
228 uint32_t h = seed;
229
230 while(len >= 4)
231 {
232 uint32_t k = *reinterpret_cast<const uint32_t*>(data);
233
235
236 data += 4;
237 len -= 4;
238 }
239
240 uint32_t t = 0;
241
242 switch(len)
243 {
244 case 3: t ^= data[2] << 16;
245 // FALLTHROUGH
246 case 2: t ^= data[1] << 8;
247 // FALLTHROUGH
248 case 1: t ^= data[0];
249 };
250
253
254 h ^= h >> 13;
255 h *= M;
256 h ^= h >> 15;
257
258 return h;
259}
260
261//-----------------------------------------------------------------------------
262// MurmurHashNeutral2, by Austin Appleby
263
264// Same as MurmurHash2, but endian- and alignment-neutral.
265// Half the speed though, alas.
266
267uint32_t MurmurHashNeutral2 ( const void * key, int len, uint32_t seed )
268{
269 const uint32_t m = 0x5bd1e995;
270 const int r = 24;
271
272 uint32_t h = seed ^ len;
273
274 const unsigned char * data = (const unsigned char *)key;
275
276 while(len >= 4)
277 {
278 uint32_t k;
279
280 k = data[0];
281 k |= data[1] << 8;
282 k |= data[2] << 16;
283 k |= data[3] << 24;
284
285 k *= m;
286 k ^= k >> r;
287 k *= m;
288
289 h *= m;
290 h ^= k;
291
292 data += 4;
293 len -= 4;
294 }
295
296 switch(len)
297 {
298 case 3: h ^= data[2] << 16;
299 // FALLTHROUGH
300 case 2: h ^= data[1] << 8;
301 // FALLTHROUGH
302 case 1: h ^= data[0];
303 h *= m;
304 };
305
306 h ^= h >> 13;
307 h *= m;
308 h ^= h >> 15;
309
310 return h;
311}
312
313//-----------------------------------------------------------------------------
314// MurmurHashAligned2, by Austin Appleby
315
316// Same algorithm as MurmurHash2, but only does aligned reads - should be safer
317// on certain platforms.
318
319// Performance will be lower than MurmurHash2
320
321#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
322
323
324uint32_t MurmurHashAligned2 ( const void * key, int len, uint32_t seed )
325{
326 const uint32_t m = 0x5bd1e995;
327 const int r = 24;
328
329 const unsigned char * data = (const unsigned char *)key;
330
331 uint32_t h = seed ^ len;
332
333 int align = (uint64_t)data & 3;
334
335 if(align && (len >= 4))
336 {
337 // Pre-load the temp registers
338
339 uint32_t t = 0, d = 0;
340
341 switch(align)
342 {
343 case 1: t |= data[2] << 16;
344 // FALLTHROUGH
345 case 2: t |= data[1] << 8;
346 // FALLTHROUGH
347 case 3: t |= data[0];
348 }
349
350 t <<= (8 * align);
351
352 data += 4-align;
353 len -= 4-align;
354
355 int sl = 8 * (4-align);
356 int sr = 8 * align;
357
358 // Mix
359
360 while(len >= 4)
361 {
362 d = *reinterpret_cast<const uint32_t *>(data);
363 t = (t >> sr) | (d << sl);
364
365 uint32_t k = t;
366
367 MIX(h,k,m);
368
369 t = d;
370
371 data += 4;
372 len -= 4;
373 }
374
375 // Handle leftover data in temp registers
376
377 d = 0;
378
379 if(len >= align)
380 {
381 switch(align)
382 {
383 case 3: d |= data[2] << 16;
384 // FALLTHROUGH
385 case 2: d |= data[1] << 8;
386 // FALLTHROUGH
387 case 1: d |= data[0];
388 }
389
390 uint32_t k = (t >> sr) | (d << sl);
391 MIX(h,k,m);
392
393 // At this point, we know that len < 4 and align > 0.
394 data += align;
395 len -= align;
396 // So here, we must have 0 >= len < 3.
397
398 //----------
399 // Handle tail bytes
400
401 switch(len)
402 {
403 // can't happen --- see above.
404 //case 3: h ^= data[2] << 16;
405 // FALLTHROUGH
406 case 2: h ^= data[1] << 8;
407 // FALLTHROUGH
408 case 1: h ^= data[0];
409 h *= m;
410 };
411 }
412 else
413 {
414 switch(len)
415 {
416 // len cannot be 3, because align is at most 3.
417 //case 3: d |= data[2] << 16;
418 // FALLTHROUGH
419 case 2: d |= data[1] << 8;
420 // FALLTHROUGH
421 case 1: d |= data[0];
422 // FALLTHROUGH
423 case 0: h ^= (t >> sr) | (d << sl);
424 h *= m;
425 }
426 }
427
428 h ^= h >> 13;
429 h *= m;
430 h ^= h >> 15;
431
432 return h;
433 }
434 else
435 {
436 while(len >= 4)
437 {
438 uint32_t k = *reinterpret_cast<const uint32_t *>(data);
439
440 MIX(h,k,m);
441
442 data += 4;
443 len -= 4;
444 }
445
446 //----------
447 // Handle tail bytes
448
449 switch(len)
450 {
451 case 3: h ^= data[2] << 16;
452 // FALLTHROUGH
453 case 2: h ^= data[1] << 8;
454 // FALLTHROUGH
455 case 1: h ^= data[0];
456 h *= m;
457 };
458
459 h ^= h >> 13;
460 h *= m;
461 h ^= h >> 15;
462
463 return h;
464 }
465}
466
467//-----------------------------------------------------------------------------
468
469
470} // namespace CxxUtils
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
#define MIX(h, k, m)
#define BIG_CONSTANT(x)
Implementation of MurmurHash2.
#define MurmurHash_mmix(h, k)
Definition MurmurHash2.h:29
Header file for AthHistogramAlgorithm.
int r
Definition globals.cxx:22
uint32_t MurmurHash2A(const void *key, int len, uint32_t seed)
uint32_t MurmurHash2(const void *key, int len, uint32_t seed)
auto end(range_with_at< T > &s)
uint64_t MurmurHash64B(const void *key, int len, uint64_t seed)
uint32_t MurmurHashAligned2(const void *key, int len, uint32_t seed)
uint32_t MurmurHashNeutral2(const void *key, int len, uint32_t seed)
uint64_t MurmurHash64A(const void *key, int len, uint64_t seed)