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