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 //-----------------------------------------------------------------------------