Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/MurmurHash3.cpp
Line
Count
Source (jump to first uncovered line)
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
// Note - The x86 and x64 versions do _not_ produce the same results, as the
6
// algorithms are optimized for their respective platforms. You can still
7
// compile and run any of them on any platform, but your performance with the
8
// non-native version will be less than optimal.
9
10
#include "MurmurHash3.h"
11
#include <stdlib.h>
12
13
namespace {
14
15
//-----------------------------------------------------------------------------
16
// Platform-specific functions and macros
17
18
// Microsoft Visual Studio
19
20
#if defined(_MSC_VER)
21
22
#define FORCE_INLINE  __forceinline
23
24
#define ROTL32(x,y) _rotl(x,y)
25
#define ROTL64(x,y) _rotl64(x,y)
26
27
#define BIG_CONSTANT(x) (x)
28
29
// Other compilers
30
31
#else // defined(_MSC_VER)
32
33
// We can't do always_inline, becasue -Werror -Wattribute will trigger
34
// a "might not be able to inline" warning.
35
//#define FORCE_INLINE __attribute__((always_inline))
36
#define FORCE_INLINE inline
37
38
inline uint32_t rotl32 ( uint32_t x, int8_t r )
39
0
{
40
0
  return (x << r) | (x >> (32 - r));
41
0
}
42
43
inline uint64_t rotl64 ( uint64_t x, int8_t r )
44
0
{
45
0
  return (x << r) | (x >> (64 - r));
46
0
}
47
48
0
#define ROTL32(x,y) rotl32(x,y)
49
0
#define ROTL64(x,y) rotl64(x,y)
50
51
0
#define BIG_CONSTANT(x) (x##LLU)
52
53
#endif // !defined(_MSC_VER)
54
55
//-----------------------------------------------------------------------------
56
// Block read - if your platform needs to do endian-swapping or can only
57
// handle aligned reads, do the conversion here
58
59
FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i )
60
0
{
61
0
  return p[i];
62
0
}
63
64
FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i )
65
0
{
66
0
  return p[i];
67
0
}
68
69
//-----------------------------------------------------------------------------
70
// Finalization mix - force all bits of a hash block to avalanche
71
72
FORCE_INLINE uint32_t fmix ( uint32_t h )
73
0
{
74
0
  h ^= h >> 16;
75
0
  h *= 0x85ebca6b;
76
0
  h ^= h >> 13;
77
0
  h *= 0xc2b2ae35;
78
0
  h ^= h >> 16;
79
0
80
0
  return h;
81
0
}
82
83
//----------
84
85
FORCE_INLINE uint64_t fmix ( uint64_t k )
86
0
{
87
0
  k ^= k >> 33;
88
0
  k *= BIG_CONSTANT(0xff51afd7ed558ccd);
89
0
  k ^= k >> 33;
90
0
  k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
91
0
  k ^= k >> 33;
92
0
93
0
  return k;
94
0
}
95
96
} // unnamed namespace
97
98
//-----------------------------------------------------------------------------
99
100
void MurmurHash3_x86_32 ( const void * key, int len,
101
                          uint32_t seed, void * out )
102
0
{
103
0
  const uint8_t * data = (const uint8_t*)key;
104
0
  const int nblocks = len / 4;
105
0
106
0
  uint32_t h1 = seed;
107
0
108
0
  const uint32_t c1 = 0xcc9e2d51;
109
0
  const uint32_t c2 = 0x1b873593;
110
0
111
0
  //----------
112
0
  // body
113
0
114
0
  const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
115
0
116
0
  for(int i = -nblocks; i; i++)
117
0
  {
118
0
    uint32_t k1 = getblock(blocks,i);
119
0
120
0
    k1 *= c1;
121
0
    k1 = ROTL32(k1,15);
122
0
    k1 *= c2;
123
0
124
0
    h1 ^= k1;
125
0
    h1 = ROTL32(h1,13);
126
0
    h1 = h1*5+0xe6546b64;
127
0
  }
128
0
129
0
  //----------
130
0
  // tail
131
0
132
0
  const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
133
0
134
0
  uint32_t k1 = 0;
135
0
136
0
  switch(len & 3)
137
0
  {
138
0
  case 3: k1 ^= tail[2] << 16;
139
0
  case 2: k1 ^= tail[1] << 8;
140
0
  case 1: k1 ^= tail[0];
141
0
          k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
142
0
  }
143
0
144
0
  //----------
145
0
  // finalization
146
0
147
0
  h1 ^= len;
148
0
149
0
  h1 = fmix(h1);
150
0
151
0
  *(uint32_t*)out = h1;
152
0
}
153
154
//-----------------------------------------------------------------------------
155
156
void MurmurHash3_x86_128 ( const void * key, const int len,
157
                           uint32_t seed, void * out )
158
0
{
159
0
  const uint8_t * data = (const uint8_t*)key;
160
0
  const int nblocks = len / 16;
161
0
162
0
  uint32_t h1 = seed;
163
0
  uint32_t h2 = seed;
164
0
  uint32_t h3 = seed;
165
0
  uint32_t h4 = seed;
166
0
167
0
  const uint32_t c1 = 0x239b961b;
168
0
  const uint32_t c2 = 0xab0e9789;
169
0
  const uint32_t c3 = 0x38b34ae5;
170
0
  const uint32_t c4 = 0xa1e38b93;
171
0
172
0
  //----------
173
0
  // body
174
0
175
0
  const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
176
0
177
0
  for(int i = -nblocks; i; i++)
178
0
  {
179
0
    uint32_t k1 = getblock(blocks,i*4+0);
180
0
    uint32_t k2 = getblock(blocks,i*4+1);
181
0
    uint32_t k3 = getblock(blocks,i*4+2);
182
0
    uint32_t k4 = getblock(blocks,i*4+3);
183
0
184
0
    k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
185
0
186
0
    h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
187
0
188
0
    k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
189
0
190
0
    h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
191
0
192
0
    k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
193
0
194
0
    h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
195
0
196
0
    k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
197
0
198
0
    h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
199
0
  }
200
0
201
0
  //----------
202
0
  // tail
203
0
204
0
  const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
205
0
206
0
  uint32_t k1 = 0;
207
0
  uint32_t k2 = 0;
208
0
  uint32_t k3 = 0;
209
0
  uint32_t k4 = 0;
210
0
211
0
  switch(len & 15)
212
0
  {
213
0
  case 15: k4 ^= tail[14] << 16;
214
0
  case 14: k4 ^= tail[13] << 8;
215
0
  case 13: k4 ^= tail[12] << 0;
216
0
           k4 *= c4; k4  = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
217
0
218
0
  case 12: k3 ^= tail[11] << 24;
219
0
  case 11: k3 ^= tail[10] << 16;
220
0
  case 10: k3 ^= tail[ 9] << 8;
221
0
  case  9: k3 ^= tail[ 8] << 0;
222
0
           k3 *= c3; k3  = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
223
0
224
0
  case  8: k2 ^= tail[ 7] << 24;
225
0
  case  7: k2 ^= tail[ 6] << 16;
226
0
  case  6: k2 ^= tail[ 5] << 8;
227
0
  case  5: k2 ^= tail[ 4] << 0;
228
0
           k2 *= c2; k2  = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
229
0
230
0
  case  4: k1 ^= tail[ 3] << 24;
231
0
  case  3: k1 ^= tail[ 2] << 16;
232
0
  case  2: k1 ^= tail[ 1] << 8;
233
0
  case  1: k1 ^= tail[ 0] << 0;
234
0
           k1 *= c1; k1  = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
235
0
  }
236
0
237
0
  //----------
238
0
  // finalization
239
0
240
0
  h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
241
0
242
0
  h1 += h2; h1 += h3; h1 += h4;
243
0
  h2 += h1; h3 += h1; h4 += h1;
244
0
245
0
  h1 = fmix(h1);
246
0
  h2 = fmix(h2);
247
0
  h3 = fmix(h3);
248
0
  h4 = fmix(h4);
249
0
250
0
  h1 += h2; h1 += h3; h1 += h4;
251
0
  h2 += h1; h3 += h1; h4 += h1;
252
0
253
0
  ((uint32_t*)out)[0] = h1;
254
0
  ((uint32_t*)out)[1] = h2;
255
0
  ((uint32_t*)out)[2] = h3;
256
0
  ((uint32_t*)out)[3] = h4;
257
0
}
258
259
//-----------------------------------------------------------------------------
260
261
void MurmurHash3_x64_128 ( const void * key, const int len,
262
                           const uint32_t seed, void * out )
263
0
{
264
0
  const uint8_t * data = (const uint8_t*)key;
265
0
  const int nblocks = len / 16;
266
0
267
0
  uint64_t h1 = seed;
268
0
  uint64_t h2 = seed;
269
0
270
0
  const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
271
0
  const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
272
0
273
0
  //----------
274
0
  // body
275
0
276
0
  const uint64_t * blocks = (const uint64_t *)(data);
277
0
278
0
  for(int i = 0; i < nblocks; i++)
279
0
  {
280
0
    uint64_t k1 = getblock(blocks,i*2+0);
281
0
    uint64_t k2 = getblock(blocks,i*2+1);
282
0
283
0
    k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
284
0
285
0
    h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
286
0
287
0
    k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
288
0
289
0
    h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
290
0
  }
291
0
292
0
  //----------
293
0
  // tail
294
0
295
0
  const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
296
0
297
0
  uint64_t k1 = 0;
298
0
  uint64_t k2 = 0;
299
0
300
0
  switch(len & 15)
301
0
  {
302
0
  case 15: k2 ^= uint64_t(tail[14]) << 48;
303
0
  case 14: k2 ^= uint64_t(tail[13]) << 40;
304
0
  case 13: k2 ^= uint64_t(tail[12]) << 32;
305
0
  case 12: k2 ^= uint64_t(tail[11]) << 24;
306
0
  case 11: k2 ^= uint64_t(tail[10]) << 16;
307
0
  case 10: k2 ^= uint64_t(tail[ 9]) << 8;
308
0
  case  9: k2 ^= uint64_t(tail[ 8]) << 0;
309
0
           k2 *= c2; k2  = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
310
0
311
0
  case  8: k1 ^= uint64_t(tail[ 7]) << 56;
312
0
  case  7: k1 ^= uint64_t(tail[ 6]) << 48;
313
0
  case  6: k1 ^= uint64_t(tail[ 5]) << 40;
314
0
  case  5: k1 ^= uint64_t(tail[ 4]) << 32;
315
0
  case  4: k1 ^= uint64_t(tail[ 3]) << 24;
316
0
  case  3: k1 ^= uint64_t(tail[ 2]) << 16;
317
0
  case  2: k1 ^= uint64_t(tail[ 1]) << 8;
318
0
  case  1: k1 ^= uint64_t(tail[ 0]) << 0;
319
0
           k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
320
0
  }
321
0
322
0
  //----------
323
0
  // finalization
324
0
325
0
  h1 ^= len; h2 ^= len;
326
0
327
0
  h1 += h2;
328
0
  h2 += h1;
329
0
330
0
  h1 = fmix(h1);
331
0
  h2 = fmix(h2);
332
0
333
0
  h1 += h2;
334
0
  h2 += h1;
335
0
336
0
  ((uint64_t*)out)[0] = h1;
337
0
  ((uint64_t*)out)[1] = h2;
338
0
}
339
340
//-----------------------------------------------------------------------------