A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
hash-murmur3.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2012 Lawrence Livermore National Laboratory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
19  *
20  * This copyright notice applies strictly to the wrapper material.
21  *
22  * The murmur3 source code itself is in the public domain. The murmur3 source
23  * code sections are marked by
24  * // Begin <murmur3-file> ---->
25  * and
26  * // End <murmur3-file> ---->
27  * comments.
28  *
29  * Changes from the murmur3 distribution are marked with `//PDB'
30  */
31 
32 #include "log.h"
33 #include "hash-murmur3.h"
34 
35 #include <iomanip>
36 
37 namespace ns3 {
38 
39 NS_LOG_COMPONENT_DEFINE ("Hash-Murmur3")
40  ;
41 
42 namespace Hash {
43 
44 namespace Function {
45 
46 namespace Murmur3Implementation {
47 
48 // Changes from Murmur3 distribution are marked with `//PDB'
49 //
50 
51 /*************************************************
52  ** class Murmur3HashImplementation
53  ************************************************/
54 
55 // Adapted from http://code.google.com/p/smhasher/
56 
57 // Begin Murmur3.cpp ----------------------------->
58 
59 //
60 //-----------------------------------------------------------------------------
61 // MurmurHash3 was written by Austin Appleby, and is placed in the public
62 // domain. The author hereby disclaims copyright to this source code.
63 
64 // Note - The x86 and x64 versions do _not_ produce the same results, as the
65 // algorithms are optimized for their respective platforms. You can still
66 // compile and run any of them on any platform, but your performance with the
67 // non-native version will be less than optimal.
68 
69 
70 inline uint32_t rotl32 ( uint32_t x, int8_t r )
71 {
72  return (x << r) | (x >> (32 - r));
73 }
74 
75 inline uint64_t rotl64 ( uint64_t x, int8_t r )
76 {
77  return (x << r) | (x >> (64 - r));
78 }
79 
80 #define BIG_CONSTANT(x) (x##LLU)
81 
82 //-----------------------------------------------------------------------------
83 // Block read - if your platform needs to do endian-swapping or can only
84 // handle aligned reads, do the conversion here
85 
86 inline uint32_t getblock ( const uint32_t * p, int i )
87 {
88  return p[i];
89 }
90 
91 inline uint64_t getblock ( const uint64_t * p, int i )
92 {
93  return p[i];
94 }
95 
96 //-----------------------------------------------------------------------------
97 // Finalization mix - force all bits of a hash block to avalanche
98 
99 inline uint32_t fmix ( uint32_t h )
100 {
101  h ^= h >> 16;
102  h *= 0x85ebca6b;
103  h ^= h >> 13;
104  h *= 0xc2b2ae35;
105  h ^= h >> 16;
106 
107  return h;
108 }
109 
110 //----------
111 
112 inline uint64_t fmix ( uint64_t k )
113 {
114  k ^= k >> 33;
115  k *= BIG_CONSTANT(0xff51afd7ed558ccd);
116  k ^= k >> 33;
117  k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
118  k ^= k >> 33;
119 
120  return k;
121 }
122 
123 //-----------------------------------------------------------------------------
124 
125 //PDB forward
126 void MurmurHash3_x86_32_incr ( const void * key, int len,
127  uint32_t seed, void * out );
128 void MurmurHash3_x86_32_fin ( int len,
129  uint32_t seed, void * out );
130 
131 //PDB - incremental hashing
132 void MurmurHash3_x86_32 ( const void * key, int len,
133  uint32_t seed, void * out )
134 {
135  uint32_t h1;
136  MurmurHash3_x86_32_incr (key, len, seed, &h1);
137  MurmurHash3_x86_32_fin (len, h1, out);
138 }
139 
140 void MurmurHash3_x86_32_incr ( const void * key, int len,
141  uint32_t seed, void * out )
142 {
143  const uint8_t * data = (const uint8_t*)key;
144  const int nblocks = len / 4;
145 
146  uint32_t h1 = seed;
147 
148  uint32_t c1 = 0xcc9e2d51;
149  uint32_t c2 = 0x1b873593;
150 
151  //----------
152  // body
153 
154  const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
155 
156  for(int i = -nblocks; i; i++)
157  {
158  uint32_t k1 = getblock(blocks,i);
159 
160  k1 *= c1;
161  k1 = rotl32(k1,15);
162  k1 *= c2;
163 
164  h1 ^= k1;
165  h1 = rotl32(h1,13);
166  h1 = h1*5+0xe6546b64;
167  }
168 
169  //----------
170  // tail
171 
172  const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
173 
174  uint32_t k1 = 0;
175 
176  switch(len & 3)
177  {
178  case 3: k1 ^= tail[2] << 16;
179  case 2: k1 ^= tail[1] << 8;
180  case 1: k1 ^= tail[0];
181  k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
182  };
183 
184  *(uint32_t *)out = h1;
185 }
186 
187 //PDB - incremental hashing - finalization
188 void MurmurHash3_x86_32_fin ( int len,
189  uint32_t seed, void * out )
190 {
191  uint32_t h1 = seed;
192 
193  //----------
194  // finalization
195 
196  h1 ^= len;
197 
198  h1 = fmix(h1);
199 
200  *(uint32_t *)out = h1;
201 }
202 
203 //-----------------------------------------------------------------------------
204 
205 //PDB forward
206 void MurmurHash3_x86_128_incr ( const void * key, const int len,
207  uint32_t * seeds, void * out );
208 void MurmurHash3_x86_128_fin ( const int len,
209  uint32_t * seeds, void * out );
210 
211 //PDB - incremental hashing
212 void MurmurHash3_x86_128 ( const void * key, const int len,
213  uint32_t seed, void * out )
214 {
215  uint32_t seeds[4];
216  uint32_t h[4];
217  seeds[0] = seeds[1] = seeds[2] = seeds[3] = seed;
218  MurmurHash3_x86_128_incr (key, len, seeds, h);
219  MurmurHash3_x86_128_fin (len, h, out);
220 }
221 
222 void MurmurHash3_x86_128_incr ( const void * key, const int len,
223  uint32_t * seeds, void * out )
224 {
225  const uint8_t * data = (const uint8_t*)key;
226  const int nblocks = len / 16;
227 
228  uint32_t h1 = seeds[0];
229  uint32_t h2 = seeds[1];
230  uint32_t h3 = seeds[2];
231  uint32_t h4 = seeds[3];
232 
233  uint32_t c1 = 0x239b961b;
234  uint32_t c2 = 0xab0e9789;
235  uint32_t c3 = 0x38b34ae5;
236  uint32_t c4 = 0xa1e38b93;
237 
238  //----------
239  // body
240 
241  const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
242 
243  for(int i = -nblocks; i; i++)
244  {
245  uint32_t k1 = getblock(blocks,i*4+0);
246  uint32_t k2 = getblock(blocks,i*4+1);
247  uint32_t k3 = getblock(blocks,i*4+2);
248  uint32_t k4 = getblock(blocks,i*4+3);
249 
250  k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
251 
252  h1 = rotl32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
253 
254  k2 *= c2; k2 = rotl32(k2,16); k2 *= c3; h2 ^= k2;
255 
256  h2 = rotl32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
257 
258  k3 *= c3; k3 = rotl32(k3,17); k3 *= c4; h3 ^= k3;
259 
260  h3 = rotl32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
261 
262  k4 *= c4; k4 = rotl32(k4,18); k4 *= c1; h4 ^= k4;
263 
264  h4 = rotl32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
265  }
266 
267  //----------
268  // tail
269 
270  const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
271 
272  uint32_t k1 = 0;
273  uint32_t k2 = 0;
274  uint32_t k3 = 0;
275  uint32_t k4 = 0;
276 
277  switch(len & 15)
278  {
279  case 15: k4 ^= tail[14] << 16;
280  case 14: k4 ^= tail[13] << 8;
281  case 13: k4 ^= tail[12] << 0;
282  k4 *= c4; k4 = rotl32(k4,18); k4 *= c1; h4 ^= k4;
283 
284  case 12: k3 ^= tail[11] << 24;
285  case 11: k3 ^= tail[10] << 16;
286  case 10: k3 ^= tail[ 9] << 8;
287  case 9: k3 ^= tail[ 8] << 0;
288  k3 *= c3; k3 = rotl32(k3,17); k3 *= c4; h3 ^= k3;
289 
290  case 8: k2 ^= tail[ 7] << 24;
291  case 7: k2 ^= tail[ 6] << 16;
292  case 6: k2 ^= tail[ 5] << 8;
293  case 5: k2 ^= tail[ 4] << 0;
294  k2 *= c2; k2 = rotl32(k2,16); k2 *= c3; h2 ^= k2;
295 
296  case 4: k1 ^= tail[ 3] << 24;
297  case 3: k1 ^= tail[ 2] << 16;
298  case 2: k1 ^= tail[ 1] << 8;
299  case 1: k1 ^= tail[ 0] << 0;
300  k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
301  };
302 
303  ((uint32_t *)out)[0] = h1;
304  ((uint32_t *)out)[1] = h2;
305  ((uint32_t *)out)[2] = h3;
306  ((uint32_t *)out)[3] = h4;
307 }
308 
309 //PDB - incremental hashing - finalization
310 void MurmurHash3_x86_128_fin ( const int len,
311  uint32_t * seeds, void * out )
312 {
313  //----------
314  // finalization
315 
316  uint32_t h1 = seeds[0];
317  uint32_t h2 = seeds[1];
318  uint32_t h3 = seeds[2];
319  uint32_t h4 = seeds[3];
320 
321  h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
322 
323  h1 += h2; h1 += h3; h1 += h4;
324  h2 += h1; h3 += h1; h4 += h1;
325 
326  h1 = fmix(h1);
327  h2 = fmix(h2);
328  h3 = fmix(h3);
329  h4 = fmix(h4);
330 
331  h1 += h2; h1 += h3; h1 += h4;
332  h2 += h1; h3 += h1; h4 += h1;
333 
334  ((uint32_t *)out)[0] = h1;
335  ((uint32_t *)out)[1] = h2;
336  ((uint32_t *)out)[2] = h3;
337  ((uint32_t *)out)[3] = h4;
338 }
339 
340 //-----------------------------------------------------------------------------
341 
342 void MurmurHash3_x64_128 ( const void * key, const int len,
343  const uint32_t seed, void * out )
344 {
345  const uint8_t * data = (const uint8_t*)key;
346  const int nblocks = len / 16;
347 
348  uint64_t h1 = seed;
349  uint64_t h2 = seed;
350 
351  uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
352  uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
353 
354  //----------
355  // body
356 
357  const uint64_t * blocks = (const uint64_t *)(data);
358 
359  for(int i = 0; i < nblocks; i++)
360  {
361  uint64_t k1 = getblock(blocks,i*2+0);
362  uint64_t k2 = getblock(blocks,i*2+1);
363 
364  k1 *= c1; k1 = rotl64(k1,31); k1 *= c2; h1 ^= k1;
365 
366  h1 = rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
367 
368  k2 *= c2; k2 = rotl64(k2,33); k2 *= c1; h2 ^= k2;
369 
370  h2 = rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
371  }
372 
373  //----------
374  // tail
375 
376  const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
377 
378  uint64_t k1 = 0;
379  uint64_t k2 = 0;
380 
381  switch(len & 15)
382  {
383  case 15: k2 ^= uint64_t(tail[14]) << 48;
384  case 14: k2 ^= uint64_t(tail[13]) << 40;
385  case 13: k2 ^= uint64_t(tail[12]) << 32;
386  case 12: k2 ^= uint64_t(tail[11]) << 24;
387  case 11: k2 ^= uint64_t(tail[10]) << 16;
388  case 10: k2 ^= uint64_t(tail[ 9]) << 8;
389  case 9: k2 ^= uint64_t(tail[ 8]) << 0;
390  k2 *= c2; k2 = rotl64(k2,33); k2 *= c1; h2 ^= k2;
391 
392  case 8: k1 ^= uint64_t(tail[ 7]) << 56;
393  case 7: k1 ^= uint64_t(tail[ 6]) << 48;
394  case 6: k1 ^= uint64_t(tail[ 5]) << 40;
395  case 5: k1 ^= uint64_t(tail[ 4]) << 32;
396  case 4: k1 ^= uint64_t(tail[ 3]) << 24;
397  case 3: k1 ^= uint64_t(tail[ 2]) << 16;
398  case 2: k1 ^= uint64_t(tail[ 1]) << 8;
399  case 1: k1 ^= uint64_t(tail[ 0]) << 0;
400  k1 *= c1; k1 = rotl64(k1,31); k1 *= c2; h1 ^= k1;
401  };
402 
403  //----------
404  // finalization
405 
406  h1 ^= len; h2 ^= len;
407 
408  h1 += h2;
409  h2 += h1;
410 
411  h1 = fmix(h1);
412  h2 = fmix(h2);
413 
414  h1 += h2;
415  h2 += h1;
416 
417  ((uint32_t *)out)[0] = h1;
418  ((uint32_t *)out)[1] = h2;
419 }
420 
421 
422 // End Murmur3.cpp ----------------------------->
423 
424 #undef BIG_CONSTANT
425 
426 
427 //-----------------------------------------------------------------------------
428 
429 
430 } // namespace Murmur3Implementation
431 
432 
434 {
435  clear ();
436 }
437 
438 uint32_t
439 Murmur3::GetHash32 (const char * buffer, const size_t size)
440 {
441  using namespace Murmur3Implementation;
442 
443  MurmurHash3_x86_32_incr (buffer, size, m_hash32, (void *) & m_hash32);
444  m_size32 += size;
445  uint32_t hash;
446  MurmurHash3_x86_32_fin (m_size32, m_hash32, (void *) & hash);
447 
448  return hash;
449 }
450 
451 uint64_t
452 Murmur3::GetHash64 (const char * buffer, const size_t size)
453 {
454  using namespace Murmur3Implementation;
455  MurmurHash3_x86_128_incr (buffer, size,
456  (uint32_t *)(void *)m_hash64, m_hash64);
457  m_size64 += size;
458 
459  // Simpler would be:
460  //
461  // uint64_t hash[2];
462  // MurmurHash3_x86_128_fin (m_size64, m_hash64, hash);
463  // return hash[0];
464  //
465  // but this triggers an aliasing bug in gcc-4.4 (perhaps related to
466  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390).
467  // In ns-3, this bug produces incorrect results in static optimized
468  // builds only.
469  //
470  // Using uint32_t here avoids the bug, and continues to works with newer gcc.
471  uint32_t hash[4];
472 
474  (uint32_t *)(void *)m_hash64, hash);
475  uint64_t result = hash[1];
476  result = (result << 32) | hash[0];
477  return result;
478 }
479 
480 void
482 {
483  m_hash32 = (uint32_t)SEED;
484  m_size32 = 0;
485  m_hash64[0] = m_hash64[1] = ((uint64_t)(SEED) << 32) + (uint64_t)SEED;
486  m_size64 = 0;
487 }
488 
489 } // namespace Function
490 
491 } // namespace Hash
492 
493 } // namespace ns3
uint32_t m_size32
Cache last hash value, and total bytes hashed (needed to finalize), for incremental hashing...
Definition: hash-murmur3.h:106
NS_LOG_COMPONENT_DEFINE("GrantedTimeWindowMpiInterface")
void MurmurHash3_x64_128(const void *key, const int len, const uint32_t seed, void *out)
virtual void clear(void)
Restore initial state.
uint64_t rotl64(uint64_t x, int8_t r)
Definition: hash-murmur3.cc:75
void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
uint8_t data[writeSize]
#define BIG_CONSTANT(x)
Definition: hash-murmur3.cc:80
uint32_t rotl32(uint32_t x, int8_t r)
Definition: hash-murmur3.cc:70
void MurmurHash3_x86_32_incr(const void *key, int len, uint32_t seed, void *out)
void MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, void *out)
Murmur3()
Constructor, clears internal state.
uint32_t getblock(const uint32_t *p, int i)
Definition: hash-murmur3.cc:86
uint64_t m_size64
Cache last hash value, and total bytes hashed (needed to finalize), for incremental hashing...
Definition: hash-murmur3.h:109
uint64_t GetHash64(const char *buffer, const size_t size)
Compute 64-bit hash of a byte buffer.
void MurmurHash3_x86_32_fin(int len, uint32_t seed, void *out)
void MurmurHash3_x86_128_fin(const int len, uint32_t *seeds, void *out)
void MurmurHash3_x86_128_incr(const void *key, const int len, uint32_t *seeds, void *out)
uint32_t m_hash32
Cache last hash value, and total bytes hashed (needed to finalize), for incremental hashing...
Definition: hash-murmur3.h:105
uint64_t m_hash64[2]
murmur3 produces 128-bit hash and state; we use just the first 64-bits.
Definition: hash-murmur3.h:108
uint32_t GetHash32(const char *buffer, const size_t size)
Compute 32-bit hash of a byte buffer.