digest-xxhash 0.0.2

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.
@@ -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
+ }