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 6 // Note - The x86 and x64 versions do _not_ produce the same results, as the 7 // algorithms are optimized for their respective platforms. You can still 8 // compile and run any of them on any platform, but your performance with the 9 // non-native version will be less than optimal. 10 11 12 module ae.utils.digest_murmurhash3; 13 14 private: 15 16 import ae.utils.meta; 17 18 alias byte int8_t; 19 alias ubyte uint8_t; 20 alias uint uint32_t; 21 alias ulong uint64_t; 22 23 //----------------------------------------------------------------------------- 24 // Platform-specific functions and macros 25 26 /*inline*/ uint32_t rotl32(int r) ( uint32_t x ) 27 { 28 return (x << r) | (x >> (32 - r)); 29 } 30 31 32 /*inline*/ uint64_t rotl64(int r) ( uint64_t x ) 33 { 34 return (x << r) | (x >> (64 - r)); 35 } 36 37 //----------------------------------------------------------------------------- 38 // Block read - if your platform needs to do endian-swapping or can only 39 // handle aligned reads, do the conversion here 40 41 /+ 42 /*FORCE_INLINE*/ uint32_t getblock ( const uint32_t * p, int i ) 43 { 44 return p[i]; 45 } 46 47 48 /*FORCE_INLINE*/ uint64_t getblock ( const uint64_t * p, int i ) 49 { 50 return p[i]; 51 } 52 +/ 53 54 string GETBLOCK(string P, string I) 55 { 56 return mixin(X!q{ @(P) [ @(I) ] }); 57 } 58 59 //----------------------------------------------------------------------------- 60 // Finalization mix - force all bits of a hash block to avalanche 61 62 /+ 63 /*FORCE_INLINE*/ uint32_t fmix ( uint32_t h ) 64 { 65 h ^= h >> 16; 66 h *= 0x85ebca6b; 67 h ^= h >> 13; 68 h *= 0xc2b2ae35; 69 h ^= h >> 16; 70 71 72 return h; 73 } 74 75 76 //---------- 77 78 79 /*FORCE_INLINE*/ uint64_t fmix ( uint64_t k ) 80 { 81 k ^= k >> 33; 82 k *= BIG_CONSTANT(0xff51afd7ed558ccd); 83 k ^= k >> 33; 84 k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); 85 k ^= k >> 33; 86 87 88 return k; 89 } 90 +/ 91 92 string FMIX_32(string H) 93 { 94 return mixin(X!q{ 95 @(H) ^= @(H) >> 16; 96 @(H) *= 0x85ebca6b; 97 @(H) ^= @(H) >> 13; 98 @(H) *= 0xc2b2ae35; 99 @(H) ^= @(H) >> 16; 100 }); 101 } 102 103 string FMIX_64(string H) 104 { 105 return mixin(X!q{ 106 @(H) ^= @(H) >> 33; 107 @(H) *= 0xff51afd7ed558ccdL; 108 @(H) ^= @(H) >> 33; 109 @(H) *= 0xc4ceb9fe1a85ec53L; 110 @(H) ^= @(H) >> 33; 111 }); 112 } 113 114 115 //----------------------------------------------------------------------------- 116 117 public: 118 119 void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * output ) 120 { 121 const uint8_t * data = cast(const uint8_t*)key; 122 const int nblocks = len / 4; 123 124 125 uint32_t h1 = seed; 126 127 128 uint32_t c1 = 0xcc9e2d51; 129 uint32_t c2 = 0x1b873593; 130 131 132 //---------- 133 // body 134 135 136 const uint32_t * blocks = cast(const uint32_t *)(data + nblocks*4); 137 138 139 for(int i = -nblocks; i; i++) 140 { 141 uint32_t k1 = mixin(GETBLOCK(q{blocks},q{i})); 142 143 144 k1 *= c1; 145 k1 = rotl32!15(k1); 146 k1 *= c2; 147 148 h1 ^= k1; 149 h1 = rotl32!13(h1); 150 h1 = h1*5+0xe6546b64; 151 } 152 153 154 //---------- 155 // tail 156 157 158 const uint8_t * tail = cast(const uint8_t*)(data + nblocks*4); 159 160 161 uint32_t k1 = 0; 162 163 164 switch(len & 3) 165 { 166 case 3: k1 ^= tail[2] << 16; goto case; 167 case 2: k1 ^= tail[1] << 8; goto case; 168 case 1: k1 ^= tail[0]; 169 k1 *= c1; k1 = rotl32!15(k1); k1 *= c2; h1 ^= k1; break; 170 default: 171 } 172 173 174 //---------- 175 // finalization 176 177 178 h1 ^= len; 179 180 181 mixin(FMIX_32(q{h1})); 182 183 184 *cast(uint32_t*)output = h1; 185 } 186 187 //----------------------------------------------------------------------------- 188 189 190 void MurmurHash3_x86_128 ( const void * key, const int len, uint32_t seed, void * output ) 191 { 192 const uint8_t * data = cast(const uint8_t*)key; 193 const int nblocks = len / 16; 194 195 196 uint32_t h1 = seed; 197 uint32_t h2 = seed; 198 uint32_t h3 = seed; 199 uint32_t h4 = seed; 200 201 202 uint32_t c1 = 0x239b961b; 203 uint32_t c2 = 0xab0e9789; 204 uint32_t c3 = 0x38b34ae5; 205 uint32_t c4 = 0xa1e38b93; 206 207 208 //---------- 209 // body 210 211 212 const uint32_t * blocks = cast(const uint32_t *)(data + nblocks*16); 213 214 215 for(int i = -nblocks; i; i++) 216 { 217 uint32_t k1 = mixin(GETBLOCK(q{blocks},q{i*4+0})); 218 uint32_t k2 = mixin(GETBLOCK(q{blocks},q{i*4+1})); 219 uint32_t k3 = mixin(GETBLOCK(q{blocks},q{i*4+2})); 220 uint32_t k4 = mixin(GETBLOCK(q{blocks},q{i*4+3})); 221 222 223 k1 *= c1; k1 = rotl32!15(k1); k1 *= c2; h1 ^= k1; 224 225 226 h1 = rotl32!19(h1); h1 += h2; h1 = h1*5+0x561ccd1b; 227 228 229 k2 *= c2; k2 = rotl32!16(k2); k2 *= c3; h2 ^= k2; 230 231 232 h2 = rotl32!17(h2); h2 += h3; h2 = h2*5+0x0bcaa747; 233 234 235 k3 *= c3; k3 = rotl32!17(k3); k3 *= c4; h3 ^= k3; 236 237 238 h3 = rotl32!15(h3); h3 += h4; h3 = h3*5+0x96cd1c35; 239 240 241 k4 *= c4; k4 = rotl32!18(k4); k4 *= c1; h4 ^= k4; 242 243 244 h4 = rotl32!13(h4); h4 += h1; h4 = h4*5+0x32ac3b17; 245 } 246 247 248 //---------- 249 // tail 250 251 252 const uint8_t * tail = cast(const uint8_t*)(data + nblocks*16); 253 254 255 uint32_t k1 = 0; 256 uint32_t k2 = 0; 257 uint32_t k3 = 0; 258 uint32_t k4 = 0; 259 260 261 switch(len & 15) 262 { 263 case 15: k4 ^= tail[14] << 16; goto case; 264 case 14: k4 ^= tail[13] << 8; goto case; 265 case 13: k4 ^= tail[12] << 0; 266 k4 *= c4; k4 = rotl32!18(k4); k4 *= c1; h4 ^= k4; goto case; 267 268 269 case 12: k3 ^= tail[11] << 24; goto case; 270 case 11: k3 ^= tail[10] << 16; goto case; 271 case 10: k3 ^= tail[ 9] << 8; goto case; 272 case 9: k3 ^= tail[ 8] << 0; 273 k3 *= c3; k3 = rotl32!17(k3); k3 *= c4; h3 ^= k3; goto case; 274 275 276 case 8: k2 ^= tail[ 7] << 24; goto case; 277 case 7: k2 ^= tail[ 6] << 16; goto case; 278 case 6: k2 ^= tail[ 5] << 8; goto case; 279 case 5: k2 ^= tail[ 4] << 0; 280 k2 *= c2; k2 = rotl32!16(k2); k2 *= c3; h2 ^= k2; goto case; 281 282 283 case 4: k1 ^= tail[ 3] << 24; goto case; 284 case 3: k1 ^= tail[ 2] << 16; goto case; 285 case 2: k1 ^= tail[ 1] << 8; goto case; 286 case 1: k1 ^= tail[ 0] << 0; 287 k1 *= c1; k1 = rotl32!15(k1); k1 *= c2; h1 ^= k1; goto default; 288 default: 289 } 290 291 292 //---------- 293 // finalization 294 295 296 h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; 297 298 299 h1 += h2; h1 += h3; h1 += h4; 300 h2 += h1; h3 += h1; h4 += h1; 301 302 303 mixin(FMIX_32(q{h1})); 304 mixin(FMIX_32(q{h2})); 305 mixin(FMIX_32(q{h3})); 306 mixin(FMIX_32(q{h4})); 307 308 309 h1 += h2; h1 += h3; h1 += h4; 310 h2 += h1; h3 += h1; h4 += h1; 311 312 313 (cast(uint32_t*)output)[0] = h1; 314 (cast(uint32_t*)output)[1] = h2; 315 (cast(uint32_t*)output)[2] = h3; 316 (cast(uint32_t*)output)[3] = h4; 317 } 318 319 320 //----------------------------------------------------------------------------- 321 322 void MurmurHash3_x64_128 ( const void * key, const int len, const uint32_t seed, void * output ) 323 { 324 const uint8_t * data = cast(const uint8_t*)key; 325 const int nblocks = len / 16; 326 327 328 uint64_t h1 = seed; 329 uint64_t h2 = seed; 330 331 332 uint64_t c1 = 0x87c37b91114253d5L; 333 uint64_t c2 = 0x4cf5ad432745937fL; 334 335 336 //---------- 337 // body 338 339 340 const uint64_t * blocks = cast(const uint64_t *)(data); 341 342 343 for(int i = 0; i < nblocks; i++) 344 { 345 uint64_t k1 = mixin(GETBLOCK(q{blocks},q{i*2+0})); 346 uint64_t k2 = mixin(GETBLOCK(q{blocks},q{i*2+1})); 347 348 349 k1 *= c1; k1 = rotl64!31(k1); k1 *= c2; h1 ^= k1; 350 351 352 h1 = rotl64!27(h1); h1 += h2; h1 = h1*5+0x52dce729; 353 354 355 k2 *= c2; k2 = rotl64!33(k2); k2 *= c1; h2 ^= k2; 356 357 358 h2 = rotl64!31(h2); h2 += h1; h2 = h2*5+0x38495ab5; 359 } 360 361 362 //---------- 363 // tail 364 365 366 const uint8_t * tail = cast(const uint8_t*)(data + nblocks*16); 367 368 369 uint64_t k1 = 0; 370 uint64_t k2 = 0; 371 372 373 switch(len & 15) 374 { 375 case 15: k2 ^= cast(uint64_t)(tail[14]) << 48; goto case; 376 case 14: k2 ^= cast(uint64_t)(tail[13]) << 40; goto case; 377 case 13: k2 ^= cast(uint64_t)(tail[12]) << 32; goto case; 378 case 12: k2 ^= cast(uint64_t)(tail[11]) << 24; goto case; 379 case 11: k2 ^= cast(uint64_t)(tail[10]) << 16; goto case; 380 case 10: k2 ^= cast(uint64_t)(tail[ 9]) << 8; goto case; 381 case 9: k2 ^= cast(uint64_t)(tail[ 8]) << 0; 382 k2 *= c2; k2 = rotl64!33(k2); k2 *= c1; h2 ^= k2; goto case; 383 384 385 case 8: k1 ^= cast(uint64_t)(tail[ 7]) << 56; goto case; 386 case 7: k1 ^= cast(uint64_t)(tail[ 6]) << 48; goto case; 387 case 6: k1 ^= cast(uint64_t)(tail[ 5]) << 40; goto case; 388 case 5: k1 ^= cast(uint64_t)(tail[ 4]) << 32; goto case; 389 case 4: k1 ^= cast(uint64_t)(tail[ 3]) << 24; goto case; 390 case 3: k1 ^= cast(uint64_t)(tail[ 2]) << 16; goto case; 391 case 2: k1 ^= cast(uint64_t)(tail[ 1]) << 8; goto case; 392 case 1: k1 ^= cast(uint64_t)(tail[ 0]) << 0; 393 k1 *= c1; k1 = rotl64!31(k1); k1 *= c2; h1 ^= k1; goto default; 394 default: 395 } 396 397 398 //---------- 399 // finalization 400 401 402 h1 ^= len; h2 ^= len; 403 404 405 h1 += h2; 406 h2 += h1; 407 408 409 mixin(FMIX_64(q{h1})); 410 mixin(FMIX_64(q{h2})); 411 412 413 h1 += h2; 414 h2 += h1; 415 416 417 (cast(uint64_t*)output)[0] = h1; 418 (cast(uint64_t*)output)[1] = h2; 419 } 420 421 422 //-----------------------------------------------------------------------------