murmur_redux 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +0 -0
- data/.ruby-gemset +0 -0
- data/.ruby-version +0 -0
- data/Gemfile +1 -0
- data/Guardfile +0 -0
- data/README.md +27 -8
- data/Rakefile +9 -0
- data/ext/murmur_native/extconf.rb +3 -0
- data/ext/murmur_native/murmur_native.c +467 -0
- data/lib/murmur_redux/errors.rb +0 -0
- data/lib/murmur_redux/hash.rb +3 -3
- data/lib/murmur_redux/version.rb +1 -1
- data/lib/murmur_redux.rb +5 -2
- data/murmur_redux.gemspec +17 -16
- data/spec/murmur_native_spec.rb +55 -0
- data/spec/murmur_redux/hash_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -0
- metadata +15 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 925117d747be38f53fff1621f2b2a5c50ff81843
|
4
|
+
data.tar.gz: 2f56e116c367da28c0d039fcfb43ce6a082ce84b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af1fffda69050fd8a3d9290622c6a1fa2024fd0d0097e273ca9409aebbfb116f48f11e1bd45295098aad07ee850f1c0598e062ec28f2c8e3502eca65eff24d1c
|
7
|
+
data.tar.gz: 6acbb6e828d76d3f2bdef8dd9b25180d32145426c2d2d009af4ca8ab25f31d67437290aad20a9f2dfcf8996ed4313fe3a1f8ade0cbe74791dbbd72a2fd0933be
|
data/.rspec
CHANGED
File without changes
|
data/.ruby-gemset
CHANGED
File without changes
|
data/.ruby-version
CHANGED
File without changes
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# Murmur redux
|
2
2
|
|
3
3
|
A simpler wrapper around [murmurhash3](https://github.com/funny-falcon/murmurhash3-ruby) gem with a nicer API.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
Murmur redux requires at least Ruby >= 1.9.2
|
5
|
+
It defaults to `MurmurHash3_x86_128` which is a nice combination of low latency and with good collision resistence.
|
8
6
|
|
9
7
|
## Installation
|
10
8
|
|
@@ -19,12 +17,33 @@ gem 'murmur_redux'
|
|
19
17
|
By default it uses MurmurHash3_x86_128 which is a nice combination of low latency and with good collision resistence.
|
20
18
|
|
21
19
|
```ruby
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
hex_string = MurmurRedux::Hash.digest('test')
|
21
|
+
|
22
|
+
# => '9de1bd74cc287dac824dbdf93182129a'
|
25
23
|
```
|
26
24
|
|
27
|
-
|
25
|
+
### FAQ
|
26
|
+
|
27
|
+
##### What is MurmurHash ?
|
28
|
+
|
29
|
+
From its Wikipedia page[0] :
|
30
|
+
|
31
|
+
>MurmurHash is a non-cryptographic hash function suitable for general hash-based lookup. It was created by Austin Appleby in 2008, and exists in a number of variants, all of which have been released into the public domain. When compared to other popular hash functions, MurmurHash performed well in a random distribution of regular keys.
|
32
|
+
|
33
|
+
##### How fast is it ?
|
34
|
+
|
35
|
+
Is one of the fastest hashing algorithms with with good to great collision resistence[1].
|
36
|
+
|
37
|
+
- [0] - [wiki article](http://en.wikipedia.org/wiki/MurmurHash)
|
38
|
+
- [1] - [performance](http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed)
|
39
|
+
|
40
|
+
### Credits
|
41
|
+
|
42
|
+
- [MurmurHash3](https://code.google.com/p/smhasher/wiki/MurmurHash3)
|
43
|
+
- [murmurhash3-ruby gem](https://github.com/funny-falcon/murmurhash3-ruby)
|
44
|
+
- [Byte Friendly article on MurmurHash 3](http://tech.tulentsev.com/2012/10/ruby-gem-for-murmurhash-3)
|
45
|
+
|
46
|
+
### License (MIT)
|
28
47
|
|
29
48
|
Copyright (c) 2013 Marian Posaceanu
|
30
49
|
|
data/Rakefile
ADDED
@@ -0,0 +1,467 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
/*-----------------------------------------------------------------------------
|
3
|
+
* MurmurHash3 was written by Austin Appleby, and is placed in the public
|
4
|
+
* domain. The author hereby disclaims copyright to this source code.
|
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
|
+
typedef unsigned char uint8_t;
|
13
|
+
typedef unsigned int uint32_t;
|
14
|
+
#ifndef HAVE_STDINT_H
|
15
|
+
#if SIZEOF_LONG == 8
|
16
|
+
typedef unsigned long uint64_t;
|
17
|
+
#else
|
18
|
+
typedef unsigned long long uint64_t;
|
19
|
+
#endif
|
20
|
+
#endif
|
21
|
+
|
22
|
+
/*-----------------------------------------------------------------------------
|
23
|
+
* Platform-specific functions and macros
|
24
|
+
*/
|
25
|
+
|
26
|
+
#ifdef __GNUC__
|
27
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
28
|
+
#elif defined(_MSC_VER)
|
29
|
+
#define FORCE_INLINE __forceinline
|
30
|
+
#else
|
31
|
+
#define FORCE_INLINE
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#if defined(_MSC_VER)
|
35
|
+
|
36
|
+
#define ROTL32(x,y) _rotl(x,y)
|
37
|
+
#define ROTL64(x,y) _rotl64(x,y)
|
38
|
+
|
39
|
+
#define BIG_CONSTANT(x) (x)
|
40
|
+
|
41
|
+
#else
|
42
|
+
|
43
|
+
static inline FORCE_INLINE uint32_t
|
44
|
+
rotl32 ( uint32_t x, int8_t r )
|
45
|
+
{
|
46
|
+
return (x << r) | (x >> (32 - r));
|
47
|
+
}
|
48
|
+
|
49
|
+
static inline FORCE_INLINE uint64_t
|
50
|
+
rotl64 ( uint64_t x, int8_t r )
|
51
|
+
{
|
52
|
+
return (x << r) | (x >> (64 - r));
|
53
|
+
}
|
54
|
+
|
55
|
+
#define ROTL32(x,y) rotl32(x,y)
|
56
|
+
#define ROTL64(x,y) rotl64(x,y)
|
57
|
+
|
58
|
+
#define BIG_CONSTANT(x) (x##LLU)
|
59
|
+
#endif
|
60
|
+
|
61
|
+
/* end platform specific */
|
62
|
+
|
63
|
+
/* Block read - if your platform needs to do endian-swapping or can only
|
64
|
+
* handle aligned reads, do the conversion here */
|
65
|
+
#ifdef WORDS_BIGENDIAN
|
66
|
+
#define GCC_VERSION_SINCE(major, minor, patchlevel) \
|
67
|
+
(defined(__GNUC__) && !defined(__INTEL_COMPILER) && \
|
68
|
+
((__GNUC__ > (major)) || \
|
69
|
+
(__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \
|
70
|
+
(__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel))))
|
71
|
+
#if GCC_VERSION_SINCE(4,3,0)
|
72
|
+
# define swap32(x) __builtin_bswap32(x)
|
73
|
+
# define swap64(x) __builtin_bswap64(x)
|
74
|
+
#endif
|
75
|
+
|
76
|
+
#ifndef swap32
|
77
|
+
# define swap32(x) ((((x)&0xFF)<<24) \
|
78
|
+
|(((x)>>24)&0xFF) \
|
79
|
+
|(((x)&0x0000FF00)<<8) \
|
80
|
+
|(((x)&0x00FF0000)>>8) )
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#ifndef swap64
|
84
|
+
# ifdef HAVE_INT64_T
|
85
|
+
static inline FORCE_INLINE uint64_t
|
86
|
+
swap64(uint64_t x) {
|
87
|
+
x = (x>>32) | (x << 32);
|
88
|
+
x = ((x & BIG_CONSTANT(0xFFFF0000FFFF0000)) >> 16) |
|
89
|
+
((x & BIG_CONSTANT(0x0000FFFF0000FFFF)) << 16);
|
90
|
+
return ((x & BIG_CONSTANT(0xFF00FF00FF00FF00)) >> 8) |
|
91
|
+
((x & BIG_CONSTANT(0x00FF00FF00FF00FF)) << 8);
|
92
|
+
}
|
93
|
+
# endif
|
94
|
+
|
95
|
+
#endif
|
96
|
+
static inline FORCE_INLINE uint32_t
|
97
|
+
getblock32(const uint32_t * p, int i)
|
98
|
+
{
|
99
|
+
return swap32(p[i]);
|
100
|
+
}
|
101
|
+
|
102
|
+
static inline FORCE_INLINE uint64_t
|
103
|
+
getblock64(const uint64_t * p, int i)
|
104
|
+
{
|
105
|
+
return swap64(p[i]);
|
106
|
+
}
|
107
|
+
#else
|
108
|
+
#define getblock32(p, i) (p[i])
|
109
|
+
#define getblock64(p, i) (p[i])
|
110
|
+
#endif
|
111
|
+
|
112
|
+
/* Finalization mix - force all bits of a hash block to avalanche */
|
113
|
+
|
114
|
+
static inline FORCE_INLINE uint32_t
|
115
|
+
fmix32 ( uint32_t h )
|
116
|
+
{
|
117
|
+
h ^= h >> 16;
|
118
|
+
h *= 0x85ebca6b;
|
119
|
+
h ^= h >> 13;
|
120
|
+
h *= 0xc2b2ae35;
|
121
|
+
h ^= h >> 16;
|
122
|
+
|
123
|
+
return h;
|
124
|
+
}
|
125
|
+
|
126
|
+
static inline FORCE_INLINE uint64_t
|
127
|
+
fmix64 ( uint64_t k )
|
128
|
+
{
|
129
|
+
k ^= k >> 33;
|
130
|
+
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
131
|
+
k ^= k >> 33;
|
132
|
+
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
133
|
+
k ^= k >> 33;
|
134
|
+
|
135
|
+
return k;
|
136
|
+
}
|
137
|
+
|
138
|
+
static inline FORCE_INLINE uint32_t
|
139
|
+
mmix32(uint32_t k1)
|
140
|
+
{
|
141
|
+
k1 *= 0xcc9e2d51;
|
142
|
+
k1 = ROTL32(k1, 15);
|
143
|
+
return k1 * 0x1b873593;
|
144
|
+
}
|
145
|
+
|
146
|
+
static uint32_t
|
147
|
+
MurmurHash3_x86_32 ( const void * key, long len, uint32_t seed)
|
148
|
+
{
|
149
|
+
const uint8_t * data = (const uint8_t*)key;
|
150
|
+
const int nblocks = (int)(len / 4);
|
151
|
+
int i;
|
152
|
+
|
153
|
+
uint32_t h1 = seed;
|
154
|
+
uint32_t k1 = 0;
|
155
|
+
|
156
|
+
|
157
|
+
/* body */
|
158
|
+
|
159
|
+
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
160
|
+
|
161
|
+
for(i = -nblocks; i; i++)
|
162
|
+
{
|
163
|
+
h1 ^= mmix32(getblock32(blocks, i));
|
164
|
+
h1 = ROTL32(h1,13);
|
165
|
+
h1 = h1*5+0xe6546b64;
|
166
|
+
}
|
167
|
+
|
168
|
+
/* tail */
|
169
|
+
|
170
|
+
data += nblocks*4;
|
171
|
+
|
172
|
+
switch(len & 3)
|
173
|
+
{
|
174
|
+
case 3: k1 ^= data[2] << 16;
|
175
|
+
case 2: k1 ^= data[1] << 8;
|
176
|
+
case 1: k1 ^= data[0];
|
177
|
+
h1 ^= mmix32(k1);
|
178
|
+
};
|
179
|
+
|
180
|
+
/* finalization */
|
181
|
+
|
182
|
+
h1 ^= len;
|
183
|
+
|
184
|
+
h1 = fmix32(h1);
|
185
|
+
|
186
|
+
return h1;
|
187
|
+
}
|
188
|
+
|
189
|
+
#define C1_128 BIG_CONSTANT(0x87c37b91114253d5)
|
190
|
+
#define C2_128 BIG_CONSTANT(0x4cf5ad432745937f)
|
191
|
+
|
192
|
+
static inline FORCE_INLINE uint64_t
|
193
|
+
mmix128_1(uint64_t k1)
|
194
|
+
{
|
195
|
+
k1 *= C1_128;
|
196
|
+
k1 = ROTL64(k1, 31);
|
197
|
+
return k1 * C2_128;
|
198
|
+
}
|
199
|
+
|
200
|
+
static inline FORCE_INLINE uint64_t
|
201
|
+
mmix128_2(uint64_t k2)
|
202
|
+
{
|
203
|
+
k2 *= C2_128;
|
204
|
+
k2 = ROTL64(k2, 33);
|
205
|
+
return k2 * C1_128;
|
206
|
+
}
|
207
|
+
|
208
|
+
static void MurmurHash3_x64_128 ( const void * key, const long len,
|
209
|
+
const uint32_t seed, void * out )
|
210
|
+
{
|
211
|
+
const uint8_t * data = (const uint8_t*)key;
|
212
|
+
const int nblocks = (int)(len / 16);
|
213
|
+
int i;
|
214
|
+
|
215
|
+
uint64_t h1 = seed;
|
216
|
+
uint64_t h2 = seed;
|
217
|
+
uint64_t k1 = 0, k2 = 0;
|
218
|
+
|
219
|
+
/* body */
|
220
|
+
|
221
|
+
const uint64_t * blocks = (const uint64_t *)(data);
|
222
|
+
|
223
|
+
for(i = 0; i < nblocks; i++)
|
224
|
+
{
|
225
|
+
k1 = getblock64(blocks, i*2+0);
|
226
|
+
k2 = getblock64(blocks, i*2+1);
|
227
|
+
|
228
|
+
h1 ^= mmix128_1(k1);
|
229
|
+
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
230
|
+
|
231
|
+
h2 ^= mmix128_2(k2);
|
232
|
+
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
233
|
+
}
|
234
|
+
|
235
|
+
/* tail */
|
236
|
+
|
237
|
+
data += nblocks*16;
|
238
|
+
k1 = k2 = 0;
|
239
|
+
|
240
|
+
switch(len & 15)
|
241
|
+
{
|
242
|
+
case 15: k2 ^= (uint64_t)(data[14]) << 48;
|
243
|
+
case 14: k2 ^= (uint64_t)(data[13]) << 40;
|
244
|
+
case 13: k2 ^= (uint64_t)(data[12]) << 32;
|
245
|
+
case 12: k2 ^= (uint64_t)(data[11]) << 24;
|
246
|
+
case 11: k2 ^= (uint64_t)(data[10]) << 16;
|
247
|
+
case 10: k2 ^= (uint64_t)(data[ 9]) << 8;
|
248
|
+
case 9: k2 ^= (uint64_t)(data[ 8]) << 0;
|
249
|
+
h2 ^= mmix128_2(k2);
|
250
|
+
|
251
|
+
case 8: k1 ^= (uint64_t)(data[ 7]) << 56;
|
252
|
+
case 7: k1 ^= (uint64_t)(data[ 6]) << 48;
|
253
|
+
case 6: k1 ^= (uint64_t)(data[ 5]) << 40;
|
254
|
+
case 5: k1 ^= (uint64_t)(data[ 4]) << 32;
|
255
|
+
case 4: k1 ^= (uint64_t)(data[ 3]) << 24;
|
256
|
+
case 3: k1 ^= (uint64_t)(data[ 2]) << 16;
|
257
|
+
case 2: k1 ^= (uint64_t)(data[ 1]) << 8;
|
258
|
+
case 1: k1 ^= (uint64_t)(data[ 0]) << 0;
|
259
|
+
h1 ^= mmix128_1(k1);
|
260
|
+
};
|
261
|
+
|
262
|
+
/* finalization */
|
263
|
+
|
264
|
+
h1 ^= len; h2 ^= len;
|
265
|
+
|
266
|
+
h1 += h2;
|
267
|
+
h2 += h1;
|
268
|
+
|
269
|
+
h1 = fmix64(h1);
|
270
|
+
h2 = fmix64(h2);
|
271
|
+
|
272
|
+
h1 += h2;
|
273
|
+
h2 += h1;
|
274
|
+
|
275
|
+
((uint64_t*)out)[0] = h1;
|
276
|
+
((uint64_t*)out)[1] = h2;
|
277
|
+
}
|
278
|
+
|
279
|
+
/* end of MurmurHash3 algorithm */
|
280
|
+
|
281
|
+
static VALUE
|
282
|
+
rb_fmix32(VALUE self, VALUE integer)
|
283
|
+
{
|
284
|
+
uint32_t _int = NUM2UINT(integer);
|
285
|
+
return UINT2NUM(fmix32(_int));
|
286
|
+
}
|
287
|
+
|
288
|
+
static VALUE
|
289
|
+
rb_fmix64(VALUE self, VALUE integer)
|
290
|
+
{
|
291
|
+
#if SIZEOF_LONG == 8
|
292
|
+
uint64_t _int = NUM2ULONG(integer);
|
293
|
+
return ULONG2NUM(fmix64(_int));
|
294
|
+
#else
|
295
|
+
uint64_t _int = NUM2ULL(integer);
|
296
|
+
return ULL2NUM(fmix64(_int));
|
297
|
+
#endif
|
298
|
+
}
|
299
|
+
|
300
|
+
static VALUE
|
301
|
+
rb_murmur3_32_str_hash(int argc, VALUE* argv, VALUE self)
|
302
|
+
{
|
303
|
+
VALUE rstr;
|
304
|
+
uint32_t result;
|
305
|
+
|
306
|
+
if (argc == 0 || argc > 2) {
|
307
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (string[, seed])");
|
308
|
+
}
|
309
|
+
rstr = argv[0];
|
310
|
+
StringValue(rstr);
|
311
|
+
|
312
|
+
result = MurmurHash3_x86_32(RSTRING_PTR(rstr), RSTRING_LEN(rstr), argc == 1 ? 0 : NUM2UINT(argv[1]));
|
313
|
+
|
314
|
+
return UINT2NUM(result);
|
315
|
+
}
|
316
|
+
|
317
|
+
static VALUE
|
318
|
+
rb_murmur3_32_int32_hash(int argc, VALUE* argv, VALUE self)
|
319
|
+
{
|
320
|
+
/* VALUE rint; */
|
321
|
+
uint32_t _int;
|
322
|
+
uint32_t result;
|
323
|
+
|
324
|
+
if (argc == 0 || argc > 2) {
|
325
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int32[, seed])");
|
326
|
+
}
|
327
|
+
_int = NUM2UINT(argv[0]);
|
328
|
+
|
329
|
+
result = MurmurHash3_x86_32(&_int, 4, argc == 1 ? 0 : NUM2UINT(argv[1]));
|
330
|
+
|
331
|
+
return UINT2NUM(result);
|
332
|
+
}
|
333
|
+
|
334
|
+
static VALUE
|
335
|
+
rb_murmur3_32_int64_hash(int argc, VALUE* argv, VALUE self)
|
336
|
+
{
|
337
|
+
/* VALUE rint; */
|
338
|
+
uint64_t _int;
|
339
|
+
uint32_t result;
|
340
|
+
|
341
|
+
if (argc == 0 || argc > 2) {
|
342
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int64[, seed])");
|
343
|
+
}
|
344
|
+
#if SIZEOF_LONG == 8
|
345
|
+
_int = NUM2ULONG(argv[0]);
|
346
|
+
#else
|
347
|
+
_int = NUM2ULL(argv[0]);
|
348
|
+
#endif
|
349
|
+
|
350
|
+
result = MurmurHash3_x86_32(&_int, 8, argc == 1 ? 0 : NUM2UINT(argv[1]));
|
351
|
+
|
352
|
+
return UINT2NUM(result);
|
353
|
+
}
|
354
|
+
|
355
|
+
#define PREPARE_128_BIT() \
|
356
|
+
VALUE rstr, rseed, ar_result; \
|
357
|
+
uint32_t result[4]; \
|
358
|
+
|
359
|
+
#define SWAP_128_BIT() do { \
|
360
|
+
uint32_t tmp; \
|
361
|
+
tmp = result[0]; \
|
362
|
+
result[0] = result[1]; \
|
363
|
+
result[1] = tmp; \
|
364
|
+
tmp = result[2]; \
|
365
|
+
result[2] = result[3]; \
|
366
|
+
result[3] = tmp; \
|
367
|
+
} while (0)
|
368
|
+
|
369
|
+
#define RETURN_128_BIT() \
|
370
|
+
ar_result = rb_ary_new2(4); \
|
371
|
+
rb_ary_push(ar_result, UINT2NUM(result[0])); \
|
372
|
+
rb_ary_push(ar_result, UINT2NUM(result[1])); \
|
373
|
+
rb_ary_push(ar_result, UINT2NUM(result[2])); \
|
374
|
+
rb_ary_push(ar_result, UINT2NUM(result[3])); \
|
375
|
+
return ar_result
|
376
|
+
|
377
|
+
static VALUE
|
378
|
+
rb_murmur3_128_str_hash(int argc, VALUE* argv, VALUE self)
|
379
|
+
{
|
380
|
+
VALUE rstr, ar_result;
|
381
|
+
uint32_t result[4];
|
382
|
+
|
383
|
+
if (argc == 0 || argc > 2) {
|
384
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (string[, seed])");
|
385
|
+
}
|
386
|
+
rstr = argv[0];
|
387
|
+
StringValue(rstr);
|
388
|
+
|
389
|
+
MurmurHash3_x64_128(RSTRING_PTR(rstr), RSTRING_LEN(rstr), argc == 1 ? 0 : NUM2UINT(argv[1]), result);
|
390
|
+
#if WORDS_BIGENDIAN
|
391
|
+
SWAP_128_BIT();
|
392
|
+
#endif
|
393
|
+
RETURN_128_BIT();
|
394
|
+
}
|
395
|
+
|
396
|
+
static VALUE
|
397
|
+
rb_murmur3_128_int32_hash(int argc, VALUE* argv, VALUE self)
|
398
|
+
{
|
399
|
+
VALUE ar_result;
|
400
|
+
uint32_t result[4], _int;
|
401
|
+
|
402
|
+
if (argc == 0 || argc > 2) {
|
403
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int32[, seed])");
|
404
|
+
}
|
405
|
+
_int = NUM2UINT(argv[0]);
|
406
|
+
MurmurHash3_x64_128(&_int, 4, argc == 1 ? 0 : NUM2UINT(argv[1]), result);
|
407
|
+
#if WORDS_BIGENDIAN
|
408
|
+
SWAP_128_BIT();
|
409
|
+
#endif
|
410
|
+
RETURN_128_BIT();
|
411
|
+
}
|
412
|
+
|
413
|
+
static VALUE
|
414
|
+
rb_murmur3_128_int64_hash(int argc, VALUE* argv, VALUE self)
|
415
|
+
{
|
416
|
+
VALUE ar_result;
|
417
|
+
uint32_t result[4];
|
418
|
+
uint64_t _int;
|
419
|
+
|
420
|
+
if (argc == 0 || argc > 2) {
|
421
|
+
rb_raise(rb_eArgError, "accept 1 or 2 arguments: (int64[, seed])");
|
422
|
+
}
|
423
|
+
#if SIZEOF_LONG == 8
|
424
|
+
_int = NUM2ULONG(argv[0]);
|
425
|
+
#else
|
426
|
+
_int = NUM2ULL(argv[0]);
|
427
|
+
#endif
|
428
|
+
MurmurHash3_x64_128(&_int, 8, argc == 1 ? 0 : NUM2UINT(argv[1]), result);
|
429
|
+
#if WORDS_BIGENDIAN
|
430
|
+
SWAP_128_BIT();
|
431
|
+
#endif
|
432
|
+
RETURN_128_BIT();
|
433
|
+
}
|
434
|
+
|
435
|
+
void
|
436
|
+
Init_murmur_native() {
|
437
|
+
VALUE singleton;
|
438
|
+
VALUE mod_murmur = rb_define_module("MurmurRedux");
|
439
|
+
VALUE mod_murmur32 = rb_define_module_under(mod_murmur, "Native32");
|
440
|
+
VALUE mod_murmur128 = rb_define_module_under(mod_murmur, "Native128");
|
441
|
+
|
442
|
+
rb_define_method(mod_murmur32, "murmur3_32_fmix", rb_fmix32, 1);
|
443
|
+
rb_define_method(mod_murmur32, "murmur3_32_str_hash", rb_murmur3_32_str_hash, -1);
|
444
|
+
rb_define_method(mod_murmur32, "murmur3_32_int32_hash", rb_murmur3_32_int32_hash, -1);
|
445
|
+
rb_define_method(mod_murmur32, "murmur3_32_int64_hash", rb_murmur3_32_int64_hash, -1);
|
446
|
+
|
447
|
+
rb_extend_object(mod_murmur32, mod_murmur32);
|
448
|
+
singleton = rb_singleton_class(mod_murmur32);
|
449
|
+
rb_define_alias(singleton, "fmix", "murmur3_32_fmix");
|
450
|
+
rb_define_alias(singleton, "str_hash", "murmur3_32_str_hash");
|
451
|
+
rb_define_alias(singleton, "int32_hash", "murmur3_32_int32_hash");
|
452
|
+
rb_define_alias(singleton, "int64_hash", "murmur3_32_int64_hash");
|
453
|
+
|
454
|
+
|
455
|
+
rb_define_method(mod_murmur128, "murmur3_128_fmix", rb_fmix64, 1);
|
456
|
+
rb_define_method(mod_murmur128, "murmur3_128_str_hash", rb_murmur3_128_str_hash, -1);
|
457
|
+
rb_define_method(mod_murmur128, "murmur3_128_int32_hash", rb_murmur3_128_int32_hash, -1);
|
458
|
+
rb_define_method(mod_murmur128, "murmur3_128_int64_hash", rb_murmur3_128_int64_hash, -1);
|
459
|
+
|
460
|
+
rb_extend_object(mod_murmur128, mod_murmur128);
|
461
|
+
singleton = rb_singleton_class(mod_murmur128);
|
462
|
+
rb_define_alias(singleton, "fmix", "murmur3_128_fmix");
|
463
|
+
rb_define_alias(singleton, "str_hash", "murmur3_128_str_hash");
|
464
|
+
rb_define_alias(singleton, "int32_hash", "murmur3_128_int32_hash");
|
465
|
+
rb_define_alias(singleton, "int64_hash", "murmur3_128_int64_hash");
|
466
|
+
|
467
|
+
}
|
data/lib/murmur_redux/errors.rb
CHANGED
File without changes
|
data/lib/murmur_redux/hash.rb
CHANGED
@@ -2,14 +2,14 @@ module MurmurRedux
|
|
2
2
|
class Hash
|
3
3
|
class << self
|
4
4
|
def digest(string)
|
5
|
-
ints =
|
5
|
+
ints = MurmurRedux::V128.str_hash(string)
|
6
6
|
|
7
|
-
|
7
|
+
generate_hex_string(ints)
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
-
def
|
12
|
+
def generate_hex_string(ints)
|
13
13
|
ints.pack('L*').unpack('H*').first
|
14
14
|
end
|
15
15
|
end
|
data/lib/murmur_redux/version.rb
CHANGED
data/lib/murmur_redux.rb
CHANGED
data/murmur_redux.gemspec
CHANGED
@@ -1,20 +1,21 @@
|
|
1
|
-
$LOAD_PATH.push File.expand_path(
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'rake'
|
2
3
|
require 'murmur_redux/version'
|
3
4
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'murmur_redux'
|
7
|
+
gem.version = MurmurRedux::VERSION
|
8
|
+
gem.platform = Gem::Platform::RUBY
|
9
|
+
gem.summary = 'A simple wrapper around murmurhash3 C extension.'
|
10
|
+
gem.description = 'A simple wrapper around murmurhash3 C extension originally based on https://github.com/funny-falcon/murmurhash3-ruby'
|
11
|
+
gem.author = 'Marian Posaceanu'
|
12
|
+
gem.email = 'contact@marianposaceanu.com'
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
gem.require_paths = ['lib', 'ext']
|
16
|
+
gem.homepage = 'https://github.com/dakull/murmur_redux'
|
17
|
+
gem.extensions = FileList["ext/**/extconf.rb"]
|
18
|
+
gem.license = 'MIT'
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
s.add_dependency('murmurhash3', '~> 0.1.3')
|
20
|
+
gem.required_ruby_version = '>= 1.9.2'
|
20
21
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
shared_examples_128 = proc do
|
2
|
+
it 'should make correct hash for string' do
|
3
|
+
murmur.str_hash('asdfqwer', 0).should eq([0xd6d7d367, 0xcb41f064, 0x8973cd72, 0xc345e72e])
|
4
|
+
murmur.str_hash('asdfqwerzxcvyui', 0).should eq([0x007b2172f, 0x64ecae1b, 0x1813b5a5, 0x9c674ee6])
|
5
|
+
murmur.str_hash('asdfqwerzxcvyuio', 0).should eq([0xf508df57, 0xbb38f3fd, 0xf48c9d98, 0xb65c36cd])
|
6
|
+
murmur.str_hash('asdfqwerzxcvyuio!', 0).should eq([0x8a011755, 0xb13d463f, 0x8386d32a, 0x0df8884c])
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should make correct hash for 32bit integer' do
|
10
|
+
murmur.int32_hash(1717859169).should eq([0x20b48108, 0x10369ceb, 0x3ad523cc, 0xdacb587f])
|
11
|
+
murmur.int32_hash(1717859169).should eq(murmur.str_hash('asdf'))
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should make correct hash for 64bit integer' do
|
15
|
+
murmur.int64_hash(0x12345678).should eq(murmur.str_hash("\x78\x56\x34\x12\x00\x00\x00\x00"))
|
16
|
+
murmur.int64_hash(0x1234567812345678).should eq(murmur.str_hash("\x78\x56\x34\x12\x78\x56\x34\x12"))
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should make correct fmix for 64bit integer' do
|
20
|
+
murmur.fmix(1717859169).should eq(0xbefb9076a3712207)
|
21
|
+
murmur.fmix(12345678912345678).should eq(0x197ef59146f5221c)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
shared_examples_32 = proc do
|
26
|
+
it 'should make correct hash for string' do
|
27
|
+
murmur.str_hash('asdfqwer', 0).should eq(0xa46b5209)
|
28
|
+
murmur.str_hash('asdfqwerty', 0).should eq(0xa3cfe04b)
|
29
|
+
murmur.str_hash('asd', 0).should eq(0x14570c6f)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should make correct hash for 32bit integer' do
|
33
|
+
murmur.int32_hash(1717859169).should eq(0x1b20e026)
|
34
|
+
murmur.int32_hash(1717859169).should eq(murmur.str_hash('asdf'))
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should make correct hash for 64bit integer' do
|
38
|
+
murmur.int64_hash(0x12345678).should eq(murmur.str_hash("\x78\x56\x34\x12\x00\x00\x00\x00"))
|
39
|
+
murmur.int64_hash(0x1234567812345678).should eq(murmur.str_hash("\x78\x56\x34\x12\x78\x56\x34\x12"))
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should make correct fmix for 32bit integer' do
|
43
|
+
murmur.fmix(1717859169).should eq(0x17561734)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "Native 32" do
|
48
|
+
let(:murmur) { MurmurRedux::Native32 }
|
49
|
+
class_exec &shared_examples_32
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Native 128" do
|
53
|
+
let(:murmur) { MurmurRedux::Native128 }
|
54
|
+
class_exec &shared_examples_128
|
55
|
+
end
|
@@ -6,6 +6,6 @@ describe MurmurRedux::Hash do
|
|
6
6
|
it 'digests an argument supplied string into a hexadecimal representation' do
|
7
7
|
digested_string = MurmurRedux::Hash.digest(string_to_digest)
|
8
8
|
|
9
|
-
expect(digested_string).
|
9
|
+
expect(digested_string).to eq('df65d6d2d12d51f164c5f3a85066322c')
|
10
10
|
end
|
11
11
|
end
|
data/spec/spec_helper.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,33 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murmur_redux
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marian Posaceanu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
-
dependencies:
|
13
|
-
-
|
14
|
-
name: murmurhash3
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.1.3
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.1.3
|
27
|
-
description: 'A simple wrapper around murmurhash3 gem with a nicer API : MurmurRedux::Hash.digest(string)'
|
11
|
+
date: 2013-09-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple wrapper around murmurhash3 C extension originally based on https://github.com/funny-falcon/murmurhash3-ruby
|
28
14
|
email: contact@marianposaceanu.com
|
29
15
|
executables: []
|
30
|
-
extensions:
|
16
|
+
extensions:
|
17
|
+
- ext/murmur_native/extconf.rb
|
31
18
|
extra_rdoc_files: []
|
32
19
|
files:
|
33
20
|
- .gitignore
|
@@ -37,20 +24,26 @@ files:
|
|
37
24
|
- Gemfile
|
38
25
|
- Guardfile
|
39
26
|
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- ext/murmur_native/extconf.rb
|
29
|
+
- ext/murmur_native/murmur_native.c
|
40
30
|
- lib/murmur_redux.rb
|
41
31
|
- lib/murmur_redux/errors.rb
|
42
32
|
- lib/murmur_redux/hash.rb
|
43
33
|
- lib/murmur_redux/version.rb
|
44
34
|
- murmur_redux.gemspec
|
35
|
+
- spec/murmur_native_spec.rb
|
45
36
|
- spec/murmur_redux/hash_spec.rb
|
46
37
|
- spec/spec_helper.rb
|
47
38
|
homepage: https://github.com/dakull/murmur_redux
|
48
|
-
licenses:
|
39
|
+
licenses:
|
40
|
+
- MIT
|
49
41
|
metadata: {}
|
50
42
|
post_install_message:
|
51
43
|
rdoc_options: []
|
52
44
|
require_paths:
|
53
45
|
- lib
|
46
|
+
- ext
|
54
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
55
48
|
requirements:
|
56
49
|
- - '>='
|
@@ -63,8 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
56
|
version: '0'
|
64
57
|
requirements: []
|
65
58
|
rubyforge_project:
|
66
|
-
rubygems_version: 2.0.
|
59
|
+
rubygems_version: 2.0.3
|
67
60
|
signing_key:
|
68
61
|
specification_version: 4
|
69
|
-
summary: A simple wrapper around murmurhash3
|
62
|
+
summary: A simple wrapper around murmurhash3 C extension.
|
70
63
|
test_files: []
|