|
1 |
| -#include <bignum.c> |
| 1 | +#include <ruby.h> |
2 | 2 |
|
| 3 | +// extract bignum to array of unsigned ints |
| 4 | +static unsigned int * idhash_bignum_to_buf(VALUE a, size_t *num) { |
| 5 | + size_t word_numbits = sizeof(unsigned int) * CHAR_BIT; |
| 6 | + size_t nlz_bits = 0; |
| 7 | + *num = rb_absint_numwords(a, word_numbits, &nlz_bits); |
| 8 | + |
| 9 | + if (*num == (size_t)-1) { |
| 10 | + rb_raise(rb_eRuntimeError, "Number too large to represent and overflow occured"); |
| 11 | + } |
| 12 | + |
| 13 | + unsigned int *buf = ALLOC_N(unsigned int, *num); |
| 14 | + |
| 15 | + rb_integer_pack(a, buf, *num, sizeof(unsigned int), 0, |
| 16 | + INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER| |
| 17 | + INTEGER_PACK_2COMP); |
| 18 | + |
| 19 | + return buf; |
| 20 | +} |
| 21 | + |
| 22 | +// does ((a ^ b) & (a | b) >> 128) |
3 | 23 | static VALUE idhash_distance(VALUE self, VALUE a, VALUE b){
|
4 |
| - BDIGIT* tempd; |
5 |
| - long i, an = BIGNUM_LEN(a), bn = BIGNUM_LEN(b), templ, acc = 0; |
6 |
| - BDIGIT* as = BDIGITS(a); |
7 |
| - BDIGIT* bs = BDIGITS(b); |
8 |
| - while (0 < an && as[an-1] == 0) an--; // for (i = an; --i;) printf("%u\n", as[i]); |
9 |
| - while (0 < bn && bs[bn-1] == 0) bn--; // for (i = bn; --i;) printf("%u\n", bs[i]); |
10 |
| - // printf("%lu %lu\n", an, bn); |
| 24 | + size_t an, bn; |
| 25 | + unsigned int *as = idhash_bignum_to_buf(a, &an); |
| 26 | + unsigned int *bs = idhash_bignum_to_buf(b, &bn); |
| 27 | + |
| 28 | + while (an > 0 && as[an-1] == 0) an--; |
| 29 | + while (bn > 0 && bs[bn-1] == 0) bn--; |
| 30 | + |
11 | 31 | if (an < bn) {
|
| 32 | + unsigned int *tempd; size_t templ; |
12 | 33 | tempd = as; as = bs; bs = tempd;
|
13 | 34 | templ = an; an = bn; bn = templ;
|
14 | 35 | }
|
15 |
| - for (i = an; i-- > 4;) { |
16 |
| - // printf("%ld : (%u | %u) & (%u ^ %u)\n", i, as[i], (i >= bn ? 0 : bs[i]), as[i-4], bs[i-4]); |
17 |
| - acc += __builtin_popcountl((as[i] | (i >= bn ? 0 : bs[i])) & (as[i-4] ^ bs[i-4])); |
18 |
| - // printf("%ld : %ld\n", i, acc); |
| 36 | + |
| 37 | + size_t i; |
| 38 | + long acc = 0; |
| 39 | + // to count >> 128 |
| 40 | + size_t cycles = 128 / (sizeof(unsigned int) * CHAR_BIT); |
| 41 | + |
| 42 | + for (i = an; i-- > cycles;) { |
| 43 | + acc += __builtin_popcountl((as[i] | (i >= bn ? 0 : bs[i])) & (as[i-cycles] ^ (i-cycles >= bn ? 0 : bs[i-cycles]))); |
19 | 44 | }
|
| 45 | + |
20 | 46 | RB_GC_GUARD(a);
|
21 | 47 | RB_GC_GUARD(b);
|
| 48 | + xfree(as); |
| 49 | + xfree(bs); |
| 50 | + |
22 | 51 | return INT2FIX(acc);
|
23 | 52 | }
|
24 | 53 |
|
25 | 54 | void Init_idhash() {
|
26 |
| - VALUE m = rb_define_module("DHashVips"); |
27 |
| - VALUE mm = rb_define_module_under(m, "IDHash"); |
28 |
| - rb_define_module_function(mm, "distance3_c", idhash_distance, 2); |
| 55 | + VALUE m = rb_define_module("DHashVips"); |
| 56 | + VALUE mm = rb_define_module_under(m, "IDHash"); |
| 57 | + rb_define_module_function(mm, "distance3_c", idhash_distance, 2); |
29 | 58 | }
|
0 commit comments