xxhash 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +4 -0
- data/Rakefile +1 -0
- data/ext/xxhash/extconf.rb +2 -3
- data/ext/xxhash/libxxhash.c +545 -93
- data/ext/xxhash/libxxhash.h +56 -64
- data/ext/xxhash/xxhash.c +109 -0
- data/ext/xxhash/xxhash.h +18 -0
- data/lib/xxhash.rb +20 -4
- data/lib/xxhash/version.rb +1 -1
- data/test/xxhash_test.rb +32 -4
- data/xxhash.gemspec +2 -1
- metadata +13 -19
- data/ext/xxhash/xxhash.cc +0 -56
data/ext/xxhash/libxxhash.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
|
-
xxHash - Fast Hash algorithm
|
2
|
+
xxHash - Extremely Fast Hash algorithm
|
3
3
|
Header File
|
4
|
-
Copyright (C) 2012-
|
4
|
+
Copyright (C) 2012-2014, Yann Collet.
|
5
5
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
6
6
|
|
7
7
|
Redistribution and use in source and binary forms, with or without
|
@@ -64,101 +64,93 @@ extern "C" {
|
|
64
64
|
#endif
|
65
65
|
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
/*****************************
|
68
|
+
Includes
|
69
|
+
*****************************/
|
70
|
+
#include <stddef.h> /* size_t */
|
71
|
+
|
72
|
+
|
73
|
+
/*****************************
|
74
|
+
Type
|
75
|
+
*****************************/
|
70
76
|
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
71
77
|
|
72
78
|
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
80
|
+
/*****************************
|
81
|
+
Simple Hash Functions
|
82
|
+
*****************************/
|
77
83
|
|
78
|
-
unsigned int
|
84
|
+
unsigned int XXH32 (const void* input, size_t length, unsigned seed);
|
85
|
+
unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed);
|
79
86
|
|
80
87
|
/*
|
81
88
|
XXH32() :
|
82
|
-
Calculate the 32-bits hash of sequence
|
83
|
-
The memory between input & input+
|
89
|
+
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
90
|
+
The memory between input & input+length must be valid (allocated and read-accessible).
|
84
91
|
"seed" can be used to alter the result predictably.
|
85
92
|
This function successfully passes all SMHasher tests.
|
86
93
|
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
87
|
-
|
88
|
-
|
94
|
+
XXH64() :
|
95
|
+
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
89
96
|
*/
|
90
97
|
|
91
98
|
|
92
99
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
XXH_errorcode XXH32_update (void* state, const void* input, int len);
|
99
|
-
unsigned int XXH32_digest (void* state);
|
100
|
+
/*****************************
|
101
|
+
Advanced Hash Functions
|
102
|
+
*****************************/
|
103
|
+
typedef struct { long long ll[ 6]; } XXH32_state_t;
|
104
|
+
typedef struct { long long ll[11]; } XXH64_state_t;
|
100
105
|
|
101
106
|
/*
|
102
|
-
These
|
103
|
-
|
107
|
+
These structures allow static allocation of XXH states.
|
108
|
+
States must then be initialized using XXHnn_reset() before first use.
|
104
109
|
|
105
|
-
|
106
|
-
void* XXH32_init()
|
107
|
-
The function returns a pointer which holds the state of calculation.
|
108
|
-
|
109
|
-
This pointer must be provided as "void* state" parameter for XXH32_update().
|
110
|
-
XXH32_update() can be called as many times as necessary.
|
111
|
-
The user must provide a valid (allocated) input.
|
112
|
-
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
113
|
-
Note that "len" is type "int", which means it is limited to 2^31-1.
|
114
|
-
If your data is larger, it is recommended to chunk your data into blocks
|
115
|
-
of size for example 2^30 (1GB) to avoid any "int" overflow issue.
|
116
|
-
|
117
|
-
Finally, you can end the calculation anytime, by using XXH32_digest().
|
118
|
-
This function returns the final 32-bits hash.
|
119
|
-
You must provide the same "void* state" parameter created by XXH32_init().
|
120
|
-
Memory will be freed by XXH32_digest().
|
110
|
+
If you prefer dynamic allocation, please refer to functions below.
|
121
111
|
*/
|
122
112
|
|
113
|
+
XXH32_state_t* XXH32_createState(void);
|
114
|
+
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
123
115
|
|
124
|
-
|
125
|
-
XXH_errorcode
|
116
|
+
XXH64_state_t* XXH64_createState(void);
|
117
|
+
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
126
118
|
|
127
|
-
#define XXH32_SIZEOFSTATE 48
|
128
|
-
typedef struct { long long ll[(XXH32_SIZEOFSTATE+(sizeof(long long)-1))/sizeof(long long)]; } XXH32_stateSpace_t;
|
129
119
|
/*
|
130
|
-
These functions
|
120
|
+
These functions create and release memory for XXH state.
|
121
|
+
States must then be initialized using XXHnn_reset() before first use.
|
122
|
+
*/
|
131
123
|
|
132
|
-
XXH32_sizeofState() is used to know how much space must be allocated for the xxHash 32-bits state.
|
133
|
-
Note that the state must be aligned to access 'long long' fields. Memory must be allocated and referenced by a pointer.
|
134
|
-
This pointer must then be provided as 'state' into XXH32_resetState(), which initializes the state.
|
135
124
|
|
136
|
-
|
137
|
-
|
138
|
-
|
125
|
+
XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned seed);
|
126
|
+
XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
127
|
+
unsigned int XXH32_digest (const XXH32_state_t* statePtr);
|
139
128
|
|
129
|
+
XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
130
|
+
XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
131
|
+
unsigned long long XXH64_digest (const XXH64_state_t* statePtr);
|
140
132
|
|
141
|
-
unsigned int XXH32_intermediateDigest (void* state);
|
142
133
|
/*
|
143
|
-
|
144
|
-
|
145
|
-
This way, it becomes possible to generate intermediate hashes, and then continue feeding data with XXH32_update().
|
146
|
-
To free memory context, use XXH32_digest(), or free().
|
147
|
-
*/
|
134
|
+
These functions calculate the xxHash of an input provided in multiple smaller packets,
|
135
|
+
as opposed to an input provided as a single block.
|
148
136
|
|
137
|
+
XXH state space must first be allocated, using either static or dynamic method provided above.
|
149
138
|
|
139
|
+
Start a new hash by initializing state with a seed, using XXHnn_reset().
|
150
140
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
// The following translations are provided to ease code transition
|
155
|
-
// You are encouraged to no longer this function names
|
156
|
-
#define XXH32_feed XXH32_update
|
157
|
-
#define XXH32_result XXH32_digest
|
158
|
-
#define XXH32_getIntermediateResult XXH32_intermediateDigest
|
141
|
+
Then, feed the hash state by calling XXHnn_update() as many times as necessary.
|
142
|
+
Obviously, input must be valid, meaning allocated and read accessible.
|
143
|
+
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
159
144
|
|
145
|
+
Finally, you can produce a hash anytime, by using XXHnn_digest().
|
146
|
+
This function returns the final nn-bits hash.
|
147
|
+
You can nonetheless continue feeding the hash state with more input,
|
148
|
+
and therefore get some new hashes, by calling again XXHnn_digest().
|
149
|
+
|
150
|
+
When you are done, don't forget to free XXH state space, using typically XXHnn_freeState().
|
151
|
+
*/
|
160
152
|
|
161
153
|
|
162
154
|
#if defined (__cplusplus)
|
163
155
|
}
|
164
|
-
#endif
|
156
|
+
#endif
|
data/ext/xxhash/xxhash.c
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
#include "xxhash.h"
|
2
|
+
|
3
|
+
VALUE xxhash_xxh32(VALUE mod, VALUE input, VALUE seed)
|
4
|
+
{
|
5
|
+
return ULL2NUM(XXH32(StringValuePtr(input), (size_t)RSTRING_LEN(input), (unsigned int)NUM2ULL(seed)));
|
6
|
+
}
|
7
|
+
|
8
|
+
void xxhash32_streaming_hash_free(XXH32_state_t* state)
|
9
|
+
{
|
10
|
+
// Digest frees the memory.
|
11
|
+
XXH32_freeState(state);
|
12
|
+
}
|
13
|
+
|
14
|
+
VALUE xxhash32_streaming_hash_new(VALUE klass, VALUE seed)
|
15
|
+
{
|
16
|
+
XXH32_state_t* state = XXH32_createState();
|
17
|
+
XXH_errorcode code = XXH32_reset(state, (unsigned int)NUM2ULL(seed));
|
18
|
+
if(code != XXH_OK) {
|
19
|
+
rb_raise(rb_eRuntimeError, "Error during reset.");
|
20
|
+
return Qnil;
|
21
|
+
}
|
22
|
+
return Data_Wrap_Struct(klass, 0, xxhash32_streaming_hash_free, state);
|
23
|
+
}
|
24
|
+
|
25
|
+
VALUE xxhash32_streaming_hash_update(VALUE self, VALUE data)
|
26
|
+
{
|
27
|
+
XXH32_state_t* state;
|
28
|
+
Data_Get_Struct(self, XXH32_state_t, state);
|
29
|
+
|
30
|
+
XXH_errorcode code = XXH32_update(state, StringValuePtr(data), (size_t)RSTRING_LEN(data));
|
31
|
+
if(code != XXH_OK) {
|
32
|
+
rb_raise(rb_eRuntimeError, "Error during update.");
|
33
|
+
}
|
34
|
+
return Qnil;
|
35
|
+
}
|
36
|
+
|
37
|
+
VALUE xxhash32_streaming_hash_digest(VALUE self)
|
38
|
+
{
|
39
|
+
XXH32_state_t* state;
|
40
|
+
Data_Get_Struct(self, XXH32_state_t, state);
|
41
|
+
|
42
|
+
// Do not free memory now.
|
43
|
+
return ULL2NUM(XXH32_digest(state));
|
44
|
+
}
|
45
|
+
|
46
|
+
VALUE xxhash_xxh64(VALUE mod, VALUE input, VALUE seed)
|
47
|
+
{
|
48
|
+
return ULL2NUM(XXH64(StringValuePtr(input), (size_t)RSTRING_LEN(input), (unsigned int)NUM2ULL(seed)));
|
49
|
+
}
|
50
|
+
|
51
|
+
void xxhash64_streaming_hash_free(XXH64_state_t* state)
|
52
|
+
{
|
53
|
+
// Digest frees the memory.
|
54
|
+
XXH64_freeState(state);
|
55
|
+
}
|
56
|
+
|
57
|
+
VALUE xxhash64_streaming_hash_new(VALUE klass, VALUE seed)
|
58
|
+
{
|
59
|
+
XXH64_state_t* state = XXH64_createState();
|
60
|
+
XXH_errorcode code = XXH64_reset(state, NUM2ULL(seed));
|
61
|
+
if(code != XXH_OK) {
|
62
|
+
rb_raise(rb_eRuntimeError, "Error during reset.");
|
63
|
+
return Qnil;
|
64
|
+
}
|
65
|
+
return Data_Wrap_Struct(klass, 0, xxhash64_streaming_hash_free, state);
|
66
|
+
}
|
67
|
+
|
68
|
+
VALUE xxhash64_streaming_hash_update(VALUE self, VALUE data)
|
69
|
+
{
|
70
|
+
XXH64_state_t* state;
|
71
|
+
Data_Get_Struct(self, XXH64_state_t, state);
|
72
|
+
|
73
|
+
XXH_errorcode code = XXH64_update(state, StringValuePtr(data), (size_t)RSTRING_LEN(data));
|
74
|
+
if(code != XXH_OK) {
|
75
|
+
rb_raise(rb_eRuntimeError, "Error during update.");
|
76
|
+
}
|
77
|
+
return Qnil;
|
78
|
+
}
|
79
|
+
|
80
|
+
VALUE xxhash64_streaming_hash_digest(VALUE self)
|
81
|
+
{
|
82
|
+
XXH64_state_t* state;
|
83
|
+
Data_Get_Struct(self, XXH64_state_t, state);
|
84
|
+
|
85
|
+
// Do not free memory now.
|
86
|
+
return ULL2NUM(XXH64_digest(state));
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
void Init_xxhash(void)
|
91
|
+
{
|
92
|
+
VALUE mXXhash = rb_define_module("XXhash");
|
93
|
+
VALUE mInternal = rb_define_module_under(mXXhash, "XXhashInternal");
|
94
|
+
|
95
|
+
rb_define_singleton_method(mInternal, "xxh32", (ruby_method*) &xxhash_xxh32, 2);
|
96
|
+
rb_define_singleton_method(mInternal, "xxh64", (ruby_method*) &xxhash_xxh64, 2);
|
97
|
+
|
98
|
+
VALUE cStreamingHash = rb_define_class_under(mInternal, "StreamingHash32", rb_cObject);
|
99
|
+
|
100
|
+
rb_define_singleton_method(cStreamingHash, "new", (ruby_method*) &xxhash32_streaming_hash_new, 1);
|
101
|
+
rb_define_method(cStreamingHash, "update", (ruby_method*) &xxhash32_streaming_hash_update, 1);
|
102
|
+
rb_define_method(cStreamingHash, "digest", (ruby_method*) &xxhash32_streaming_hash_digest, 0);
|
103
|
+
|
104
|
+
VALUE cStreamingHash64 = rb_define_class_under(mInternal, "StreamingHash64", rb_cObject);
|
105
|
+
|
106
|
+
rb_define_singleton_method(cStreamingHash64, "new", (ruby_method*) &xxhash64_streaming_hash_new, 1);
|
107
|
+
rb_define_method(cStreamingHash64, "update", (ruby_method*) &xxhash64_streaming_hash_update, 1);
|
108
|
+
rb_define_method(cStreamingHash64, "digest", (ruby_method*) &xxhash64_streaming_hash_digest, 0);
|
109
|
+
}
|
data/ext/xxhash/xxhash.h
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include "libxxhash.h"
|
3
|
+
|
4
|
+
// Use this typedef to make the compiler happy when
|
5
|
+
// calling rb_define_method()
|
6
|
+
typedef VALUE (ruby_method)();
|
7
|
+
|
8
|
+
VALUE xxhash_xxh32(VALUE mod, VALUE input, VALUE seed);
|
9
|
+
void xxhash32_streaming_hash_free(XXH32_state_t* state);
|
10
|
+
VALUE xxhash32_streaming_hash_new(VALUE klass, VALUE seed);
|
11
|
+
VALUE xxhash32_streaming_hash_update(VALUE self, VALUE data);
|
12
|
+
VALUE xxhash32_streaming_hash_digest(VALUE self);
|
13
|
+
VALUE xxhash_xxh64(VALUE mod, VALUE input, VALUE seed);
|
14
|
+
void xxhash64_streaming_hash_free(XXH64_state_t* state);
|
15
|
+
VALUE xxhash64_streaming_hash_new(VALUE klass, VALUE seed);
|
16
|
+
VALUE xxhash64_streaming_hash_update(VALUE self, VALUE data);
|
17
|
+
VALUE xxhash64_streaming_hash_digest(VALUE self);
|
18
|
+
void Init_xxhash(void);
|
data/lib/xxhash.rb
CHANGED
@@ -2,14 +2,30 @@ require 'xxhash/version'
|
|
2
2
|
require 'xxhash/xxhash'
|
3
3
|
|
4
4
|
module XXhash
|
5
|
-
def self.xxh32(input, seed)
|
6
|
-
|
5
|
+
def self.xxh32(input, seed = 0)
|
6
|
+
XXhashInternal.xxh32(input, seed)
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.
|
9
|
+
def self.xxh64(input, seed = 0)
|
10
|
+
XXhashInternal.xxh64(input, seed)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.xxh32_stream(io, seed = 0, chunk_size = 32)
|
14
|
+
raise ArgumentError, 'first argument should be IO' if !io.is_a?(IO) && !io.is_a?(StringIO)
|
15
|
+
|
16
|
+
hash = XXhashInternal::StreamingHash32.new(seed)
|
17
|
+
|
18
|
+
while chunk = io.read(chunk_size)
|
19
|
+
hash.update(chunk)
|
20
|
+
end
|
21
|
+
|
22
|
+
hash.digest
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.xxh64_stream(io, seed = 0, chunk_size = 32)
|
10
26
|
raise ArgumentError, 'first argument should be IO' if !io.is_a?(IO) && !io.is_a?(StringIO)
|
11
27
|
|
12
|
-
hash =
|
28
|
+
hash = XXhashInternal::StreamingHash64.new(seed)
|
13
29
|
|
14
30
|
while chunk = io.read(chunk_size)
|
15
31
|
hash.update(chunk)
|
data/lib/xxhash/version.rb
CHANGED
data/test/xxhash_test.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
|
-
|
1
|
+
require_relative 'test_helper'
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
describe XXhash do
|
5
|
-
it 'returns hash' do
|
5
|
+
it 'returns 32-bit hash' do
|
6
6
|
assert_equal 2758658570, XXhash.xxh32('test', 123)
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
it 'returns 64-bit hash' do
|
10
|
+
assert_equal 3134990500624303823, XXhash.xxh64('test', 123)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'uses 0 (default value) if seed is not specified' do
|
14
|
+
assert_equal 1042293711, XXhash.xxh32('test')
|
15
|
+
assert_equal 5754696928334414137, XXhash.xxh64('test')
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'StreamingHash32' do
|
19
|
+
|
20
|
+
it 'rises ArgumentError if first argument is not IO object' do
|
11
21
|
assert_raises(ArgumentError) do
|
12
22
|
XXhash.xxh32_stream('test', 123)
|
13
23
|
end
|
@@ -23,4 +33,22 @@ describe XXhash do
|
|
23
33
|
assert_equal h1, h2
|
24
34
|
end
|
25
35
|
end
|
36
|
+
|
37
|
+
describe 'StreamingHash64' do
|
38
|
+
it 'rises ArgumentError if first argument is not IO object' do
|
39
|
+
assert_raises(ArgumentError) do
|
40
|
+
XXhash.xxh64_stream('test', 123)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns the hash for streamed strings' do
|
45
|
+
assert_equal 3134990500624303823, XXhash.xxh64_stream(StringIO.new('test'), 123)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns the hash for streamed files' do
|
49
|
+
h1 = XXhash.xxh64(File.read(__FILE__), 123)
|
50
|
+
h2 = XXhash.xxh64_stream(File.open(__FILE__), 123)
|
51
|
+
assert_equal h1, h2
|
52
|
+
end
|
53
|
+
end
|
26
54
|
end
|
data/xxhash.gemspec
CHANGED
@@ -11,7 +11,8 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.description = %q{Ruby wrapper for xxHash lib}
|
12
12
|
gem.summary = %q{Ruby wrapper for xxHash lib}
|
13
13
|
gem.homepage = "http://github.com/nashby/xxhash"
|
14
|
-
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
15
16
|
gem.files = `git ls-files`.split($/)
|
16
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xxhash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Vasiliy Ermolovich
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-01-18 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
13
|
description: Ruby wrapper for xxHash lib
|
15
14
|
email:
|
@@ -19,8 +18,8 @@ extensions:
|
|
19
18
|
- ext/xxhash/extconf.rb
|
20
19
|
extra_rdoc_files: []
|
21
20
|
files:
|
22
|
-
- .gitignore
|
23
|
-
- .travis.yml
|
21
|
+
- ".gitignore"
|
22
|
+
- ".travis.yml"
|
24
23
|
- CHANGELOG.md
|
25
24
|
- Gemfile
|
26
25
|
- LICENSE.txt
|
@@ -29,41 +28,36 @@ files:
|
|
29
28
|
- ext/xxhash/extconf.rb
|
30
29
|
- ext/xxhash/libxxhash.c
|
31
30
|
- ext/xxhash/libxxhash.h
|
32
|
-
- ext/xxhash/xxhash.
|
31
|
+
- ext/xxhash/xxhash.c
|
32
|
+
- ext/xxhash/xxhash.h
|
33
33
|
- lib/xxhash.rb
|
34
34
|
- lib/xxhash/version.rb
|
35
35
|
- test/test_helper.rb
|
36
36
|
- test/xxhash_test.rb
|
37
37
|
- xxhash.gemspec
|
38
38
|
homepage: http://github.com/nashby/xxhash
|
39
|
-
licenses:
|
39
|
+
licenses:
|
40
|
+
- MIT
|
41
|
+
metadata: {}
|
40
42
|
post_install_message:
|
41
43
|
rdoc_options: []
|
42
44
|
require_paths:
|
43
45
|
- lib
|
44
46
|
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
-
none: false
|
46
47
|
requirements:
|
47
|
-
- -
|
48
|
+
- - ">="
|
48
49
|
- !ruby/object:Gem::Version
|
49
50
|
version: '0'
|
50
|
-
segments:
|
51
|
-
- 0
|
52
|
-
hash: -3728750430932162062
|
53
51
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
-
none: false
|
55
52
|
requirements:
|
56
|
-
- -
|
53
|
+
- - ">="
|
57
54
|
- !ruby/object:Gem::Version
|
58
55
|
version: '0'
|
59
|
-
segments:
|
60
|
-
- 0
|
61
|
-
hash: -3728750430932162062
|
62
56
|
requirements: []
|
63
57
|
rubyforge_project:
|
64
|
-
rubygems_version:
|
58
|
+
rubygems_version: 2.2.2
|
65
59
|
signing_key:
|
66
|
-
specification_version:
|
60
|
+
specification_version: 4
|
67
61
|
summary: Ruby wrapper for xxHash lib
|
68
62
|
test_files:
|
69
63
|
- test/test_helper.rb
|