xxhash 0.4.0 → 0.6.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 +5 -5
- data/.github/workflows/ruby.yml +35 -0
- data/CHANGELOG.md +10 -1
- data/Gemfile +1 -1
- data/README.md +11 -6
- data/ext/xxhash/libxxhash.c +36 -881
- data/ext/xxhash/libxxhash.h +5452 -173
- data/ext/xxhash/xxhash.c +114 -10
- data/ext/xxhash/xxhash.h +3 -2
- data/lib/xxhash/version.rb +1 -1
- data/lib/xxhash.rb +8 -0
- data/test/xxhash_test.rb +31 -0
- metadata +7 -8
- data/.travis.yml +0 -9
data/ext/xxhash/xxhash.c
CHANGED
@@ -1,17 +1,96 @@
|
|
1
1
|
#include "xxhash.h"
|
2
2
|
|
3
|
+
VALUE xxhash_xxh32_file(VALUE mod, VALUE filename, VALUE seed)
|
4
|
+
{
|
5
|
+
StringValue(filename);
|
6
|
+
|
7
|
+
XXH32_state_t* state = XXH32_createState();
|
8
|
+
if (state == NULL) {
|
9
|
+
rb_raise(rb_eRuntimeError, "%s", "Cannot create state, out of memory");
|
10
|
+
}
|
11
|
+
|
12
|
+
XXH32_reset(state, NUM2INT(seed));
|
13
|
+
|
14
|
+
char buffer[16384];
|
15
|
+
size_t count;
|
16
|
+
FILE *fp = fopen(RSTRING_PTR(filename), "rb");
|
17
|
+
if (fp == NULL) {
|
18
|
+
XXH32_freeState(state);
|
19
|
+
VALUE error = INT2FIX(errno);
|
20
|
+
rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
|
21
|
+
}
|
22
|
+
|
23
|
+
while ((count = fread(buffer, 1, sizeof(buffer), fp)) != 0) {
|
24
|
+
XXH32_update(state, buffer, count);
|
25
|
+
}
|
26
|
+
fclose(fp);
|
27
|
+
|
28
|
+
XXH32_hash_t result = XXH32_digest(state);
|
29
|
+
|
30
|
+
XXH32_freeState(state);
|
31
|
+
return ULL2NUM(result);
|
32
|
+
}
|
33
|
+
|
34
|
+
VALUE xxhash_xxh64_file(VALUE mod, VALUE filename, VALUE seed)
|
35
|
+
{
|
36
|
+
StringValue(filename);
|
37
|
+
|
38
|
+
XXH64_state_t* state = XXH64_createState();
|
39
|
+
if (state == NULL) {
|
40
|
+
rb_raise(rb_eRuntimeError, "%s", "Cannot create state, out of memory");
|
41
|
+
}
|
42
|
+
|
43
|
+
XXH64_reset(state, NUM2INT(seed));
|
44
|
+
|
45
|
+
char buffer[16384];
|
46
|
+
size_t count;
|
47
|
+
FILE *fp = fopen(RSTRING_PTR(filename), "rb");
|
48
|
+
if (fp == NULL) {
|
49
|
+
XXH64_freeState(state);
|
50
|
+
VALUE error = INT2FIX(errno);
|
51
|
+
rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
|
52
|
+
}
|
53
|
+
|
54
|
+
while ((count = fread(buffer, 1, sizeof(buffer), fp)) != 0) {
|
55
|
+
XXH64_update(state, buffer, count);
|
56
|
+
}
|
57
|
+
fclose(fp);
|
58
|
+
|
59
|
+
XXH64_hash_t result = XXH64_digest(state);
|
60
|
+
|
61
|
+
XXH64_freeState(state);
|
62
|
+
return ULL2NUM(result);
|
63
|
+
}
|
64
|
+
|
3
65
|
VALUE xxhash_xxh32(VALUE mod, VALUE input, VALUE seed)
|
4
66
|
{
|
5
67
|
return ULL2NUM(XXH32(StringValuePtr(input), (size_t)RSTRING_LEN(input), (unsigned int)NUM2ULL(seed)));
|
6
68
|
}
|
7
69
|
|
8
|
-
void xxhash32_streaming_hash_free(
|
70
|
+
static void xxhash32_streaming_hash_free(void *ptr)
|
9
71
|
{
|
72
|
+
xxhash_xxh32_t* storage = (xxhash_xxh32_t*)ptr;
|
10
73
|
// Digest frees the memory.
|
11
74
|
XXH32_freeState(storage->state);
|
12
75
|
xfree(storage);
|
13
76
|
}
|
14
77
|
|
78
|
+
static size_t xxhash32_streaming_hash_memsize(const void *ptr)
|
79
|
+
{
|
80
|
+
// Ideally we'd include sizeof(XXH32_state_t) too, but the type is opaque.
|
81
|
+
return sizeof(xxhash_xxh32_t);
|
82
|
+
}
|
83
|
+
|
84
|
+
static const rb_data_type_t xxhash_xxh32_type = {
|
85
|
+
.wrap_struct_name = "xxhash/xxhash32_streaming_hash",
|
86
|
+
.function = {
|
87
|
+
.dmark = NULL,
|
88
|
+
.dfree = xxhash32_streaming_hash_free,
|
89
|
+
.dsize = xxhash32_streaming_hash_memsize,
|
90
|
+
},
|
91
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
|
92
|
+
};
|
93
|
+
|
15
94
|
VALUE xxhash32_streaming_hash_new(VALUE klass, VALUE seed)
|
16
95
|
{
|
17
96
|
XXH_errorcode code;
|
@@ -24,14 +103,14 @@ VALUE xxhash32_streaming_hash_new(VALUE klass, VALUE seed)
|
|
24
103
|
rb_raise(rb_eRuntimeError, "Error during reset.");
|
25
104
|
return Qnil;
|
26
105
|
}
|
27
|
-
return
|
106
|
+
return TypedData_Wrap_Struct(klass, &xxhash_xxh32_type, storage);
|
28
107
|
}
|
29
108
|
|
30
109
|
VALUE xxhash32_streaming_hash_reset(VALUE self)
|
31
110
|
{
|
32
111
|
XXH_errorcode code;
|
33
112
|
xxhash_xxh32_t* storage;
|
34
|
-
|
113
|
+
TypedData_Get_Struct(self, xxhash_xxh32_t, &xxhash_xxh32_type, storage);
|
35
114
|
|
36
115
|
code = XXH32_reset(storage->state, storage->seed);
|
37
116
|
if(code != XXH_OK) {
|
@@ -45,7 +124,7 @@ VALUE xxhash32_streaming_hash_update(VALUE self, VALUE data)
|
|
45
124
|
{
|
46
125
|
XXH_errorcode code;
|
47
126
|
xxhash_xxh32_t* storage;
|
48
|
-
|
127
|
+
TypedData_Get_Struct(self, xxhash_xxh32_t, &xxhash_xxh32_type, storage);
|
49
128
|
|
50
129
|
code = XXH32_update(storage->state, StringValuePtr(data), (size_t)RSTRING_LEN(data));
|
51
130
|
if(code != XXH_OK) {
|
@@ -57,7 +136,7 @@ VALUE xxhash32_streaming_hash_update(VALUE self, VALUE data)
|
|
57
136
|
VALUE xxhash32_streaming_hash_digest(VALUE self)
|
58
137
|
{
|
59
138
|
xxhash_xxh32_t* storage;
|
60
|
-
|
139
|
+
TypedData_Get_Struct(self, xxhash_xxh32_t, &xxhash_xxh32_type, storage);
|
61
140
|
|
62
141
|
// Do not free memory now.
|
63
142
|
return ULL2NUM(XXH32_digest(storage->state));
|
@@ -68,13 +147,30 @@ VALUE xxhash_xxh64(VALUE mod, VALUE input, VALUE seed)
|
|
68
147
|
return ULL2NUM(XXH64(StringValuePtr(input), (size_t)RSTRING_LEN(input), (unsigned int)NUM2ULL(seed)));
|
69
148
|
}
|
70
149
|
|
71
|
-
void xxhash64_streaming_hash_free(
|
150
|
+
static void xxhash64_streaming_hash_free(void *ptr)
|
72
151
|
{
|
152
|
+
xxhash_xxh64_t* storage = (xxhash_xxh64_t*)ptr;
|
73
153
|
// Digest frees the memory.
|
74
154
|
XXH64_freeState(storage->state);
|
75
155
|
xfree(storage);
|
76
156
|
}
|
77
157
|
|
158
|
+
static size_t xxhash64_streaming_hash_memsize(const void *ptr)
|
159
|
+
{
|
160
|
+
// Ideally we'd include sizeof(XXH64_state_t) too, but the type is opaque.
|
161
|
+
return sizeof(xxhash_xxh64_t);
|
162
|
+
}
|
163
|
+
|
164
|
+
static const rb_data_type_t xxhash_xxh64_type = {
|
165
|
+
.wrap_struct_name = "xxhash/xxhash64_streaming_hash",
|
166
|
+
.function = {
|
167
|
+
.dmark = NULL,
|
168
|
+
.dfree = xxhash64_streaming_hash_free,
|
169
|
+
.dsize = xxhash64_streaming_hash_memsize,
|
170
|
+
},
|
171
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
|
172
|
+
};
|
173
|
+
|
78
174
|
VALUE xxhash64_streaming_hash_new(VALUE klass, VALUE seed)
|
79
175
|
{
|
80
176
|
XXH_errorcode code;
|
@@ -88,14 +184,14 @@ VALUE xxhash64_streaming_hash_new(VALUE klass, VALUE seed)
|
|
88
184
|
rb_raise(rb_eRuntimeError, "Error during reset.");
|
89
185
|
return Qnil;
|
90
186
|
}
|
91
|
-
return
|
187
|
+
return TypedData_Wrap_Struct(klass, &xxhash_xxh64_type, storage);
|
92
188
|
}
|
93
189
|
|
94
190
|
VALUE xxhash64_streaming_hash_reset(VALUE self)
|
95
191
|
{
|
96
192
|
XXH_errorcode code;
|
97
193
|
xxhash_xxh64_t* storage;
|
98
|
-
|
194
|
+
TypedData_Get_Struct(self, xxhash_xxh64_t, &xxhash_xxh64_type, storage);
|
99
195
|
|
100
196
|
code = XXH64_reset(storage->state, storage->seed);
|
101
197
|
if(code != XXH_OK) {
|
@@ -108,7 +204,7 @@ VALUE xxhash64_streaming_hash_update(VALUE self, VALUE data)
|
|
108
204
|
{
|
109
205
|
XXH_errorcode code;
|
110
206
|
xxhash_xxh64_t* storage;
|
111
|
-
|
207
|
+
TypedData_Get_Struct(self, xxhash_xxh64_t, &xxhash_xxh64_type, storage);
|
112
208
|
|
113
209
|
code = XXH64_update(storage->state, StringValuePtr(data), (size_t)RSTRING_LEN(data));
|
114
210
|
if(code != XXH_OK) {
|
@@ -120,7 +216,7 @@ VALUE xxhash64_streaming_hash_update(VALUE self, VALUE data)
|
|
120
216
|
VALUE xxhash64_streaming_hash_digest(VALUE self)
|
121
217
|
{
|
122
218
|
xxhash_xxh64_t* storage;
|
123
|
-
|
219
|
+
TypedData_Get_Struct(self, xxhash_xxh64_t, &xxhash_xxh64_type, storage);
|
124
220
|
|
125
221
|
// Do not free memory now.
|
126
222
|
return ULL2NUM(XXH64_digest(storage->state));
|
@@ -129,6 +225,10 @@ VALUE xxhash64_streaming_hash_digest(VALUE self)
|
|
129
225
|
|
130
226
|
void Init_xxhash(void)
|
131
227
|
{
|
228
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
229
|
+
rb_ext_ractor_safe(true);
|
230
|
+
#endif
|
231
|
+
|
132
232
|
VALUE cStreamingHash;
|
133
233
|
VALUE cStreamingHash64;
|
134
234
|
VALUE mXXhash;
|
@@ -138,9 +238,12 @@ void Init_xxhash(void)
|
|
138
238
|
mInternal = rb_define_module_under(mXXhash, "XXhashInternal");
|
139
239
|
|
140
240
|
rb_define_singleton_method(mInternal, "xxh32", (ruby_method*) &xxhash_xxh32, 2);
|
241
|
+
rb_define_singleton_method(mInternal, "xxh32_file", (ruby_method*) &xxhash_xxh32_file, 2);
|
141
242
|
rb_define_singleton_method(mInternal, "xxh64", (ruby_method*) &xxhash_xxh64, 2);
|
243
|
+
rb_define_singleton_method(mInternal, "xxh64_file", (ruby_method*) &xxhash_xxh64_file, 2);
|
142
244
|
|
143
245
|
cStreamingHash = rb_define_class_under(mInternal, "StreamingHash32", rb_cObject);
|
246
|
+
rb_undef_alloc_func(cStreamingHash);
|
144
247
|
|
145
248
|
rb_define_singleton_method(cStreamingHash, "new", (ruby_method*) &xxhash32_streaming_hash_new, 1);
|
146
249
|
rb_define_method(cStreamingHash, "update", (ruby_method*) &xxhash32_streaming_hash_update, 1);
|
@@ -148,6 +251,7 @@ void Init_xxhash(void)
|
|
148
251
|
rb_define_method(cStreamingHash, "reset", (ruby_method*) &xxhash32_streaming_hash_reset, 0);
|
149
252
|
|
150
253
|
cStreamingHash64 = rb_define_class_under(mInternal, "StreamingHash64", rb_cObject);
|
254
|
+
rb_undef_alloc_func(cStreamingHash64);
|
151
255
|
|
152
256
|
rb_define_singleton_method(cStreamingHash64, "new", (ruby_method*) &xxhash64_streaming_hash_new, 1);
|
153
257
|
rb_define_method(cStreamingHash64, "update", (ruby_method*) &xxhash64_streaming_hash_update, 1);
|
data/ext/xxhash/xxhash.h
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include <stdlib.h>
|
2
|
+
#include <errno.h>
|
2
3
|
#include <ruby.h>
|
3
4
|
#include "libxxhash.h"
|
4
5
|
|
@@ -17,13 +18,13 @@ typedef struct {
|
|
17
18
|
typedef VALUE (ruby_method)();
|
18
19
|
|
19
20
|
VALUE xxhash_xxh32(VALUE mod, VALUE input, VALUE seed);
|
20
|
-
|
21
|
+
VALUE xxhash_xxh32_file(VALUE mod, VALUE filename, VALUE seed);
|
21
22
|
VALUE xxhash32_streaming_hash_new(VALUE klass, VALUE seed);
|
22
23
|
VALUE xxhash32_streaming_hash_update(VALUE self, VALUE data);
|
23
24
|
VALUE xxhash32_streaming_hash_reset(VALUE self);
|
24
25
|
VALUE xxhash32_streaming_hash_digest(VALUE self);
|
25
26
|
VALUE xxhash_xxh64(VALUE mod, VALUE input, VALUE seed);
|
26
|
-
|
27
|
+
VALUE xxhash_xxh64_file(VALUE mod, VALUE filename, VALUE seed);
|
27
28
|
VALUE xxhash64_streaming_hash_new(VALUE klass, VALUE seed);
|
28
29
|
VALUE xxhash64_streaming_hash_update(VALUE self, VALUE data);
|
29
30
|
VALUE xxhash64_streaming_hash_reset(VALUE self);
|
data/lib/xxhash/version.rb
CHANGED
data/lib/xxhash.rb
CHANGED
@@ -11,6 +11,14 @@ module XXhash
|
|
11
11
|
XXhashInternal.xxh64(input.to_s, seed.to_i)
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.xxh32_file(filename, seed = 0)
|
15
|
+
XXhashInternal.xxh32_file(filename.to_s, seed.to_i)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.xxh64_file(filename, seed = 0)
|
19
|
+
XXhashInternal.xxh64_file(filename.to_s, seed.to_i)
|
20
|
+
end
|
21
|
+
|
14
22
|
def self.xxh32_stream(io, seed = 0, chunk_size = 32)
|
15
23
|
seed = seed.to_i
|
16
24
|
chunk_size = chunk_size.to_i
|
data/test/xxhash_test.rb
CHANGED
@@ -2,19 +2,50 @@ require_relative 'test_helper'
|
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
describe XXhash do
|
5
|
+
it 'is marked as ractor-safe' do
|
6
|
+
skip("Ractorrs are not supported in this version of ruby(#{RUBY_VERSION})") unless defined?(Ractor)
|
7
|
+
|
8
|
+
ractor = Ractor.new do
|
9
|
+
Ractor.yield XXhash.xxh32(Ractor.receive)
|
10
|
+
end
|
11
|
+
|
12
|
+
ractor.send('test')
|
13
|
+
assert_equal ractor.take, XXhash.xxh32('test')
|
14
|
+
end
|
15
|
+
|
5
16
|
it 'returns 32-bit hash' do
|
6
17
|
assert_equal 2758658570, XXhash.xxh32('test', 123)
|
7
18
|
end
|
8
19
|
|
20
|
+
it 'returns 32-bit hash from a file' do
|
21
|
+
assert_equal XXhash.xxh32(File.read(__FILE__)), XXhash.xxh32_file(__FILE__)
|
22
|
+
assert_equal XXhash.xxh32(File.read(__FILE__), 123), XXhash.xxh32_file(__FILE__, 123)
|
23
|
+
end
|
24
|
+
|
9
25
|
it 'returns 64-bit hash' do
|
10
26
|
assert_equal 3134990500624303823, XXhash.xxh64('test', 123)
|
11
27
|
end
|
12
28
|
|
29
|
+
it 'returns 64-bit hash from a file' do
|
30
|
+
assert_equal XXhash.xxh64(File.read(__FILE__)), XXhash.xxh64_file(__FILE__)
|
31
|
+
assert_equal XXhash.xxh64(File.read(__FILE__), 123), XXhash.xxh64_file(__FILE__, 123)
|
32
|
+
end
|
33
|
+
|
13
34
|
it 'uses 0 (default value) if seed is not specified' do
|
14
35
|
assert_equal 1042293711, XXhash.xxh32('test')
|
15
36
|
assert_equal 5754696928334414137, XXhash.xxh64('test')
|
16
37
|
end
|
17
38
|
|
39
|
+
it 'raises an Errno exception for invalid file' do
|
40
|
+
assert_raises Errno::ENOENT do
|
41
|
+
XXhash.xxh32_file('nonexistent-file')
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_raises Errno::ENOENT do
|
45
|
+
XXhash.xxh64_file('nonexistent-file')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
18
49
|
describe 'XXhashInternal::StreamingHash32' do
|
19
50
|
|
20
51
|
it 'rises ArgumentError if first argument is not IO object' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xxhash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasiliy Ermolovich
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby wrapper for xxHash lib
|
14
14
|
email:
|
@@ -18,8 +18,8 @@ extensions:
|
|
18
18
|
- ext/xxhash/extconf.rb
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
+
- ".github/workflows/ruby.yml"
|
21
22
|
- ".gitignore"
|
22
|
-
- ".travis.yml"
|
23
23
|
- CHANGELOG.md
|
24
24
|
- Gemfile
|
25
25
|
- LICENSE.txt
|
@@ -39,7 +39,7 @@ homepage: http://github.com/nashby/xxhash
|
|
39
39
|
licenses:
|
40
40
|
- MIT
|
41
41
|
metadata: {}
|
42
|
-
post_install_message:
|
42
|
+
post_install_message:
|
43
43
|
rdoc_options: []
|
44
44
|
require_paths:
|
45
45
|
- lib
|
@@ -54,9 +54,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
requirements: []
|
57
|
-
|
58
|
-
|
59
|
-
signing_key:
|
57
|
+
rubygems_version: 3.5.16
|
58
|
+
signing_key:
|
60
59
|
specification_version: 4
|
61
60
|
summary: Ruby wrapper for xxHash lib
|
62
61
|
test_files:
|