bitset 1.0.1 → 1.1.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 +4 -4
- data/README.markdown +22 -13
- data/VERSION +1 -1
- data/bitset.gemspec +4 -4
- data/ext/bitset/bitset.c +57 -8
- data/spec/bitset_spec.rb +7 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c14192c25ee30542e0317d9866aae505540db2d
|
4
|
+
data.tar.gz: 3ca3e7cdd173f8f45785f80925afc31960236200
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c811e6e8fc572c7efd0338e4b249189542be2c8e533cc672166cd22e2113b4d1ed10c28a5ea1587492c38d26787700dd45fa3d705badf6273014ecde1fa64b8
|
7
|
+
data.tar.gz: 5f602be6047488f9f1ba99f168b98050f3479fba816032bdeb7a4873786f9e8de9fd6b076c0ad29d3ac39c5818a7977a72209c19f2acdad637a735e5c7f966a7
|
data/README.markdown
CHANGED
@@ -39,16 +39,16 @@ Obviously you can also set and clear bits...
|
|
39
39
|
|
40
40
|
>> bitset = Bitset.new(8)
|
41
41
|
=> 00000000
|
42
|
-
|
42
|
+
|
43
43
|
>> bitset[3] = true
|
44
44
|
=> 00010000
|
45
|
-
|
45
|
+
|
46
46
|
>> bitset[3] = false
|
47
47
|
=> 00000000
|
48
|
-
|
48
|
+
|
49
49
|
>> bitset.set(1, 3, 5, 7)
|
50
50
|
=> 01010101
|
51
|
-
|
51
|
+
|
52
52
|
>> bitset.clear(1, 5)
|
53
53
|
=> 00010001
|
54
54
|
|
@@ -59,31 +59,31 @@ support basic set and bitwise operations. So, let's look at a few of those.
|
|
59
59
|
|
60
60
|
>> a = Bitset.from_s('00001111')
|
61
61
|
=> 00001111
|
62
|
-
|
62
|
+
|
63
63
|
>> b = Bitset.from_s('01010101')
|
64
64
|
=> 01010101
|
65
|
-
|
65
|
+
|
66
66
|
>> a & b
|
67
67
|
=> 00000101
|
68
|
-
|
68
|
+
|
69
69
|
>> a | b
|
70
70
|
=> 01011111
|
71
|
-
|
71
|
+
|
72
72
|
>> b - a
|
73
73
|
=> 01010000
|
74
|
-
|
74
|
+
|
75
75
|
>> a ^ b
|
76
76
|
=> 01011010
|
77
|
-
|
77
|
+
|
78
78
|
>> ~a
|
79
79
|
=> 11110000
|
80
|
-
|
80
|
+
|
81
81
|
>> a.hamming(b)
|
82
82
|
=> 4
|
83
|
-
|
83
|
+
|
84
84
|
>> a.cardinality
|
85
85
|
=> 4
|
86
|
-
|
86
|
+
|
87
87
|
>> a.reverse
|
88
88
|
=> 11110000
|
89
89
|
|
@@ -123,6 +123,15 @@ support basic set and bitwise operations. So, let's look at a few of those.
|
|
123
123
|
>> b.each_set # AKA b.to_a
|
124
124
|
=> [1, 3, 5, 7]
|
125
125
|
|
126
|
+
# b.each_set(index) == b.each_set[index], but faster.
|
127
|
+
>> b.each_set(-3) # Negative index wraps around.
|
128
|
+
=> 3
|
129
|
+
|
130
|
+
# b.each_set(index, len) == b.each_set[index, len], but faster.
|
131
|
+
>> b.each_set(2,2) # Block is also allowed
|
132
|
+
=> [5,7]
|
133
|
+
|
134
|
+
|
126
135
|
# The following methods modify a Bitset in place very quickly:
|
127
136
|
>> a.intersect!(b) # like a &= b
|
128
137
|
>> a.union!(b) # like a |= b
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/bitset.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: bitset 1.0
|
5
|
+
# stub: bitset 1.1.0 ruby lib
|
6
6
|
# stub: ext/bitset/extconf.rb
|
7
7
|
|
8
8
|
Gem::Specification.new do |s|
|
9
9
|
s.name = "bitset".freeze
|
10
|
-
s.version = "1.0
|
10
|
+
s.version = "1.1.0"
|
11
11
|
|
12
12
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
13
13
|
s.require_paths = ["lib".freeze]
|
14
14
|
s.authors = ["Tyler McMullen".freeze]
|
15
|
-
s.date = "
|
15
|
+
s.date = "2018-01-06"
|
16
16
|
s.description = "A fast C-based Bitset. It supports the standard set operations as well as operations you may expect on bit arrays,such as popcount.".freeze
|
17
17
|
s.email = "eric.boesch@nist.gov".freeze
|
18
18
|
s.extensions = ["ext/bitset/extconf.rb".freeze]
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
]
|
36
36
|
s.homepage = "http://github.com/ericboesch/bitset".freeze
|
37
37
|
s.licenses = ["MIT".freeze]
|
38
|
-
s.rubygems_version = "2.6.
|
38
|
+
s.rubygems_version = "2.6.14".freeze
|
39
39
|
s.summary = "Bitset implementation.".freeze
|
40
40
|
end
|
41
41
|
|
data/ext/bitset/bitset.c
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
#include "builtin.h"
|
3
3
|
|
4
4
|
#include <stdint.h>
|
5
|
+
#include <stdbool.h>
|
5
6
|
#include <string.h>
|
6
7
|
#include <stdio.h>
|
8
|
+
#include <limits.h>
|
7
9
|
|
8
10
|
VALUE cBitset;
|
9
11
|
|
@@ -173,15 +175,19 @@ static VALUE rb_bitset_set_p(int argc, VALUE * argv, VALUE self) {
|
|
173
175
|
return Qtrue;
|
174
176
|
}
|
175
177
|
|
176
|
-
static
|
177
|
-
Bitset * bs = get_bitset(self);
|
178
|
+
static int cardinality(Bitset * bs) {
|
178
179
|
int i;
|
179
180
|
int max = INTS(bs);
|
180
181
|
int count = 0;
|
181
182
|
for(i = 0; i < max; i++) {
|
182
183
|
count += psnip_builtin_popcount64(bs->data[i]);
|
183
184
|
}
|
184
|
-
return
|
185
|
+
return count;
|
186
|
+
}
|
187
|
+
|
188
|
+
static VALUE rb_bitset_cardinality(VALUE self) {
|
189
|
+
Bitset * bs = get_bitset(self);
|
190
|
+
return INT2NUM(cardinality(bs));
|
185
191
|
}
|
186
192
|
|
187
193
|
static VALUE rb_bitset_intersect(VALUE self, VALUE other) {
|
@@ -388,21 +394,51 @@ static VALUE rb_bitset_dup(VALUE self) {
|
|
388
394
|
|
389
395
|
/* Yield the bit numbers of each set bit in sequence to a block. If
|
390
396
|
there is no block, return an array of those numbers. */
|
391
|
-
static VALUE rb_bitset_each_set(VALUE self) {
|
397
|
+
static VALUE rb_bitset_each_set(int argc, VALUE * argv, VALUE self) {
|
392
398
|
Bitset * bs = get_bitset(self);
|
393
399
|
int seg_no;
|
394
400
|
int max = INTS(bs);
|
395
401
|
uint64_t* seg_ptr = bs->data;
|
396
402
|
int block_p = rb_block_given_p();
|
397
403
|
VALUE ary = Qnil;
|
404
|
+
int set_bit_no = -1;
|
405
|
+
|
406
|
+
/* If there is one argument, it is an index into the notional
|
407
|
+
output array, and return an int. If there are two arguments,
|
408
|
+
return up to <n> arguments where is the second argument. */
|
409
|
+
int min_set_bit_no = (argc > 0) ? NUM2INT(argv[0]) : 0;
|
410
|
+
int max_set_bit_no;
|
411
|
+
|
412
|
+
if (argc > 2) {
|
413
|
+
VALUE error = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
414
|
+
rb_raise(error, "wrong number of arguments (given %d, expected 0..2)",
|
415
|
+
argc);
|
416
|
+
}
|
417
|
+
|
418
|
+
if (min_set_bit_no < 0) {
|
419
|
+
/* Convert negative numbers into offsets from the end of the array. */
|
420
|
+
min_set_bit_no = cardinality(bs) + min_set_bit_no;
|
421
|
+
}
|
398
422
|
|
399
|
-
|
423
|
+
max_set_bit_no = (argc == 0)
|
424
|
+
? INT_MAX
|
425
|
+
: (argc == 1)
|
426
|
+
? (min_set_bit_no + 1)
|
427
|
+
: (min_set_bit_no + NUM2INT(argv[1]));
|
428
|
+
|
429
|
+
if (min_set_bit_no < 0 || max_set_bit_no < min_set_bit_no)
|
430
|
+
return Qnil;
|
431
|
+
|
432
|
+
if (argc != 1 && !block_p) {
|
400
433
|
ary = rb_ary_new();
|
401
434
|
}
|
435
|
+
if (min_set_bit_no < 0 || max_set_bit_no < min_set_bit_no)
|
436
|
+
return Qnil;
|
402
437
|
|
403
438
|
for (seg_no = 0; seg_no < max; ++seg_no, ++seg_ptr) {
|
404
439
|
uint64_t segment = *seg_ptr;
|
405
440
|
int bit_position = 0;
|
441
|
+
bool finished = false;
|
406
442
|
while (segment) {
|
407
443
|
VALUE v;
|
408
444
|
|
@@ -412,13 +448,26 @@ static VALUE rb_bitset_each_set(VALUE self) {
|
|
412
448
|
segment >>= shift;
|
413
449
|
}
|
414
450
|
v = INT2NUM(_seg_no_to_bit_no(seg_no) + bit_position);
|
451
|
+
++bit_position;
|
452
|
+
segment >>= 1;
|
453
|
+
++set_bit_no;
|
454
|
+
if (set_bit_no < min_set_bit_no) {
|
455
|
+
continue;
|
456
|
+
}
|
457
|
+
if (set_bit_no >= max_set_bit_no) {
|
458
|
+
finished = true;
|
459
|
+
break;
|
460
|
+
}
|
415
461
|
if (block_p) {
|
416
462
|
rb_yield(v);
|
463
|
+
} else if (argc == 1) {
|
464
|
+
return v;
|
417
465
|
} else {
|
418
466
|
rb_ary_push(ary, v);
|
419
467
|
}
|
420
|
-
|
421
|
-
|
468
|
+
}
|
469
|
+
if (finished) {
|
470
|
+
break;
|
422
471
|
}
|
423
472
|
}
|
424
473
|
|
@@ -576,7 +625,7 @@ void Init_bitset() {
|
|
576
625
|
rb_define_method(cBitset, "to_binary_array", rb_bitset_to_binary_array, 0);
|
577
626
|
rb_define_method(cBitset, "dup", rb_bitset_dup, 0);
|
578
627
|
rb_define_alias(cBitset, "clone", "dup");
|
579
|
-
rb_define_method(cBitset, "each_set", rb_bitset_each_set,
|
628
|
+
rb_define_method(cBitset, "each_set", rb_bitset_each_set, -1);
|
580
629
|
rb_define_alias(cBitset, "to_a", "each_set");
|
581
630
|
/* #each_set allows an optional block, and #to_a normally doesn't.
|
582
631
|
But an alias is simpler than having two different functions. */
|
data/spec/bitset_spec.rb
CHANGED
@@ -271,6 +271,13 @@ describe Bitset do
|
|
271
271
|
bs.set(*sets)
|
272
272
|
expect(bs.each_set).to eq(sets)
|
273
273
|
end
|
274
|
+
|
275
|
+
it 'behaves properly with arguments' do
|
276
|
+
bs = Bitset.from_s "110110011"
|
277
|
+
expect { bs.each_set 1, 2, 3 }.to raise_error(ArgumentError)
|
278
|
+
expect(bs.each_set 2).to eq(3)
|
279
|
+
expect(bs.each_set -3, 2).to eq([4,7])
|
280
|
+
end
|
274
281
|
end
|
275
282
|
|
276
283
|
describe :empty? do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitset
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler McMullen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A fast C-based Bitset. It supports the standard set operations as well
|
14
14
|
as operations you may expect on bit arrays,such as popcount.
|
@@ -51,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
51
|
version: '0'
|
52
52
|
requirements: []
|
53
53
|
rubyforge_project:
|
54
|
-
rubygems_version: 2.6.
|
54
|
+
rubygems_version: 2.6.14
|
55
55
|
signing_key:
|
56
56
|
specification_version: 4
|
57
57
|
summary: Bitset implementation.
|