Derive-C
Loading...
Searching...
No Matches
murmurhash.h
Go to the documentation of this file.
1
3
4#include <derive-c/core.h>
5#include <stddef.h>
6#include <stdint.h>
7
8FORCE_INLINE uint32_t derive_c_rotl32(uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); }
9
10FORCE_INLINE uint64_t derive_c_rotl64(uint64_t x, int8_t r) { return (x << r) | (x >> (64 - r)); }
11
12FORCE_INLINE uint32_t derive_c_getblock32(const uint32_t* p, int32_t i) { return p[i]; }
13
14FORCE_INLINE uint64_t derive_c_getblock64(const uint64_t* p, int32_t i) { return p[i]; }
15
16FORCE_INLINE uint32_t derive_c_fmix32(uint32_t h) {
17 h ^= h >> 16;
18 h *= 0x85ebca6b;
19 h ^= h >> 13;
20 h *= 0xc2b2ae35;
21 h ^= h >> 16;
22
23 return h;
24}
25
26FORCE_INLINE uint64_t derive_c_fmix64(uint64_t k) {
27 k ^= k >> 33;
28 k *= 0xff51afd7ed558ccdLLU;
29 k ^= k >> 33;
30 k *= 0xc4ceb9fe1a85ec53LLU;
31 k ^= k >> 33;
32
33 return k;
34}
35
36void derive_c_MurmurHash3_x86_32(const void* key, int32_t len, uint32_t seed, void* out) {
37 const uint8_t* data = (const uint8_t*)key;
38 const int32_t nblocks = len / 4;
39
40 uint32_t h1 = seed;
41
42 const uint32_t c1 = 0xcc9e2d51;
43 const uint32_t c2 = 0x1b873593;
44
45 // body
46
47 const uint32_t* blocks = (const uint32_t*)(data + (ptrdiff_t)(nblocks * 4));
48
49 for (int i = -nblocks; i; i++) {
50 uint32_t k1 = derive_c_getblock32(blocks, i);
51
52 k1 *= c1;
53 k1 = derive_c_rotl32(k1, 15);
54 k1 *= c2;
55
56 h1 ^= k1;
57 h1 = derive_c_rotl32(h1, 13);
58 h1 = h1 * 5 + 0xe6546b64;
59 }
60
61 // tail
62
63 const uint8_t* tail = (const uint8_t*)(data + (ptrdiff_t)(nblocks * 4));
64
65 uint32_t k1 = 0;
66
67 switch (len & 3) {
68 case 3:
69 k1 ^= tail[2] << 16;
70 case 2:
71 k1 ^= tail[1] << 8;
72 case 1:
73 k1 ^= tail[0];
74 k1 *= c1;
75 k1 = derive_c_rotl32(k1, 15);
76 k1 *= c2;
77 h1 ^= k1;
78 default:
79 };
80
81 // finalization
82
83 h1 ^= len;
84
85 h1 = derive_c_fmix32(h1);
86
87 *(uint32_t*)out = h1;
88}
89
90void derive_c_MurmurHash3_x86_128(const void* key, const int32_t len, uint32_t seed, void* out) {
91 const uint8_t* data = (const uint8_t*)key;
92 const int32_t nblocks = len / 16;
93
94 uint32_t h1 = seed;
95 uint32_t h2 = seed;
96 uint32_t h3 = seed;
97 uint32_t h4 = seed;
98
99 const uint32_t c1 = 0x239b961b;
100 const uint32_t c2 = 0xab0e9789;
101 const uint32_t c3 = 0x38b34ae5;
102 const uint32_t c4 = 0xa1e38b93;
103
104 // body
105
106 const uint32_t* blocks = (const uint32_t*)(data + (ptrdiff_t)(nblocks * 16));
107
108 for (int i = -nblocks; i; i++) {
109 uint32_t k1 = derive_c_getblock32(blocks, (i * 4) + 0);
110 uint32_t k2 = derive_c_getblock32(blocks, (i * 4) + 1);
111 uint32_t k3 = derive_c_getblock32(blocks, (i * 4) + 2);
112 uint32_t k4 = derive_c_getblock32(blocks, (i * 4) + 3);
113
114 k1 *= c1;
115 k1 = derive_c_rotl32(k1, 15);
116 k1 *= c2;
117 h1 ^= k1;
118
119 h1 = derive_c_rotl32(h1, 19);
120 h1 += h2;
121 h1 = h1 * 5 + 0x561ccd1b;
122
123 k2 *= c2;
124 k2 = derive_c_rotl32(k2, 16);
125 k2 *= c3;
126 h2 ^= k2;
127
128 h2 = derive_c_rotl32(h2, 17);
129 h2 += h3;
130 h2 = h2 * 5 + 0x0bcaa747;
131
132 k3 *= c3;
133 k3 = derive_c_rotl32(k3, 17);
134 k3 *= c4;
135 h3 ^= k3;
136
137 h3 = derive_c_rotl32(h3, 15);
138 h3 += h4;
139 h3 = h3 * 5 + 0x96cd1c35;
140
141 k4 *= c4;
142 k4 = derive_c_rotl32(k4, 18);
143 k4 *= c1;
144 h4 ^= k4;
145
146 h4 = derive_c_rotl32(h4, 13);
147 h4 += h1;
148 h4 = h4 * 5 + 0x32ac3b17;
149 }
150
151 // tail
152
153 const uint8_t* tail = (const uint8_t*)(data + (ptrdiff_t)(nblocks * 16));
154
155 uint32_t k1 = 0;
156 uint32_t k2 = 0;
157 uint32_t k3 = 0;
158 uint32_t k4 = 0;
159
160 switch (len & 15) {
161 case 15:
162 k4 ^= tail[14] << 16;
163 case 14:
164 k4 ^= tail[13] << 8;
165 case 13:
166 k4 ^= tail[12] << 0;
167 k4 *= c4;
168 k4 = derive_c_rotl32(k4, 18);
169 k4 *= c1;
170 h4 ^= k4;
171
172 case 12:
173 k3 ^= tail[11] << 24;
174 case 11:
175 k3 ^= tail[10] << 16;
176 case 10:
177 k3 ^= tail[9] << 8;
178 case 9:
179 k3 ^= tail[8] << 0;
180 k3 *= c3;
181 k3 = derive_c_rotl32(k3, 17);
182 k3 *= c4;
183 h3 ^= k3;
184
185 case 8:
186 k2 ^= tail[7] << 24;
187 case 7:
188 k2 ^= tail[6] << 16;
189 case 6:
190 k2 ^= tail[5] << 8;
191 case 5:
192 k2 ^= tail[4] << 0;
193 k2 *= c2;
194 k2 = derive_c_rotl32(k2, 16);
195 k2 *= c3;
196 h2 ^= k2;
197
198 case 4:
199 k1 ^= tail[3] << 24;
200 case 3:
201 k1 ^= tail[2] << 16;
202 case 2:
203 k1 ^= tail[1] << 8;
204 case 1:
205 k1 ^= tail[0] << 0;
206 k1 *= c1;
207 k1 = derive_c_rotl32(k1, 15);
208 k1 *= c2;
209 h1 ^= k1;
210 default:
211 };
212
213 // finalization
214
215 h1 ^= len;
216 h2 ^= len;
217 h3 ^= len;
218 h4 ^= len;
219
220 h1 += h2;
221 h1 += h3;
222 h1 += h4;
223 h2 += h1;
224 h3 += h1;
225 h4 += h1;
226
227 h1 = derive_c_fmix32(h1);
228 h2 = derive_c_fmix32(h2);
229 h3 = derive_c_fmix32(h3);
230 h4 = derive_c_fmix32(h4);
231
232 h1 += h2;
233 h1 += h3;
234 h1 += h4;
235 h2 += h1;
236 h3 += h1;
237 h4 += h1;
238
239 ((uint32_t*)out)[0] = h1;
240 ((uint32_t*)out)[1] = h2;
241 ((uint32_t*)out)[2] = h3;
242 ((uint32_t*)out)[3] = h4;
243}
244
245void derive_c_MurmurHash3_x64_128(const void* key, const int32_t len, const uint32_t seed,
246 void* out) {
247 const uint8_t* data = (const uint8_t*)key;
248 const int32_t nblocks = len / 16;
249
250 uint64_t h1 = seed;
251 uint64_t h2 = seed;
252
253 const uint64_t c1 = 0x87c37b91114253d5LLU;
254 const uint64_t c2 = 0x4cf5ad432745937fLLU;
255
256 // body
257
258 const uint64_t* blocks = (const uint64_t*)(data);
259
260 for (int32_t i = 0; i < nblocks; i++) {
261 uint64_t k1 = derive_c_getblock64(blocks, (i * 2) + 0);
262 uint64_t k2 = derive_c_getblock64(blocks, (i * 2) + 1);
263
264 k1 *= c1;
265 k1 = derive_c_rotl64(k1, 31);
266 k1 *= c2;
267 h1 ^= k1;
268
269 h1 = derive_c_rotl64(h1, 27);
270 h1 += h2;
271 h1 = h1 * 5 + 0x52dce729;
272
273 k2 *= c2;
274 k2 = derive_c_rotl64(k2, 33);
275 k2 *= c1;
276 h2 ^= k2;
277
278 h2 = derive_c_rotl64(h2, 31);
279 h2 += h1;
280 h2 = h2 * 5 + 0x38495ab5;
281 }
282
283 // tail
284
285 const uint8_t* tail = (const uint8_t*)(data + (ptrdiff_t)(nblocks * 16));
286
287 uint64_t k1 = 0;
288 uint64_t k2 = 0;
289
290 switch (len & 15) {
291 case 15:
292 k2 ^= ((uint64_t)tail[14]) << 48;
293 case 14:
294 k2 ^= ((uint64_t)tail[13]) << 40;
295 case 13:
296 k2 ^= ((uint64_t)tail[12]) << 32;
297 case 12:
298 k2 ^= ((uint64_t)tail[11]) << 24;
299 case 11:
300 k2 ^= ((uint64_t)tail[10]) << 16;
301 case 10:
302 k2 ^= ((uint64_t)tail[9]) << 8;
303 case 9:
304 k2 ^= ((uint64_t)tail[8]) << 0;
305 k2 *= c2;
306 k2 = derive_c_rotl64(k2, 33);
307 k2 *= c1;
308 h2 ^= k2;
309
310 case 8:
311 k1 ^= ((uint64_t)tail[7]) << 56;
312 case 7:
313 k1 ^= ((uint64_t)tail[6]) << 48;
314 case 6:
315 k1 ^= ((uint64_t)tail[5]) << 40;
316 case 5:
317 k1 ^= ((uint64_t)tail[4]) << 32;
318 case 4:
319 k1 ^= ((uint64_t)tail[3]) << 24;
320 case 3:
321 k1 ^= ((uint64_t)tail[2]) << 16;
322 case 2:
323 k1 ^= ((uint64_t)tail[1]) << 8;
324 case 1:
325 k1 ^= ((uint64_t)tail[0]) << 0;
326 k1 *= c1;
327 k1 = derive_c_rotl64(k1, 31);
328 k1 *= c2;
329 h1 ^= k1;
330 default:
331 };
332
333 // finalization
334
335 h1 ^= len;
336 h2 ^= len;
337
338 h1 += h2;
339 h2 += h1;
340
341 h1 = derive_c_fmix64(h1);
342 h2 = derive_c_fmix64(h2);
343
344 h1 += h2;
345 h2 += h1;
346
347 ((uint64_t*)out)[0] = h1;
348 ((uint64_t*)out)[1] = h2;
349}
350
351size_t derive_c_murmurhash(const void* key, int32_t len, uint32_t seed) {
352#if SIZE_MAX == UINT64_MAX
353 // 64-bit platform: use the x64 128-bit variant, return lower 64 bits
354 uint64_t out128[2];
355 derive_c_MurmurHash3_x64_128(key, len, seed, out128);
356 return (size_t)out128[0];
357#elif SIZE_MAX == UINT32_MAX
358 // 32-bit platform: use the x86 32-bit variant
359 uint32_t out32;
360 MurmurHash3_x86_32(key, len, seed, &out32);
361 return (size_t)out32;
362#else
363#error "Unsupported size_t width"
364#endif
365}
#define FORCE_INLINE
Definition core.h:43
void derive_c_MurmurHash3_x86_128(const void *key, const int32_t len, uint32_t seed, void *out)
Definition murmurhash.h:90
FORCE_INLINE uint64_t derive_c_rotl64(uint64_t x, int8_t r)
Definition murmurhash.h:10
FORCE_INLINE uint32_t derive_c_getblock32(const uint32_t *p, int32_t i)
Definition murmurhash.h:12
void derive_c_MurmurHash3_x86_32(const void *key, int32_t len, uint32_t seed, void *out)
Definition murmurhash.h:36
FORCE_INLINE uint32_t derive_c_rotl32(uint32_t x, int8_t r)
MurmurHash3 implementation, copied (with love) from Austin Appleby's implementation
Definition murmurhash.h:8
FORCE_INLINE uint32_t derive_c_fmix32(uint32_t h)
Definition murmurhash.h:16
FORCE_INLINE uint64_t derive_c_getblock64(const uint64_t *p, int32_t i)
Definition murmurhash.h:14
size_t derive_c_murmurhash(const void *key, int32_t len, uint32_t seed)
Definition murmurhash.h:351
void derive_c_MurmurHash3_x64_128(const void *key, const int32_t len, const uint32_t seed, void *out)
Definition murmurhash.h:245
FORCE_INLINE uint64_t derive_c_fmix64(uint64_t k)
Definition murmurhash.h:26