murmurhash3.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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. // Note - The x86 and x64 versions do _not_ produce the same results, as the
  5. // algorithms are optimized for their respective platforms. You can still
  6. // compile and run any of them on any platform, but your performance with the
  7. // non-native version will be less than optimal.
  8. #if defined(_MSC_VER)
  9. #define ROTL32(x,y) _rotl(x,y)
  10. #define ROTL64(x,y) _rotl64(x,y)
  11. #else
  12. gb_inline u32 rotl32(u32 x, i8 r) {
  13. return (x << r) | (x >> (32-r));
  14. }
  15. gb_inline u64 rotl64(u64 x, i8 r) {
  16. return (x << r) | (x >> (64-r));
  17. }
  18. #define ROTL32(x,y) rotl32(x,y)
  19. #define ROTL64(x,y) rotl64(x,y)
  20. #endif
  21. gb_inline u32 fmix32(u32 h) {
  22. h ^= h >> 16;
  23. h *= 0x85ebca6b;
  24. h ^= h >> 13;
  25. h *= 0xc2b2ae35;
  26. h ^= h >> 16;
  27. return h;
  28. }
  29. gb_inline u64 fmix64(u64 k) {
  30. k ^= k >> 33;
  31. k *= 0xff51afd7ed558ccdULL;
  32. k ^= k >> 33;
  33. k *= 0xc4ceb9fe1a85ec53ULL;
  34. k ^= k >> 33;
  35. return k;
  36. }
  37. gb_inline u32 mm3_getblock32(u32 const *p, isize i) {
  38. return p[i];
  39. }
  40. gb_inline u64 mm3_getblock64(u64 const *p, isize i) {
  41. return p[i];
  42. }
  43. void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) {
  44. u8 const * data = cast(u8 const *)key;
  45. isize nblocks = len / 16;
  46. u64 h1 = seed;
  47. u64 h2 = seed;
  48. u64 const c1 = 0x87c37b91114253d5ULL;
  49. u64 const c2 = 0x4cf5ad432745937fULL;
  50. u64 const * blocks = cast(u64 const *)data;
  51. for (isize i = 0; i < nblocks; i++) {
  52. u64 k1 = mm3_getblock64(blocks, i*2 + 0);
  53. u64 k2 = mm3_getblock64(blocks, i*2 + 1);
  54. k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h1 ^= k1;
  55. h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
  56. k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
  57. h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
  58. }
  59. u8 const * tail = cast(u8 const *)(data + nblocks*16);
  60. u64 k1 = 0;
  61. u64 k2 = 0;
  62. switch(len & 15) {
  63. case 15: k2 ^= ((u64)tail[14]) << 48;
  64. case 14: k2 ^= ((u64)tail[13]) << 40;
  65. case 13: k2 ^= ((u64)tail[12]) << 32;
  66. case 12: k2 ^= ((u64)tail[11]) << 24;
  67. case 11: k2 ^= ((u64)tail[10]) << 16;
  68. case 10: k2 ^= ((u64)tail[ 9]) << 8;
  69. case 9: k2 ^= ((u64)tail[ 8]) << 0;
  70. k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
  71. case 8: k1 ^= ((u64)tail[ 7]) << 56;
  72. case 7: k1 ^= ((u64)tail[ 6]) << 48;
  73. case 6: k1 ^= ((u64)tail[ 5]) << 40;
  74. case 5: k1 ^= ((u64)tail[ 4]) << 32;
  75. case 4: k1 ^= ((u64)tail[ 3]) << 24;
  76. case 3: k1 ^= ((u64)tail[ 2]) << 16;
  77. case 2: k1 ^= ((u64)tail[ 1]) << 8;
  78. case 1: k1 ^= ((u64)tail[ 0]) << 0;
  79. k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
  80. }
  81. h1 ^= len;
  82. h2 ^= len;
  83. h1 += h2;
  84. h2 += h1;
  85. h1 = fmix64(h1);
  86. h2 = fmix64(h2);
  87. h1 += h2;
  88. h2 += h1;
  89. ((u64 *)out)[0] = h1;
  90. ((u64 *)out)[1] = h2;
  91. }
  92. void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
  93. u8 const * data = cast(u8 * const)key;
  94. isize nblocks = len / 16;
  95. u32 h1 = seed;
  96. u32 h2 = seed;
  97. u32 h3 = seed;
  98. u32 h4 = seed;
  99. u32 const c1 = 0x239b961b;
  100. u32 const c2 = 0xab0e9789;
  101. u32 const c3 = 0x38b34ae5;
  102. u32 const c4 = 0xa1e38b93;
  103. //----------
  104. // body
  105. u32 const * blocks = cast(u32 const *)(data + nblocks*16);
  106. for (isize i = -nblocks; i != 0; i++) {
  107. u32 k1 = mm3_getblock32(blocks, i*4 + 0);
  108. u32 k2 = mm3_getblock32(blocks, i*4 + 1);
  109. u32 k3 = mm3_getblock32(blocks, i*4 + 2);
  110. u32 k4 = mm3_getblock32(blocks, i*4 + 3);
  111. k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
  112. h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
  113. k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
  114. h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
  115. k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
  116. h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
  117. k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
  118. h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
  119. }
  120. //----------
  121. // tail
  122. u8 const * tail = cast(u8 const *)(data + nblocks*16);
  123. u32 k1 = 0;
  124. u32 k2 = 0;
  125. u32 k3 = 0;
  126. u32 k4 = 0;
  127. switch(len & 15) {
  128. case 15: k4 ^= tail[14] << 16;
  129. case 14: k4 ^= tail[13] << 8;
  130. case 13: k4 ^= tail[12] << 0;
  131. k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
  132. case 12: k3 ^= tail[11] << 24;
  133. case 11: k3 ^= tail[10] << 16;
  134. case 10: k3 ^= tail[ 9] << 8;
  135. case 9: k3 ^= tail[ 8] << 0;
  136. k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
  137. case 8: k2 ^= tail[ 7] << 24;
  138. case 7: k2 ^= tail[ 6] << 16;
  139. case 6: k2 ^= tail[ 5] << 8;
  140. case 5: k2 ^= tail[ 4] << 0;
  141. k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
  142. case 4: k1 ^= tail[ 3] << 24;
  143. case 3: k1 ^= tail[ 2] << 16;
  144. case 2: k1 ^= tail[ 1] << 8;
  145. case 1: k1 ^= tail[ 0] << 0;
  146. k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
  147. };
  148. //----------
  149. // finalization
  150. h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
  151. h1 += h2; h1 += h3; h1 += h4;
  152. h2 += h1; h3 += h1; h4 += h1;
  153. h1 = fmix32(h1);
  154. h2 = fmix32(h2);
  155. h3 = fmix32(h3);
  156. h4 = fmix32(h4);
  157. h1 += h2; h1 += h3; h1 += h4;
  158. h2 += h1; h3 += h1; h4 += h1;
  159. ((u32 *)out)[0] = h1;
  160. ((u32 *)out)[1] = h2;
  161. ((u32 *)out)[2] = h3;
  162. ((u32 *)out)[3] = h4;
  163. }
  164. // gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
  165. // u128 res;
  166. // #if defined(GB_ARCH_64_BIT)
  167. // MurmurHash3_x64_128(key, len, seed, &res);
  168. // #else
  169. // MurmurHash3_x86_128(key, len, seed, &res);
  170. // #endif
  171. // return res;
  172. // }