Tpetra Matrix/Vector Services Version of the Day
MurmurHash3.cpp
00001 //-----------------------------------------------------------------------------
00002 // MurmurHash3 was written by Austin Appleby, and is placed in the public
00003 // domain. The author hereby disclaims copyright to this source code.
00004 
00005 // Note - The x86 and x64 versions do _not_ produce the same results, as the
00006 // algorithms are optimized for their respective platforms. You can still
00007 // compile and run any of them on any platform, but your performance with the
00008 // non-native version will be less than optimal.
00009 
00010 #include "MurmurHash3.hpp"
00011 
00012 namespace Tpetra
00013 {
00014 
00015 namespace Details
00016 
00017 {
00018 
00019 //-----------------------------------------------------------------------------
00020 // Platform-specific functions and macros
00021 
00022 // Microsoft Visual Studio
00023 #if defined(_MSC_VER)
00024 
00025 #define FORCE_INLINE  __forceinline
00026 
00027 #include <stdlib.h>
00028 
00029 #define ROTL32(x,y) _rotl(x,y)
00030 #define ROTL64(x,y) _rotl64(x,y)
00031 
00032 #define BIG_CONSTANT(x) (x)
00033 
00034 // Other compilers
00035 
00036 #else // not defined(_MSC_VER)
00037 
00038 inline uint32_t rotl32 ( uint32_t x, int8_t r )
00039 {
00040   return (x << r) | (x >> (32 - r));
00041 }
00042 
00043 inline uint64_t rotl64 ( uint64_t x, int8_t r )
00044 {
00045   return (x << r) | (x >> (64 - r));
00046 }
00047 
00048 #define ROTL32(x,y) rotl32(x,y)
00049 #define ROTL64(x,y) rotl64(x,y)
00050 
00051 #define BIG_CONSTANT(x) (x##LLU)
00052 
00053 #endif // !defined(_MSC_VER)
00054 
00055 //-----------------------------------------------------------------------------
00056 // Block read - if your platform needs to do endian-swapping or can only
00057 // handle aligned reads, do the conversion here
00058 
00059 #define GETBLOCK(lhs, p, i ) \
00060 { \
00061   lhs = p[(i)];\
00062 } \
00063 
00064 
00065 //-----------------------------------------------------------------------------
00066 // Finalization mix - force all bits of a hash block to avalanche
00067 
00068 #define FMIX_32( h ) \
00069 { \
00070   uint32_t t_h = (h); \
00071   t_h ^= t_h >> 16; \
00072   t_h *= 0x85ebca6b; \
00073   t_h ^= t_h >> 13; \
00074   t_h *= 0xc2b2ae35; \
00075   t_h ^= t_h >> 16; \
00076   h = t_h; \
00077 } \
00078 
00079 //----------
00080 
00081 #define FMIX_64( k )\
00082 {\
00083   uint64_t t_k = (k);\
00084   t_k ^= t_k >> 33;\
00085   t_k *= BIG_CONSTANT(0xff51afd7ed558ccd);\
00086   t_k ^= t_k >> 33;\
00087   t_k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);\
00088   t_k ^= t_k >> 33;\
00089   k = t_k;\
00090 }\
00091 
00092 //-----------------------------------------------------------------------------
00093 
00094 void MurmurHash3_x86_32 ( const void * key, int len,
00095                           uint32_t seed, void * out )
00096 {
00097   const uint8_t * data = (const uint8_t*)key;
00098   const int nblocks = len / 4;
00099 
00100   uint32_t h1 = seed;
00101 
00102   const uint32_t c1 = 0xcc9e2d51;
00103   const uint32_t c2 = 0x1b873593;
00104 
00105   //----------
00106   // body
00107 
00108   const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
00109 
00110   for(int i = -nblocks; i; i++)
00111   {
00112     uint32_t k1;
00113     GETBLOCK(k1, blocks,i);
00114 
00115     k1 *= c1;
00116     k1 = ROTL32(k1,15);
00117     k1 *= c2;
00118     
00119     h1 ^= k1;
00120     h1 = ROTL32(h1,13); 
00121     h1 = h1*5+0xe6546b64;
00122   }
00123 
00124   //----------
00125   // tail
00126 
00127   const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
00128 
00129   uint32_t k1 = 0;
00130 
00131   switch(len & 3)
00132   {
00133   case 3: k1 ^= tail[2] << 16;
00134   case 2: k1 ^= tail[1] << 8;
00135   case 1: k1 ^= tail[0];
00136           k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
00137   };
00138 
00139   //----------
00140   // finalization
00141 
00142   h1 ^= len;
00143 
00144   FMIX_32(h1);
00145 
00146   *(uint32_t*)out = h1;
00147 } 
00148 
00149 //-----------------------------------------------------------------------------
00150 
00151 void MurmurHash3_x86_128 ( const void * key, const int len,
00152                            uint32_t seed, void * out )
00153 {
00154   const uint8_t * data = (const uint8_t*)key;
00155   const int nblocks = len / 16;
00156 
00157   uint32_t h1 = seed;
00158   uint32_t h2 = seed;
00159   uint32_t h3 = seed;
00160   uint32_t h4 = seed;
00161 
00162   const uint32_t c1 = 0x239b961b; 
00163   const uint32_t c2 = 0xab0e9789;
00164   const uint32_t c3 = 0x38b34ae5; 
00165   const uint32_t c4 = 0xa1e38b93;
00166 
00167   //----------
00168   // body
00169 
00170   const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
00171 
00172   for(int i = -nblocks; i; i++)
00173   {
00174     uint32_t k1, k2, k3, k4;
00175     GETBLOCK(k1, blocks,i*4+0);
00176     GETBLOCK(k2, blocks,i*4+1);
00177     GETBLOCK(k3, blocks,i*4+2);
00178     GETBLOCK(k4, blocks,i*4+3);
00179 
00180     k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
00181 
00182     h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
00183 
00184     k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
00185 
00186     h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
00187 
00188     k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
00189 
00190     h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
00191 
00192     k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
00193 
00194     h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
00195   }
00196 
00197   //----------
00198   // tail
00199 
00200   const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
00201 
00202   uint32_t k1 = 0;
00203   uint32_t k2 = 0;
00204   uint32_t k3 = 0;
00205   uint32_t k4 = 0;
00206 
00207   switch(len & 15)
00208   {
00209   case 15: k4 ^= tail[14] << 16;
00210   case 14: k4 ^= tail[13] << 8;
00211   case 13: k4 ^= tail[12] << 0;
00212            k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
00213 
00214   case 12: k3 ^= tail[11] << 24;
00215   case 11: k3 ^= tail[10] << 16;
00216   case 10: k3 ^= tail[ 9] << 8;
00217   case  9: k3 ^= tail[ 8] << 0;
00218            k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
00219 
00220   case  8: k2 ^= tail[ 7] << 24;
00221   case  7: k2 ^= tail[ 6] << 16;
00222   case  6: k2 ^= tail[ 5] << 8;
00223   case  5: k2 ^= tail[ 4] << 0;
00224            k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
00225 
00226   case  4: k1 ^= tail[ 3] << 24;
00227   case  3: k1 ^= tail[ 2] << 16;
00228   case  2: k1 ^= tail[ 1] << 8;
00229   case  1: k1 ^= tail[ 0] << 0;
00230            k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
00231   };
00232 
00233   //----------
00234   // finalization
00235 
00236   h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
00237 
00238   h1 += h2; h1 += h3; h1 += h4;
00239   h2 += h1; h3 += h1; h4 += h1;
00240 
00241   FMIX_32(h1);
00242   FMIX_32(h2);
00243   FMIX_32(h3);
00244   FMIX_32(h4);
00245 
00246   h1 += h2; h1 += h3; h1 += h4;
00247   h2 += h1; h3 += h1; h4 += h1;
00248 
00249   ((uint32_t*)out)[0] = h1;
00250   ((uint32_t*)out)[1] = h2;
00251   ((uint32_t*)out)[2] = h3;
00252   ((uint32_t*)out)[3] = h4;
00253 }
00254 
00255 //-----------------------------------------------------------------------------
00256 
00257 void MurmurHash3_x64_128 ( const void * key, const int len,
00258                            const uint32_t seed, void * out )
00259 {
00260   const uint8_t * data = (const uint8_t*)key;
00261   const int nblocks = len / 16;
00262 
00263   uint64_t h1 = seed;
00264   uint64_t h2 = seed;
00265 
00266   const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
00267   const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
00268 
00269   //----------
00270   // body
00271 
00272   const uint64_t * blocks = (const uint64_t *)(data);
00273 
00274   for(int i = 0; i < nblocks; i++)
00275   {
00276     uint64_t k1, k2;
00277     GETBLOCK(k1, blocks,i*2+0);
00278     GETBLOCK(k2, blocks,i*2+1);
00279 
00280     k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
00281 
00282     h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
00283 
00284     k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
00285 
00286     h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
00287   }
00288 
00289   //----------
00290   // tail
00291 
00292   const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
00293 
00294   uint64_t k1 = 0;
00295   uint64_t k2 = 0;
00296 
00297   switch(len & 15)
00298   {
00299   case 15: k2 ^= uint64_t(tail[14]) << 48;
00300   case 14: k2 ^= uint64_t(tail[13]) << 40;
00301   case 13: k2 ^= uint64_t(tail[12]) << 32;
00302   case 12: k2 ^= uint64_t(tail[11]) << 24;
00303   case 11: k2 ^= uint64_t(tail[10]) << 16;
00304   case 10: k2 ^= uint64_t(tail[ 9]) << 8;
00305   case  9: k2 ^= uint64_t(tail[ 8]) << 0;
00306            k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
00307 
00308   case  8: k1 ^= uint64_t(tail[ 7]) << 56;
00309   case  7: k1 ^= uint64_t(tail[ 6]) << 48;
00310   case  6: k1 ^= uint64_t(tail[ 5]) << 40;
00311   case  5: k1 ^= uint64_t(tail[ 4]) << 32;
00312   case  4: k1 ^= uint64_t(tail[ 3]) << 24;
00313   case  3: k1 ^= uint64_t(tail[ 2]) << 16;
00314   case  2: k1 ^= uint64_t(tail[ 1]) << 8;
00315   case  1: k1 ^= uint64_t(tail[ 0]) << 0;
00316            k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
00317   };
00318 
00319   //----------
00320   // finalization
00321 
00322   h1 ^= len; h2 ^= len;
00323 
00324   h1 += h2;
00325   h2 += h1;
00326 
00327   FMIX_64(h1);
00328   FMIX_64(h2);
00329 
00330   h1 += h2;
00331   h2 += h1;
00332 
00333   ((uint64_t*)out)[0] = h1;
00334   ((uint64_t*)out)[1] = h2;
00335 }
00336 
00337 }
00338 
00339 }
00340 
00341 //-----------------------------------------------------------------------------
00342 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines