murmur_redux 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|