digest-xxhash 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 89f6bcb49f857af24e726b360ba1f0f4ce8de03c
4
+ data.tar.gz: 00341374c8aa7499599a41fd9d3f17e0ad522573
5
+ SHA512:
6
+ metadata.gz: b6d3e2afd0fcc4bfc4fa01bfe3315600b5d0939be148f90a97a90121993dcace0e49555c26b91a49278f429679ee81eebde22e08c786aa186f635fbe84c15d98
7
+ data.tar.gz: 17f501e8a8a864004532684ddebe011f52bf26d802827934595fbc2daf961477942260701ab48b544d92d69078c09e822a6222a91d9f768b3d01c98e595913b7
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 konsolebox
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # digest-xxhash-ruby
2
+
3
+ This gem 'digest-xxhash' provides XXH32 and XXH64 functions for Ruby. It works
4
+ on top of Digest::Class and complies with the functional design of
5
+ Digest::Instance.
6
+
7
+ Its core implementation was taken from the official source, which is
8
+ in https://github.com/Cyan4973/xxHash.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'digest-xxhash'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install digest-xxhash
23
+
24
+ ## Example Usage
25
+
26
+ require 'digest/xxhash'
27
+
28
+ Digest::XXH32.digest("ABXY")
29
+ => "\x0E\xA4\xB6\xCA"
30
+
31
+ Digest::XXH32.hexdigest("ABXY")
32
+ => "0ea4b6ca"
33
+
34
+ Digest::XXH32.idigest("ABXY")
35
+ => 245675722
36
+
37
+ Digest::XXH32.hexdigest("1234", "\xab\xcd\xef\x00")
38
+ => "2af3be26"
39
+
40
+ Digest::XXH32.hexdigest("1234", "abcdef00")
41
+ => "2af3be26"
42
+
43
+ Digest::XXH32.hexdigest("1234", 2882400000)
44
+ => "2af3be26"
45
+
46
+ Digest::XXH64.hexdigest("1234", "0123456789abcdef")
47
+ => "d7544504de216507"
48
+
49
+ Digest::XXH64.new("0123456789abcdef").update("1234").hexdigest
50
+ => "d7544504de216507"
51
+
52
+ Digest::XXH64.new.reset("0123456789abcdef").update("12").update("34").hexdigest
53
+ => "d7544504de216507"
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it ( https://github.com/konsolebox/digest-xxhash-ruby/fork ).
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
60
+ 4. Push to the branch (`git push origin my-new-feature`).
61
+ 5. Create a new Pull Request.
@@ -0,0 +1,20 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ # clean, clobber, compile, and compile:digest/xxhash
5
+ require 'rake/extensiontask'
6
+ Rake::ExtensionTask.new('digest/xxhash', Bundler::GemHelper.gemspec)
7
+
8
+ # test
9
+ Rake::TestTask.new(:test => :compile) do |t|
10
+ t.test_files = FileList['test/test.rb']
11
+ t.verbose = true
12
+ end
13
+
14
+ # clean
15
+ task :clean do
16
+ list = FileList.new('test/*.tmp', 'test/*.temp')
17
+ rm_f list unless list.empty?
18
+ end
19
+
20
+ # Run `rake --tasks` for a list of tasks.
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'digest/xxhash/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "digest-xxhash"
9
+ spec.version = Digest::XXHash::VERSION
10
+ spec.authors = ["konsolebox"]
11
+ spec.email = ["konsolebox@gmail.com"]
12
+ spec.summary = "XXHash for Ruby"
13
+ spec.description = "An XXHash library that complies with Digest::Instance's functional design."
14
+ spec.homepage = "https://github.com/konsolebox/digest-xxhash-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.required_ruby_version = '>= 2.2'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rake-compiler", "~> 1.0"
26
+ spec.add_development_dependency "minitest", "~> 5.8"
27
+
28
+ spec.extensions = %w[ext/digest/xxhash/extconf.rb]
29
+ end
@@ -0,0 +1,46 @@
1
+ #ifndef DEBUG_FUNCS_H
2
+ #define DEBUG_FUNCS_H
3
+
4
+ #include "utils.h"
5
+
6
+ static void print_in_hex(const char *format, const unsigned char *str, size_t len)
7
+ {
8
+ unsigned char buffer[len * 2 + 1];
9
+ hex_encode_str_implied(str, len, buffer);
10
+ buffer[len * 2] = '\0';
11
+ _DEBUG(format, buffer);
12
+ }
13
+
14
+ static void dump_state_32(XXH32_state_t *state)
15
+ {
16
+ _DEBUG("state->total_len: %u\n", state->total_len_32);
17
+ _DEBUG("state->large_len: %u\n", state->large_len);
18
+ _DEBUG("state->v1: %u\n", state->v1);
19
+ _DEBUG("state->v2: %u\n", state->v2);
20
+ _DEBUG("state->v3: %u\n", state->v3);
21
+ _DEBUG("state->v4: %u\n", state->v4);
22
+ _DEBUG("state->mem32[0]: %u\n", state->mem32[0]);
23
+ _DEBUG("state->mem32[1]: %u\n", state->mem32[1]);
24
+ _DEBUG("state->mem32[2]: %u\n", state->mem32[2]);
25
+ _DEBUG("state->mem32[3]: %u\n", state->mem32[3]);
26
+ _DEBUG("state->memsize: %u\n", state->memsize);
27
+ _DEBUG("state->reserved: %u\n", state->reserved);
28
+ }
29
+
30
+ static void dump_state_64(XXH64_state_t *state)
31
+ {
32
+ _DEBUG("state->total_len: %llu\n", state->total_len);
33
+ _DEBUG("state->v1: %llu\n", state->v1);
34
+ _DEBUG("state->v2: %llu\n", state->v2);
35
+ _DEBUG("state->v3: %llu\n", state->v3);
36
+ _DEBUG("state->v4: %llu\n", state->v4);
37
+ _DEBUG("state->mem64[0]: %llu\n", state->mem64[0]);
38
+ _DEBUG("state->mem64[1]: %llu\n", state->mem64[1]);
39
+ _DEBUG("state->mem64[2]: %llu\n", state->mem64[2]);
40
+ _DEBUG("state->mem64[3]: %llu\n", state->mem64[3]);
41
+ _DEBUG("state->memsize: %u\n", state->memsize);
42
+ _DEBUG("state->reserved[0]: %u\n", state->reserved[0]);
43
+ _DEBUG("state->reserved[1]: %u\n", state->reserved[1]);
44
+ }
45
+
46
+ #endif
@@ -0,0 +1,771 @@
1
+ /*
2
+ * Copyright (c) 2017 konsolebox
3
+ *
4
+ * MIT License
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining
7
+ * a copy of this software and associated documentation files (the
8
+ * "Software"), to deal in the Software without restriction, including
9
+ * without limitation the rights to use, copy, modify, merge, publish,
10
+ * distribute, sublicense, and/or sell copies of the Software, and to
11
+ * permit persons to whom the Software is furnished to do so, subject to
12
+ * the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be
15
+ * included in all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+
27
+ #include <ruby.h>
28
+ #include <ruby/digest.h>
29
+ #include <stdint.h>
30
+
31
+ #define XXH_STATIC_LINKING_ONLY
32
+ #include "xxhash.h"
33
+ #include "utils.h"
34
+
35
+ #define _DIGEST_API_VERSION_IS_SUPPORTED(version) (version == 3)
36
+
37
+ #if !_DIGEST_API_VERSION_IS_SUPPORTED(RUBY_DIGEST_API_VERSION)
38
+ # error Digest API version is not supported.
39
+ #endif
40
+
41
+ #define _XXH32_DIGEST_SIZE 4
42
+ #define _XXH64_DIGEST_SIZE 8
43
+
44
+ #define _XXH32_BLOCK_SIZE 4
45
+ #define _XXH64_BLOCK_SIZE 8
46
+
47
+ #define _XXH32_DEFAULT_SEED 0
48
+ #define _XXH64_DEFAULT_SEED 0
49
+
50
+ #if 0
51
+ # define _DEBUG(...) fprintf(stderr, __VA_ARGS__)
52
+ #else
53
+ # define _DEBUG(...) (void)0;
54
+ #endif
55
+
56
+ static ID _id_digest;
57
+ static ID _id_finish;
58
+ static ID _id_hexdigest;
59
+ static ID _id_idigest;
60
+ static ID _id_ifinish;
61
+ static ID _id_new;
62
+ static ID _id_reset;
63
+ static ID _id_update;
64
+
65
+ static VALUE _Digest;
66
+ static VALUE _Digest_XXHash;
67
+ static VALUE _Digest_XXH32;
68
+ static VALUE _Digest_XXH64;
69
+
70
+ /*
71
+ * Data types
72
+ */
73
+
74
+ static const rb_data_type_t _xxh32_state_data_type = {
75
+ "xxh32_state_data",
76
+ { 0, RUBY_TYPED_DEFAULT_FREE, 0, }, 0, 0,
77
+ RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
78
+ };
79
+
80
+ static const rb_data_type_t _xxh64_state_data_type = {
81
+ "xxh64_state_data",
82
+ { 0, RUBY_TYPED_DEFAULT_FREE, 0, }, 0, 0,
83
+ RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
84
+ };
85
+
86
+ /*
87
+ * Common functions
88
+ */
89
+
90
+ static XXH32_state_t *_get_state_32(VALUE self)
91
+ {
92
+ XXH32_state_t *state_p;
93
+ TypedData_Get_Struct(self, XXH32_state_t, &_xxh32_state_data_type, state_p);
94
+ return state_p;
95
+ }
96
+
97
+ static XXH64_state_t *_get_state_64(VALUE self)
98
+ {
99
+ XXH64_state_t *state_p;
100
+ TypedData_Get_Struct(self, XXH64_state_t, &_xxh64_state_data_type, state_p);
101
+ return state_p;
102
+ }
103
+
104
+ static void _xxh32_reset(XXH32_state_t *state_p, uint32_t seed)
105
+ {
106
+ if (XXH32_reset(state_p, seed) != XXH_OK)
107
+ rb_raise(rb_eRuntimeError, "Failed to reset state.");
108
+ }
109
+
110
+ static void _xxh64_reset(XXH64_state_t *state_p, uint64_t seed)
111
+ {
112
+ if (XXH64_reset(state_p, seed) != XXH_OK)
113
+ rb_raise(rb_eRuntimeError, "Failed to reset state.");
114
+ }
115
+
116
+ static VALUE _encode_big_endian_32(uint32_t num)
117
+ {
118
+ uint32_t temp;
119
+
120
+ if (is_little_endian()) {
121
+ temp = swap_uint32(num);
122
+ } else {
123
+ temp = num;
124
+ }
125
+
126
+ return rb_usascii_str_new((unsigned char *) &temp, sizeof(uint32_t));
127
+ }
128
+
129
+ static uint32_t _decode_big_endian_32_cstr(unsigned char *str)
130
+ {
131
+ uint32_t temp = read32(str);
132
+
133
+ if (is_little_endian()) {
134
+ return swap_uint32(temp);
135
+ } else {
136
+ return temp;
137
+ }
138
+ }
139
+
140
+ static uint32_t _decode_big_endian_32(VALUE str)
141
+ {
142
+ return _decode_big_endian_32_cstr(RSTRING_PTR(str));
143
+ }
144
+
145
+ static VALUE _encode_big_endian_64(uint64_t num)
146
+ {
147
+ uint64_t temp;
148
+
149
+ if (is_little_endian()) {
150
+ temp = swap_uint64(num);
151
+ } else {
152
+ temp = num;
153
+ }
154
+
155
+ return rb_usascii_str_new((unsigned char *) &temp, sizeof(uint64_t));
156
+ }
157
+
158
+ static uint64_t _decode_big_endian_64_cstr(unsigned char *str)
159
+ {
160
+ uint64_t temp = read64(str);
161
+
162
+ if (is_little_endian()) {
163
+ return swap_uint64(temp);
164
+ } else {
165
+ return temp;
166
+ }
167
+ }
168
+
169
+ static uint64_t _decode_big_endian_64(VALUE str)
170
+ {
171
+ return _decode_big_endian_64_cstr(RSTRING_PTR(str));
172
+ }
173
+
174
+ static VALUE _hex_encode_str(VALUE str)
175
+ {
176
+ int len = RSTRING_LEN(str);
177
+ VALUE hex = rb_str_new(0, len * 2);
178
+ hex_encode_str_implied(RSTRING_PTR(str), len, RSTRING_PTR(hex));
179
+ return hex;
180
+ }
181
+
182
+ /*
183
+ * Document-class: Digest::XXHash
184
+ *
185
+ * This is the base class of Digest::XXH32 and Digest::XXH64.
186
+ */
187
+
188
+ static VALUE _Digest_XXHash_internal_allocate(VALUE klass)
189
+ {
190
+ if (klass == _Digest_XXHash)
191
+ rb_raise(rb_eRuntimeError, "Digest::XXHash is an incomplete class and cannot be instantiated.");
192
+
193
+ rb_raise(rb_eNotImpError, "Allocator function not implemented.");
194
+ }
195
+
196
+ /*
197
+ * call-seq:
198
+ * new -> instance
199
+ * new(seed) -> instance
200
+ *
201
+ * Returns a new hash instance.
202
+ *
203
+ * If seed is provided, the state is reset with its value, otherwise the default
204
+ * seed (0) is used.
205
+ *
206
+ * +seed+ can be in the form of a string, a hex string, or a number.
207
+ */
208
+ static VALUE _Digest_XXHash_initialize(int argc, VALUE* argv, VALUE self)
209
+ {
210
+ if (argc > 0)
211
+ rb_funcallv(self, _id_reset, argc, argv);
212
+
213
+ return self;
214
+ }
215
+
216
+ /* :nodoc: */
217
+ static VALUE _Digest_XXHash_ifinish(VALUE self)
218
+ {
219
+ rb_raise(rb_eNotImpError, "Method not implemented.");
220
+ }
221
+
222
+ static VALUE _do_digest(int argc, VALUE* argv, VALUE self, ID finish_method_id)
223
+ {
224
+ VALUE str, seed;
225
+ int argc2 = argc > 0 ? rb_scan_args(argc, argv, "02", &str, &seed) : 0;
226
+
227
+ if (argc2 > 0) {
228
+ if (TYPE(str) != T_STRING)
229
+ rb_raise(rb_eTypeError, "Argument type not string.");
230
+
231
+ if (argc2 > 1)
232
+ rb_funcall(self, _id_reset, 1, seed);
233
+ else
234
+ rb_funcall(self, _id_reset, 0);
235
+
236
+ rb_funcall(self, _id_update, 1, str);
237
+ }
238
+
239
+ VALUE result = rb_funcall(self, finish_method_id, 0);
240
+
241
+ if (argc2 > 0)
242
+ rb_funcall(self, _id_reset, 0);
243
+
244
+ return result;
245
+ }
246
+
247
+ /*
248
+ * call-seq:
249
+ * digest -> str
250
+ * digest(str, seed = 0) -> str
251
+ *
252
+ * Returns digest value in string form.
253
+ *
254
+ * If no argument is provided, the current digest value is returned, and no
255
+ * reset happens.
256
+ *
257
+ * If a string argument is provided, the string's digest value is calculated
258
+ * with +seed+, and is used as the return value. The instance's state is reset
259
+ * to default afterwards.
260
+ *
261
+ * Providing an argument means that previous calculations done with #update
262
+ * would be discarded, so be careful with its use.
263
+ *
264
+ * +seed+ can be in the form of a string, a hex string, or a number.
265
+ */
266
+ static VALUE _Digest_XXHash_digest(int argc, VALUE* argv, VALUE self)
267
+ {
268
+ return _do_digest(argc, argv, self, _id_finish);
269
+ }
270
+
271
+ /*
272
+ * call-seq:
273
+ * hexdigest -> hex_str
274
+ * hexdigest(str) -> hex_str
275
+ * hexdigest(str, seed) -> hex_str
276
+ *
277
+ * Same as #digest but returns the digest value in hex form.
278
+ */
279
+ static VALUE _Digest_XXHash_hexdigest(int argc, VALUE* argv, VALUE self)
280
+ {
281
+ VALUE result = _do_digest(argc, argv, self, _id_finish);
282
+ return _hex_encode_str(result);
283
+ }
284
+
285
+ /*
286
+ * call-seq:
287
+ * idigest -> num
288
+ * idigest(str) -> num
289
+ * idigest(str, seed) -> num
290
+ *
291
+ * Same as #digest but returns the digest value in numerical form.
292
+ */
293
+ static VALUE _Digest_XXHash_idigest(int argc, VALUE* argv, VALUE self)
294
+ {
295
+ return _do_digest(argc, argv, self, _id_ifinish);
296
+ }
297
+
298
+ /*
299
+ * call-seq: idigest!
300
+ *
301
+ * Returns current digest value and resets state to default form.
302
+ */
303
+ static VALUE _Digest_XXHash_idigest_bang(VALUE self)
304
+ {
305
+ VALUE result = rb_funcall(self, _id_ifinish, 0);
306
+ rb_funcall(self, _id_reset, 0);
307
+ return result;
308
+ }
309
+
310
+ /*
311
+ * call-seq: initialize_copy(orig) -> self
312
+ *
313
+ * This method is called when instances are cloned. It is responsible for
314
+ * replicating internal data.
315
+ */
316
+ static VALUE _Digest_XXHash_initialize_copy(VALUE orig)
317
+ {
318
+ rb_raise(rb_eNotImpError, "initialize_copy method not implemented.");
319
+ }
320
+
321
+ /*
322
+ * call-seq: inspect -> str
323
+ *
324
+ * Returns a string in the form of <tt>#<class_name|hex_digest></tt>.
325
+ */
326
+ static VALUE _Digest_XXHash_inspect(VALUE self)
327
+ {
328
+ VALUE klass = rb_obj_class(self);
329
+ VALUE klass_name = rb_class_name(klass);
330
+
331
+ if (klass_name == Qnil)
332
+ klass_name = rb_inspect(klass);
333
+
334
+ VALUE hexdigest = rb_funcall(self, _id_hexdigest, 0);
335
+
336
+ VALUE args[] = { klass_name, hexdigest };
337
+ return rb_str_format(sizeof(args), args, rb_str_new_literal("#<%s|%s>"));
338
+ }
339
+
340
+ static VALUE _instantiate_and_digest(int argc, VALUE* argv, VALUE klass, ID digest_method_id)
341
+ {
342
+ VALUE str, seed;
343
+ int argc2 = rb_scan_args(argc, argv, "11", &str, &seed);
344
+
345
+ if (TYPE(str) != T_STRING)
346
+ rb_raise(rb_eTypeError, "Argument type not string.");
347
+
348
+ VALUE instance = rb_funcall(klass, _id_new, 0);
349
+
350
+ if (argc2 > 1)
351
+ return rb_funcall(instance, digest_method_id, 2, str, seed);
352
+ else
353
+ return rb_funcall(instance, digest_method_id, 1, str);
354
+ }
355
+
356
+ /*
357
+ * call-seq: Digest::XXHash::digest(str, seed = 0) -> str
358
+ *
359
+ * Returns the digest value of +str+ in string form with +seed+ as its seed.
360
+ *
361
+ * +seed+ can be in the form of a string, a hex string, or a number.
362
+ *
363
+ * If +seed+ is not provided, the default value would be 0.
364
+ */
365
+ static VALUE _Digest_XXHash_singleton_digest(int argc, VALUE* argv, VALUE self)
366
+ {
367
+ return _instantiate_and_digest(argc, argv, self, _id_digest);
368
+ }
369
+
370
+ /*
371
+ * call-seq: Digest::XXHash::hexdigest -> hex_str
372
+ *
373
+ * Same as ::digest but returns the digest value in hex form.
374
+ */
375
+ static VALUE _Digest_XXHash_singleton_hexdigest(int argc, VALUE* argv, VALUE self)
376
+ {
377
+ return _instantiate_and_digest(argc, argv, self, _id_hexdigest);
378
+ }
379
+
380
+ /*
381
+ * call-seq: Digest::XXHash::idigest -> num
382
+ *
383
+ * Same as ::digest but returns the digest value in numerical form.
384
+ */
385
+ static VALUE _Digest_XXHash_singleton_idigest(int argc, VALUE* argv, VALUE self)
386
+ {
387
+ return _instantiate_and_digest(argc, argv, self, _id_idigest);
388
+ }
389
+
390
+ /*
391
+ * Document-class: Digest::XXH32
392
+ *
393
+ * This class implements XXH32.
394
+ */
395
+
396
+ static VALUE _Digest_XXH32_internal_allocate(VALUE klass)
397
+ {
398
+ XXH32_state_t *state_p;
399
+ VALUE obj = TypedData_Make_Struct(klass, XXH32_state_t, &_xxh32_state_data_type, state_p);
400
+ _xxh32_reset(state_p, 0);
401
+ return obj;
402
+ }
403
+
404
+ /*
405
+ * call-seq: update(str) -> self
406
+ *
407
+ * Updates current digest value with string.
408
+ */
409
+ static VALUE _Digest_XXH32_update(VALUE self, VALUE str)
410
+ {
411
+ if (XXH32_update(_get_state_32(self), RSTRING_PTR(str), RSTRING_LEN(str)) != XXH_OK)
412
+ rb_raise(rb_eRuntimeError, "Failed to reset state.");
413
+
414
+ return self;
415
+ }
416
+
417
+ /* :nodoc: */
418
+ static VALUE _Digest_XXH32_finish(VALUE self)
419
+ {
420
+ uint32_t result = XXH32_digest(_get_state_32(self));
421
+ return _encode_big_endian_32(result);
422
+ }
423
+
424
+ /* :nodoc: */
425
+ static VALUE _Digest_XXH32_ifinish(VALUE self)
426
+ {
427
+ uint32_t result = XXH32_digest(_get_state_32(self));
428
+ return ULONG2NUM(result);
429
+ }
430
+
431
+ /*
432
+ * call-seq: reset(seed = 0) -> self
433
+ *
434
+ * Resets state to initial form with seed.
435
+ *
436
+ * This would discard previous calculations with #update.
437
+ *
438
+ * +seed+ can be in the form of a string, a hex string, or a number.
439
+ *
440
+ * If +seed+ is not provided, the default value would be 0.
441
+ */
442
+ static VALUE _Digest_XXH32_reset(int argc, VALUE* argv, VALUE self)
443
+ {
444
+ VALUE seed;
445
+
446
+ if (argc > 0 && rb_scan_args(argc, argv, "01", &seed) > 0) {
447
+ switch (TYPE(seed)) {
448
+ case T_STRING:
449
+ {
450
+ int len = RSTRING_LEN(seed);
451
+ uint32_t decoded_seed;
452
+
453
+ if (len == (sizeof(uint32_t) * 2)) {
454
+ unsigned char hex_decoded_seed[sizeof(uint32_t)];
455
+
456
+ if (! hex_decode_str_implied(RSTRING_PTR(seed), sizeof(uint32_t) * 2, hex_decoded_seed))
457
+ rb_raise(rb_eArgError, "Invalid hex string seed: %s\n", StringValueCStr(seed));
458
+
459
+ decoded_seed = _decode_big_endian_32_cstr(hex_decoded_seed);
460
+ } else if (len == sizeof(uint32_t)) {
461
+ decoded_seed = _decode_big_endian_32_cstr(RSTRING_PTR(seed));
462
+ } else {
463
+ rb_raise(rb_eArgError, "Invalid seed length. Expecting an 8-character hex string or a 4-byte string.");
464
+ }
465
+
466
+ _xxh32_reset(_get_state_32(self), decoded_seed);
467
+ }
468
+
469
+ break;
470
+ case T_FIXNUM:
471
+ _xxh32_reset(_get_state_32(self), FIX2UINT(seed));
472
+ break;
473
+ case T_BIGNUM:
474
+ _xxh32_reset(_get_state_32(self), NUM2UINT(seed));
475
+ break;
476
+ default:
477
+ rb_raise(rb_eArgError, "Invalid argument type for seed. Expecting a string or number.");
478
+ }
479
+ } else {
480
+ _xxh32_reset(_get_state_32(self), _XXH32_DEFAULT_SEED);
481
+ }
482
+
483
+ return self;
484
+ }
485
+
486
+ /*
487
+ * call-seq: initialize_copy(orig) -> self
488
+ *
489
+ * This method is called when instances are cloned. It is responsible for
490
+ * replicating internal data.
491
+ */
492
+ static VALUE _Digest_XXH32_initialize_copy(VALUE self, VALUE orig)
493
+ {
494
+ XXH32_copyState(_get_state_32(self), _get_state_32(orig));
495
+ return self;
496
+ }
497
+
498
+ /*
499
+ * call-seq: digest_length -> int
500
+ *
501
+ * Returns 4.
502
+ */
503
+ static VALUE _Digest_XXH32_digest_length(VALUE self)
504
+ {
505
+ return INT2FIX(_XXH32_DIGEST_SIZE);
506
+ }
507
+
508
+ /*
509
+ * call-seq: block_length -> int
510
+ *
511
+ * Returns 4.
512
+ */
513
+ static VALUE _Digest_XXH32_block_length(VALUE self)
514
+ {
515
+ return INT2FIX(_XXH32_BLOCK_SIZE);
516
+ }
517
+
518
+ /*
519
+ * call-seq: digest_length -> int
520
+ *
521
+ * Returns 4.
522
+ */
523
+ static VALUE _Digest_XXH32_singleton_digest_length(VALUE self)
524
+ {
525
+ return INT2FIX(_XXH32_DIGEST_SIZE);
526
+ }
527
+
528
+ /*
529
+ * call-seq: block_length -> int
530
+ *
531
+ * Returns 4.
532
+ */
533
+ static VALUE _Digest_XXH32_singleton_block_length(VALUE self)
534
+ {
535
+ return INT2FIX(_XXH32_BLOCK_SIZE);
536
+ }
537
+
538
+ /*
539
+ * Document-class: Digest::XXH64
540
+ *
541
+ * This class implements XXH64.
542
+ */
543
+
544
+ static VALUE _Digest_XXH64_internal_allocate(VALUE klass)
545
+ {
546
+ XXH64_state_t *state_p;
547
+ VALUE obj = TypedData_Make_Struct(klass, XXH64_state_t, &_xxh64_state_data_type, state_p);
548
+ _xxh64_reset(state_p, 0);
549
+ return obj;
550
+ }
551
+
552
+ /*
553
+ * call-seq: update(str) -> self
554
+ *
555
+ * Updates current digest value with string.
556
+ */
557
+ static VALUE _Digest_XXH64_update(VALUE self, VALUE str)
558
+ {
559
+ if (XXH64_update(_get_state_64(self), RSTRING_PTR(str), RSTRING_LEN(str)) != XXH_OK)
560
+ rb_raise(rb_eRuntimeError, "Failed to reset state.");
561
+
562
+ return self;
563
+ }
564
+
565
+ /* :nodoc: */
566
+ static VALUE _Digest_XXH64_finish(VALUE self)
567
+ {
568
+ uint64_t result = XXH64_digest(_get_state_64(self));
569
+ return _encode_big_endian_64(result);
570
+ }
571
+
572
+ /* :nodoc: */
573
+ static VALUE _Digest_XXH64_ifinish(VALUE self)
574
+ {
575
+ uint64_t result = XXH64_digest(_get_state_64(self));
576
+ return ULL2NUM(result);
577
+ }
578
+
579
+ /*
580
+ * call-seq: reset(seed = 0) -> self
581
+ *
582
+ * Resets state to initial form with seed.
583
+ *
584
+ * This would discard previous calculations with #update.
585
+ *
586
+ * +seed+ can be in the form of a string, a hex string, or a number.
587
+ *
588
+ * If +seed+ is not provided, the default value would be 0.
589
+ */
590
+ static VALUE _Digest_XXH64_reset(int argc, VALUE* argv, VALUE self)
591
+ {
592
+ VALUE seed;
593
+
594
+ if (rb_scan_args(argc, argv, "01", &seed) > 0) {
595
+ switch (TYPE(seed)) {
596
+ case T_STRING:
597
+ {
598
+ int len = RSTRING_LEN(seed);
599
+ uint64_t decoded_seed;
600
+
601
+ if (len == (sizeof(uint64_t) * 2)) {
602
+ unsigned char hex_decoded_seed[sizeof(uint64_t)];
603
+
604
+ if (! hex_decode_str_implied(RSTRING_PTR(seed), sizeof(uint64_t) * 2, hex_decoded_seed))
605
+ rb_raise(rb_eArgError, "Invalid hex string seed: %s\n", StringValueCStr(seed));
606
+
607
+ decoded_seed = _decode_big_endian_64_cstr(hex_decoded_seed);
608
+ } else if (len == sizeof(uint64_t)) {
609
+ decoded_seed = _decode_big_endian_64_cstr(RSTRING_PTR(seed));
610
+ } else {
611
+ rb_raise(rb_eArgError, "Invalid seed length. Expecting a 16-character hex string or an 8-byte string.");
612
+ }
613
+
614
+ _xxh64_reset(_get_state_64(self), decoded_seed);
615
+ }
616
+
617
+ break;
618
+ case T_FIXNUM:
619
+ _xxh64_reset(_get_state_64(self), FIX2UINT(seed));
620
+ break;
621
+ case T_BIGNUM:
622
+ _xxh64_reset(_get_state_64(self), NUM2ULL(seed));
623
+ break;
624
+ default:
625
+ rb_raise(rb_eArgError, "Invalid argument type for seed. Expecting a string or number.");
626
+ }
627
+ } else {
628
+ _xxh64_reset(_get_state_64(self), _XXH64_DEFAULT_SEED);
629
+ }
630
+
631
+ return self;
632
+ }
633
+
634
+ /*
635
+ * call-seq: initialize_copy(orig) -> self
636
+ *
637
+ * This method is called when instances are cloned. It is responsible for
638
+ * replicating internal data.
639
+ */
640
+ static VALUE _Digest_XXH64_initialize_copy(VALUE self, VALUE orig)
641
+ {
642
+ XXH64_copyState(_get_state_64(self), _get_state_64(orig));
643
+ return self;
644
+ }
645
+
646
+ /*
647
+ * call-seq: digest_length -> int
648
+ *
649
+ * Returns 8.
650
+ */
651
+ static VALUE _Digest_XXH64_digest_length(VALUE self)
652
+ {
653
+ return INT2FIX(_XXH64_DIGEST_SIZE);
654
+ }
655
+
656
+ /*
657
+ * call-seq: block_length -> int
658
+ *
659
+ * Returns 8.
660
+ */
661
+ static VALUE _Digest_XXH64_block_length(VALUE self)
662
+ {
663
+ return INT2FIX(_XXH64_BLOCK_SIZE);
664
+ }
665
+
666
+ /*
667
+ * call-seq: digest_length -> int
668
+ *
669
+ * Returns 8.
670
+ */
671
+ static VALUE _Digest_XXH64_singleton_digest_length(VALUE self)
672
+ {
673
+ return INT2FIX(_XXH64_DIGEST_SIZE);
674
+ }
675
+
676
+ /*
677
+ * call-seq: block_length -> int
678
+ *
679
+ * Returns 8.
680
+ */
681
+ static VALUE _Digest_XXH64_singleton_block_length(VALUE self)
682
+ {
683
+ return INT2FIX(_XXH64_BLOCK_SIZE);
684
+ }
685
+
686
+ /*
687
+ * Initialization
688
+ */
689
+
690
+ void Init_xxhash()
691
+ {
692
+ #define DEFINE_ID(x) _id_##x = rb_intern_const(#x);
693
+
694
+ DEFINE_ID(digest)
695
+ DEFINE_ID(finish)
696
+ DEFINE_ID(hexdigest)
697
+ DEFINE_ID(idigest)
698
+ DEFINE_ID(ifinish)
699
+ DEFINE_ID(new)
700
+ DEFINE_ID(reset)
701
+ DEFINE_ID(update)
702
+
703
+ #if 0
704
+ _Digest = rb_define_module("Digest"); /* Tell RDoc about Digest since it doesn't recognize rb_path2class. */
705
+ #endif
706
+
707
+ rb_require("digest");
708
+ _Digest = rb_path2class("Digest");
709
+
710
+ /*
711
+ * Document-class: Digest::XXHash
712
+ */
713
+
714
+ _Digest_XXHash = rb_define_class_under(_Digest, "XXHash", rb_path2class("Digest::Class"));
715
+
716
+ rb_define_method(_Digest_XXHash, "digest", _Digest_XXHash_digest, -1);
717
+ rb_define_method(_Digest_XXHash, "hexdigest", _Digest_XXHash_hexdigest, -1);
718
+ rb_define_method(_Digest_XXHash, "idigest", _Digest_XXHash_idigest, -1);
719
+ rb_define_method(_Digest_XXHash, "idigest!", _Digest_XXHash_idigest_bang, 0);
720
+ rb_define_method(_Digest_XXHash, "initialize", _Digest_XXHash_initialize, -1);
721
+ rb_define_method(_Digest_XXHash, "inspect", _Digest_XXHash_inspect, 0);
722
+ rb_define_method(_Digest_XXHash, "initialize_copy", _Digest_XXHash_initialize_copy, 1);
723
+
724
+ rb_define_protected_method(_Digest_XXHash, "ifinish", _Digest_XXHash_ifinish, 0);
725
+
726
+ rb_define_singleton_method(_Digest_XXHash, "digest", _Digest_XXHash_singleton_digest, -1);
727
+ rb_define_singleton_method(_Digest_XXHash, "hexdigest", _Digest_XXHash_singleton_hexdigest, -1);
728
+ rb_define_singleton_method(_Digest_XXHash, "idigest", _Digest_XXHash_singleton_idigest, -1);
729
+
730
+ rb_define_alloc_func(_Digest_XXHash, _Digest_XXHash_internal_allocate);
731
+
732
+ /*
733
+ * Document-class: Digest::XXH32
734
+ */
735
+
736
+ _Digest_XXH32 = rb_define_class_under(_Digest, "XXH32", _Digest_XXHash);
737
+
738
+ rb_define_alloc_func(_Digest_XXH32, _Digest_XXH32_internal_allocate);
739
+
740
+ rb_define_private_method(_Digest_XXH32, "finish", _Digest_XXH32_finish, 0);
741
+ rb_define_private_method(_Digest_XXH32, "ifinish", _Digest_XXH32_ifinish, 0);
742
+
743
+ rb_define_method(_Digest_XXH32, "update", _Digest_XXH32_update, 1);
744
+ rb_define_method(_Digest_XXH32, "reset", _Digest_XXH32_reset, -1);
745
+ rb_define_method(_Digest_XXH32, "digest_length", _Digest_XXH32_digest_length, 0);
746
+ rb_define_method(_Digest_XXH32, "block_length", _Digest_XXH32_block_length, 0);
747
+ rb_define_method(_Digest_XXH32, "initialize_copy", _Digest_XXH32_initialize_copy, 1);
748
+
749
+ rb_define_singleton_method(_Digest_XXH32, "digest_length", _Digest_XXH32_singleton_digest_length, 0);
750
+ rb_define_singleton_method(_Digest_XXH32, "block_length", _Digest_XXH32_singleton_block_length, 0);
751
+
752
+ /*
753
+ * Document-class: Digest::XXH64
754
+ */
755
+
756
+ _Digest_XXH64 = rb_define_class_under(_Digest, "XXH64", _Digest_XXHash);
757
+
758
+ rb_define_alloc_func(_Digest_XXH64, _Digest_XXH64_internal_allocate);
759
+
760
+ rb_define_private_method(_Digest_XXH64, "finish", _Digest_XXH64_finish, 0);
761
+ rb_define_private_method(_Digest_XXH64, "ifinish", _Digest_XXH64_ifinish, 0);
762
+
763
+ rb_define_method(_Digest_XXH64, "update", _Digest_XXH64_update, 1);
764
+ rb_define_method(_Digest_XXH64, "reset", _Digest_XXH64_reset, -1);
765
+ rb_define_method(_Digest_XXH64, "digest_length", _Digest_XXH64_digest_length, 0);
766
+ rb_define_method(_Digest_XXH64, "block_length", _Digest_XXH64_block_length, 0);
767
+ rb_define_method(_Digest_XXH64, "initialize_copy", _Digest_XXH64_initialize_copy, 1);
768
+
769
+ rb_define_singleton_method(_Digest_XXH64, "digest_length", _Digest_XXH64_singleton_digest_length, 0);
770
+ rb_define_singleton_method(_Digest_XXH64, "block_length", _Digest_XXH64_singleton_block_length, 0);
771
+ }