bitset 0.1.0 → 1.0.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 +7 -0
- data/README.markdown +158 -0
- data/Rakefile +4 -4
- data/VERSION +1 -1
- data/bitset.gemspec +6 -5
- data/ext/bitset/bitset.c +222 -41
- data/lib/bitset/bitset.rb +23 -0
- data/spec/bitset_spec.rb +164 -47
- metadata +29 -45
- data/README.rdoc +0 -3
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 67a16f9ffaa21475905ca59bde6734954735e3c7
|
4
|
+
data.tar.gz: c734af4e2b220c01b760f1e93fd05940ca79569d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6603741fd0c7f3a5e348e3db792695fdfc5926062567d401e49b2c66f8ae7e44dc8e1eed66fc8d69859305dc265a3abe2377dad5486ee234da872fa427a9119b
|
7
|
+
data.tar.gz: 50f4c82523b31f15d176d7dc26a47be1610135bd4b826f2633abe960394c3fea407d67b7b624dc27148004374f1035968880fb007753c7efd2e440166d429431
|
data/README.markdown
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
Bitset
|
2
|
+
======
|
3
|
+
|
4
|
+
A fast Bitset implementation for Ruby. Available as the 'bitset' gem.
|
5
|
+
|
6
|
+
|
7
|
+
Installation
|
8
|
+
------------
|
9
|
+
|
10
|
+
Usually you want to do this:
|
11
|
+
|
12
|
+
gem install bitset
|
13
|
+
|
14
|
+
But if you want the latest patches or want to work on it yourself, you may want
|
15
|
+
to do this:
|
16
|
+
|
17
|
+
git clone git://github.com/ericboesch/bitset.git
|
18
|
+
cd bitset
|
19
|
+
rake build
|
20
|
+
gem install pkg/bitset-<version>.gem
|
21
|
+
|
22
|
+
|
23
|
+
Usage
|
24
|
+
-----
|
25
|
+
|
26
|
+
You create a bitset like this:
|
27
|
+
|
28
|
+
>> Bitset.new(8)
|
29
|
+
=> 00000000
|
30
|
+
|
31
|
+
Here we created an 8-bit bitset. All bits are initialized to 0.
|
32
|
+
|
33
|
+
We can also create a bitset based on a string of ones and zeros.
|
34
|
+
|
35
|
+
>> Bitset.from_s('00010001')
|
36
|
+
=> 00010001
|
37
|
+
|
38
|
+
Obviously you can also set and clear bits...
|
39
|
+
|
40
|
+
>> bitset = Bitset.new(8)
|
41
|
+
=> 00000000
|
42
|
+
|
43
|
+
>> bitset[3] = true
|
44
|
+
=> 00010000
|
45
|
+
|
46
|
+
>> bitset[3] = false
|
47
|
+
=> 00000000
|
48
|
+
|
49
|
+
>> bitset.set(1, 3, 5, 7)
|
50
|
+
=> 01010101
|
51
|
+
|
52
|
+
>> bitset.clear(1, 5)
|
53
|
+
=> 00010001
|
54
|
+
|
55
|
+
The point of a bitset is to be, effectively, an array of single bits. It should
|
56
|
+
support basic set and bitwise operations. So, let's look at a few of those.
|
57
|
+
|
58
|
+
>> a = Bitset.from_s('00001111')
|
59
|
+
=> 00001111
|
60
|
+
|
61
|
+
>> b = Bitset.from_s('01010101')
|
62
|
+
=> 01010101
|
63
|
+
|
64
|
+
>> a & b
|
65
|
+
=> 00000101
|
66
|
+
|
67
|
+
>> a | b
|
68
|
+
=> 01011111
|
69
|
+
|
70
|
+
>> b - a
|
71
|
+
=> 01010000
|
72
|
+
|
73
|
+
>> a ^ b
|
74
|
+
=> 01011010
|
75
|
+
|
76
|
+
>> ~a
|
77
|
+
=> 11110000
|
78
|
+
|
79
|
+
>> a.hamming(b)
|
80
|
+
=> 4
|
81
|
+
|
82
|
+
>> a.cardinality
|
83
|
+
=> 4
|
84
|
+
|
85
|
+
>> a.reverse
|
86
|
+
=> 11110000
|
87
|
+
|
88
|
+
# Tell whether all of the given bit numbers are set
|
89
|
+
>> a.set? 6
|
90
|
+
=> true
|
91
|
+
|
92
|
+
# Return a new Bitset composed of bits #1, #3, #5, #4, and #1 again
|
93
|
+
>> a.select_bits [1,3,5,4,1]
|
94
|
+
=> 00110
|
95
|
+
|
96
|
+
# Tell whether all of the given bit numbers are clear
|
97
|
+
>> a.clear? 1,3,5
|
98
|
+
=> false
|
99
|
+
|
100
|
+
# Tell whether all bits are clear
|
101
|
+
>> a.empty?
|
102
|
+
=> false
|
103
|
+
|
104
|
+
# Pass all bits to the block
|
105
|
+
>> b.each { |v| puts v }
|
106
|
+
=> false
|
107
|
+
true
|
108
|
+
false
|
109
|
+
...
|
110
|
+
|
111
|
+
# Pass the positions of all set bits to the block
|
112
|
+
>> b.each_set { |bit| puts bit }
|
113
|
+
=> 1
|
114
|
+
3
|
115
|
+
5
|
116
|
+
7
|
117
|
+
|
118
|
+
# Return an array of the positions of all set bits
|
119
|
+
>> b.each_set
|
120
|
+
=> [1, 3, 5, 7]
|
121
|
+
|
122
|
+
# The following methods modify a Bitset in place very quickly:
|
123
|
+
>> a.intersect!(b) # like a &= b
|
124
|
+
>> a.union!(b) # like a |= b
|
125
|
+
>> a.difference!(b) # like a -= b
|
126
|
+
>> a.xor!(b) # alias a.symmetric_difference!(b), like a ^= b
|
127
|
+
>> a.reset!
|
128
|
+
|
129
|
+
# Above, "like" does not mean "identical to." a |= b creates a new
|
130
|
+
# Bitset object. a.union!(b) changes an existing object which
|
131
|
+
# affects all variables that point to the same object.
|
132
|
+
|
133
|
+
# Attempting to apply bitwise binary operators or their in-place
|
134
|
+
# equivalents between bitsets of different sizes will raise an
|
135
|
+
# ArgumentError.
|
136
|
+
|
137
|
+
# b.dup and b.clone are also available.
|
138
|
+
|
139
|
+
# Marshal.dump and Marshal.load are also supported. If you want to
|
140
|
+
# save a few bytes and don't need Marshal.load to work, you can
|
141
|
+
# use #pack and Bitset.unpack instead.
|
142
|
+
|
143
|
+
Contributing
|
144
|
+
------------
|
145
|
+
|
146
|
+
The best way to contribute is to fork the project on GitHub, make your changes,
|
147
|
+
and send a pull request. This is always much appreciated. If you want to mess
|
148
|
+
around with the version numbers, gemspec, or anything like that feel free... But
|
149
|
+
do it in separate commits so I can easily ignore them.
|
150
|
+
|
151
|
+
|
152
|
+
License
|
153
|
+
-------
|
154
|
+
|
155
|
+
See LICENSE.txt.
|
156
|
+
|
157
|
+
|
158
|
+
### Thanks for using Bitset!
|
data/Rakefile
CHANGED
@@ -12,17 +12,17 @@ task :default => :spec
|
|
12
12
|
require 'jeweler'
|
13
13
|
Jeweler::Tasks.new do |gem|
|
14
14
|
gem.name = "bitset"
|
15
|
-
gem.homepage = "http://github.com/
|
15
|
+
gem.homepage = "http://github.com/ericboesch/bitset"
|
16
16
|
gem.license = "MIT"
|
17
17
|
gem.summary = 'Bitset implementation.'
|
18
18
|
gem.description = 'A fast C-based Bitset. It supports the standard set operations as well as operations you may expect on bit arrays. (popcount, for instance)'
|
19
|
-
gem.email = "
|
19
|
+
gem.email = "eric.boesch@nist.gov"
|
20
20
|
gem.authors = ["Tyler McMullen"]
|
21
21
|
end
|
22
22
|
Jeweler::RubygemsDotOrgTasks.new
|
23
23
|
|
24
|
-
require '
|
25
|
-
|
24
|
+
require 'rdoc/task'
|
25
|
+
RDoc::Task.new do |rdoc|
|
26
26
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
27
27
|
|
28
28
|
rdoc.rdoc_dir = 'rdoc'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.0.0
|
data/bitset.gemspec
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bitset}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Tyler McMullen"]
|
12
|
-
s.date = %q{
|
11
|
+
s.authors = ["Tyler McMullen", "Eric Boesch"]
|
12
|
+
s.date = %q{2016-02-22}
|
13
13
|
s.description = %q{A fast C-based Bitset. It supports the standard set operations as well as operations you may expect on bit arrays. (popcount, for instance)}
|
14
|
-
s.email = %q{
|
14
|
+
s.email = %q{ericboesch@gmail.com}
|
15
15
|
s.extensions = ["ext/bitset/extconf.rb"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"LICENSE.txt",
|
@@ -25,9 +25,10 @@ Gem::Specification.new do |s|
|
|
25
25
|
"bitset.gemspec",
|
26
26
|
"ext/bitset/bitset.c",
|
27
27
|
"ext/bitset/extconf.rb",
|
28
|
+
"lib/bitset/bitset.rb",
|
28
29
|
"spec/bitset_spec.rb"
|
29
30
|
]
|
30
|
-
s.homepage = %q{http://github.com/
|
31
|
+
s.homepage = %q{http://github.com/ericboesch/bitset}
|
31
32
|
s.licenses = ["MIT"]
|
32
33
|
s.require_paths = ["lib"]
|
33
34
|
s.rubygems_version = %q{1.3.7}
|
data/ext/bitset/bitset.c
CHANGED
@@ -11,16 +11,18 @@ typedef struct {
|
|
11
11
|
uint64_t * data;
|
12
12
|
} Bitset;
|
13
13
|
|
14
|
-
|
15
|
-
#define
|
14
|
+
// Avoid using (len-1), just in case len == 0.
|
15
|
+
#define BYTES(_bs) (((_bs)->len+7) >> 3)
|
16
|
+
#define INTS(_bs) (((_bs)->len+63) >> 6)
|
17
|
+
// 2^6=64
|
16
18
|
|
17
19
|
Bitset * bitset_new() {
|
18
|
-
return (Bitset *)
|
20
|
+
return (Bitset *) calloc(1, sizeof(Bitset));
|
19
21
|
}
|
20
22
|
|
21
23
|
void bitset_setup(Bitset * bs, int len) {
|
22
24
|
bs->len = len;
|
23
|
-
bs->data = (uint64_t *) calloc((
|
25
|
+
bs->data = (uint64_t *) calloc(INTS(bs), sizeof(uint64_t));
|
24
26
|
}
|
25
27
|
|
26
28
|
void bitset_free(Bitset * bs) {
|
@@ -30,7 +32,7 @@ void bitset_free(Bitset * bs) {
|
|
30
32
|
}
|
31
33
|
|
32
34
|
|
33
|
-
Bitset * get_bitset(VALUE obj) {
|
35
|
+
static Bitset * get_bitset(VALUE obj) {
|
34
36
|
Bitset * bs;
|
35
37
|
Data_Get_Struct(obj, Bitset, bs);
|
36
38
|
return bs;
|
@@ -53,44 +55,43 @@ static VALUE rb_bitset_size(VALUE self, VALUE len) {
|
|
53
55
|
return INT2NUM(bs->len);
|
54
56
|
}
|
55
57
|
|
56
|
-
void raise_index_error() {
|
58
|
+
static void raise_index_error() {
|
57
59
|
VALUE rb_eIndexError = rb_const_get(rb_cObject, rb_intern("IndexError"));
|
58
60
|
rb_raise(rb_eIndexError, "Index out of bounds");
|
59
61
|
}
|
60
62
|
|
61
|
-
#define
|
62
|
-
#define
|
63
|
+
#define _bit_no(bit) ((bit) & 0x3f)
|
64
|
+
#define _bit_segment(bit) ((bit) >> 6)
|
65
|
+
#define _bit_mask(bit) (((uint64_t) 1) << _bit_no(bit))
|
66
|
+
#define _seg_no_to_bit_no(seg_no) ((seg_no) << 6)
|
67
|
+
#define _get_bit(bs, idx) ((bs)->data[_bit_segment(idx)] & _bit_mask(idx))
|
68
|
+
#define _set_bit(bs, idx) ((bs)->data[_bit_segment(idx)] |= _bit_mask(idx))
|
69
|
+
#define _clear_bit(bs, idx) ((bs)->data[_bit_segment(idx)] &= ~_bit_mask(idx))
|
63
70
|
|
64
|
-
void validate_index(Bitset * bs, int idx) {
|
71
|
+
static void validate_index(Bitset * bs, int idx) {
|
65
72
|
if(idx < 0 || idx >= bs->len)
|
66
73
|
raise_index_error();
|
67
74
|
}
|
68
75
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
void set_bit(Bitset * bs, int idx) {
|
75
|
-
bs->data[_bit_segment(idx)] |= _bit_mask(idx);
|
76
|
-
}
|
77
|
-
|
78
|
-
void clear_bit(Bitset * bs, int idx) {
|
79
|
-
bs->data[_bit_segment(idx)] &= ~_bit_mask(idx);
|
76
|
+
static void verify_equal_size(Bitset * bs1, Bitset * bs2) {
|
77
|
+
if (bs1->len != bs2->len) {
|
78
|
+
VALUE rb_eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
79
|
+
rb_raise(rb_eArgumentError, "Operands size mismatch");
|
80
|
+
}
|
80
81
|
}
|
81
82
|
|
82
83
|
void assign_bit(Bitset * bs, int idx, VALUE value) {
|
83
84
|
if(NIL_P(value) || value == Qfalse)
|
84
|
-
|
85
|
+
_clear_bit(bs, idx);
|
85
86
|
else
|
86
|
-
|
87
|
+
_set_bit(bs, idx);
|
87
88
|
}
|
88
89
|
|
89
90
|
static VALUE rb_bitset_aref(VALUE self, VALUE index) {
|
90
91
|
Bitset * bs = get_bitset(self);
|
91
92
|
int idx = NUM2INT(index);
|
92
93
|
validate_index(bs, idx);
|
93
|
-
return
|
94
|
+
return _get_bit(bs, idx) > 0 ? Qtrue : Qfalse;
|
94
95
|
}
|
95
96
|
|
96
97
|
static VALUE rb_bitset_aset(VALUE self, VALUE index, VALUE value) {
|
@@ -108,7 +109,7 @@ static VALUE rb_bitset_set(int argc, VALUE * argv, VALUE self) {
|
|
108
109
|
VALUE index = argv[i];
|
109
110
|
int idx = NUM2INT(index);
|
110
111
|
validate_index(bs, idx);
|
111
|
-
|
112
|
+
_set_bit(bs, idx);
|
112
113
|
}
|
113
114
|
return Qtrue;
|
114
115
|
}
|
@@ -120,7 +121,7 @@ static VALUE rb_bitset_clear(int argc, VALUE * argv, VALUE self) {
|
|
120
121
|
VALUE index = argv[i];
|
121
122
|
int idx = NUM2INT(index);
|
122
123
|
validate_index(bs, idx);
|
123
|
-
|
124
|
+
_clear_bit(bs, idx);
|
124
125
|
}
|
125
126
|
return Qtrue;
|
126
127
|
}
|
@@ -132,7 +133,7 @@ static VALUE rb_bitset_clear_p(int argc, VALUE * argv, VALUE self) {
|
|
132
133
|
VALUE index = argv[i];
|
133
134
|
int idx = NUM2INT(index);
|
134
135
|
validate_index(bs, idx);
|
135
|
-
if(
|
136
|
+
if(_get_bit(bs, idx) > 0)
|
136
137
|
return Qfalse;
|
137
138
|
}
|
138
139
|
return Qtrue;
|
@@ -145,7 +146,7 @@ static VALUE rb_bitset_set_p(int argc, VALUE * argv, VALUE self) {
|
|
145
146
|
VALUE index = argv[i];
|
146
147
|
int idx = NUM2INT(index);
|
147
148
|
validate_index(bs, idx);
|
148
|
-
if(
|
149
|
+
if(_get_bit(bs, idx) == 0)
|
149
150
|
return Qfalse;
|
150
151
|
}
|
151
152
|
return Qtrue;
|
@@ -154,13 +155,10 @@ static VALUE rb_bitset_set_p(int argc, VALUE * argv, VALUE self) {
|
|
154
155
|
static VALUE rb_bitset_cardinality(VALUE self) {
|
155
156
|
Bitset * bs = get_bitset(self);
|
156
157
|
int i;
|
157
|
-
int max = (
|
158
|
+
int max = INTS(bs);
|
158
159
|
int count = 0;
|
159
160
|
for(i = 0; i < max; i++) {
|
160
|
-
|
161
|
-
if(i+1 == max)
|
162
|
-
segment &= ((((uint64_t) 1) << (bs->len & 0x3F)) - 1);
|
163
|
-
count += __builtin_popcountll(segment);
|
161
|
+
count += __builtin_popcountll(bs->data[i]);
|
164
162
|
}
|
165
163
|
return INT2NUM(count);
|
166
164
|
}
|
@@ -168,11 +166,12 @@ static VALUE rb_bitset_cardinality(VALUE self) {
|
|
168
166
|
static VALUE rb_bitset_intersect(VALUE self, VALUE other) {
|
169
167
|
Bitset * bs = get_bitset(self);
|
170
168
|
Bitset * other_bs = get_bitset(other);
|
169
|
+
verify_equal_size(bs, other_bs);
|
171
170
|
|
172
171
|
Bitset * new_bs = bitset_new();
|
173
172
|
bitset_setup(new_bs, bs->len);
|
174
173
|
|
175
|
-
int max = (
|
174
|
+
int max = INTS(bs);
|
176
175
|
int i;
|
177
176
|
for(i = 0; i < max; i++) {
|
178
177
|
uint64_t segment = bs->data[i];
|
@@ -186,11 +185,12 @@ static VALUE rb_bitset_intersect(VALUE self, VALUE other) {
|
|
186
185
|
static VALUE rb_bitset_union(VALUE self, VALUE other) {
|
187
186
|
Bitset * bs = get_bitset(self);
|
188
187
|
Bitset * other_bs = get_bitset(other);
|
188
|
+
verify_equal_size(bs, other_bs);
|
189
189
|
|
190
190
|
Bitset * new_bs = bitset_new();
|
191
191
|
bitset_setup(new_bs, bs->len);
|
192
192
|
|
193
|
-
int max = (
|
193
|
+
int max = INTS(bs);
|
194
194
|
int i;
|
195
195
|
for(i = 0; i < max; i++) {
|
196
196
|
uint64_t segment = bs->data[i];
|
@@ -204,11 +204,12 @@ static VALUE rb_bitset_union(VALUE self, VALUE other) {
|
|
204
204
|
static VALUE rb_bitset_difference(VALUE self, VALUE other) {
|
205
205
|
Bitset * bs = get_bitset(self);
|
206
206
|
Bitset * other_bs = get_bitset(other);
|
207
|
+
verify_equal_size(bs, other_bs);
|
207
208
|
|
208
209
|
Bitset * new_bs = bitset_new();
|
209
210
|
bitset_setup(new_bs, bs->len);
|
210
211
|
|
211
|
-
int max = (
|
212
|
+
int max = INTS(bs);
|
212
213
|
int i;
|
213
214
|
for(i = 0; i < max; i++) {
|
214
215
|
uint64_t segment = bs->data[i];
|
@@ -222,11 +223,12 @@ static VALUE rb_bitset_difference(VALUE self, VALUE other) {
|
|
222
223
|
static VALUE rb_bitset_xor(VALUE self, VALUE other) {
|
223
224
|
Bitset * bs = get_bitset(self);
|
224
225
|
Bitset * other_bs = get_bitset(other);
|
226
|
+
verify_equal_size(bs, other_bs);
|
225
227
|
|
226
228
|
Bitset * new_bs = bitset_new();
|
227
229
|
bitset_setup(new_bs, bs->len);
|
228
230
|
|
229
|
-
int max = (
|
231
|
+
int max = INTS(bs);
|
230
232
|
int i;
|
231
233
|
for(i = 0; i < max; i++) {
|
232
234
|
uint64_t segment = bs->data[i];
|
@@ -243,12 +245,15 @@ static VALUE rb_bitset_not(VALUE self) {
|
|
243
245
|
Bitset * new_bs = bitset_new();
|
244
246
|
bitset_setup(new_bs, bs->len);
|
245
247
|
|
246
|
-
int max = (
|
248
|
+
int max = INTS(bs);
|
249
|
+
|
247
250
|
int i;
|
248
251
|
for(i = 0; i < max; i++) {
|
249
252
|
uint64_t segment = bs->data[i];
|
250
253
|
new_bs->data[i] = ~segment;
|
251
254
|
}
|
255
|
+
if(_bit_no(bs->len) != 0)
|
256
|
+
new_bs->data[max-1] &= _bit_mask(bs->len) - 1;
|
252
257
|
|
253
258
|
return Data_Wrap_Struct(cBitset, 0, bitset_free, new_bs);
|
254
259
|
}
|
@@ -259,7 +264,7 @@ static VALUE rb_bitset_to_s(VALUE self) {
|
|
259
264
|
int i;
|
260
265
|
char * data = malloc(bs->len + 1);
|
261
266
|
for(i = 0; i < bs->len; i++) {
|
262
|
-
data[i] =
|
267
|
+
data[i] = _get_bit(bs, i) ? '1' : '0';
|
263
268
|
}
|
264
269
|
data[bs->len] = 0;
|
265
270
|
|
@@ -276,7 +281,7 @@ static VALUE rb_bitset_from_s(VALUE self, VALUE s) {
|
|
276
281
|
int i;
|
277
282
|
for (i = 0; i < length; i++) {
|
278
283
|
if (data[i] == '1') {
|
279
|
-
|
284
|
+
_set_bit(new_bs, i);
|
280
285
|
}
|
281
286
|
}
|
282
287
|
|
@@ -287,7 +292,7 @@ static VALUE rb_bitset_hamming(VALUE self, VALUE other) {
|
|
287
292
|
Bitset * bs = get_bitset(self);
|
288
293
|
Bitset * other_bs = get_bitset(other);
|
289
294
|
|
290
|
-
int max = (
|
295
|
+
int max = INTS(bs);
|
291
296
|
int count = 0;
|
292
297
|
int i;
|
293
298
|
for(i = 0; i < max; i++) {
|
@@ -304,7 +309,7 @@ static VALUE rb_bitset_each(VALUE self) {
|
|
304
309
|
int i;
|
305
310
|
|
306
311
|
for(i = 0; i < bs->len; i++) {
|
307
|
-
rb_yield(
|
312
|
+
rb_yield(_get_bit(bs, i) ? Qtrue : Qfalse);
|
308
313
|
}
|
309
314
|
|
310
315
|
return self;
|
@@ -335,11 +340,171 @@ static VALUE rb_bitset_marshall_load(VALUE self, VALUE hash) {
|
|
335
340
|
return Qnil;
|
336
341
|
}
|
337
342
|
|
343
|
+
static VALUE rb_bitset_dup(VALUE self) {
|
344
|
+
Bitset * bs = get_bitset(self);
|
345
|
+
|
346
|
+
Bitset * new_bs = bitset_new();
|
347
|
+
bitset_setup(new_bs, bs->len);
|
348
|
+
|
349
|
+
int max = INTS(bs);
|
350
|
+
memcpy(new_bs->data, bs->data, max * sizeof(bs->data[0]));
|
351
|
+
return Data_Wrap_Struct(cBitset, 0, bitset_free, new_bs);
|
352
|
+
}
|
353
|
+
|
354
|
+
/* Yield the bit numbers of each set bit in sequence to a block. If
|
355
|
+
there is no block, return an array of those numbers. */
|
356
|
+
static VALUE rb_bitset_each_set(VALUE self) {
|
357
|
+
Bitset * bs = get_bitset(self);
|
358
|
+
int seg_no;
|
359
|
+
int max = INTS(bs);
|
360
|
+
uint64_t* seg_ptr = bs->data;
|
361
|
+
int block_p = rb_block_given_p();
|
362
|
+
VALUE ary = Qnil;
|
363
|
+
|
364
|
+
if (!block_p) {
|
365
|
+
ary = rb_ary_new();
|
366
|
+
}
|
367
|
+
|
368
|
+
for (seg_no = 0; seg_no < max; ++seg_no, ++seg_ptr) {
|
369
|
+
uint64_t segment = *seg_ptr;
|
370
|
+
int bit_position = 0;
|
371
|
+
while (segment) {
|
372
|
+
VALUE v;
|
373
|
+
|
374
|
+
if (!(segment & 1)) {
|
375
|
+
int shift = __builtin_ctzll(segment);
|
376
|
+
bit_position += shift;
|
377
|
+
segment >>= shift;
|
378
|
+
}
|
379
|
+
v = INT2NUM(_seg_no_to_bit_no(seg_no) + bit_position);
|
380
|
+
if (block_p) {
|
381
|
+
rb_yield(v);
|
382
|
+
} else {
|
383
|
+
rb_ary_push(ary, v);
|
384
|
+
}
|
385
|
+
++bit_position;
|
386
|
+
segment >>= 1;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
return block_p ? self : ary;
|
391
|
+
}
|
392
|
+
|
393
|
+
static VALUE rb_bitset_empty_p(VALUE self) {
|
394
|
+
Bitset * bs = get_bitset(self);
|
395
|
+
int seg_no;
|
396
|
+
int max = INTS(bs);
|
397
|
+
uint64_t* seg_ptr = bs->data;
|
398
|
+
|
399
|
+
for (seg_no = 0; seg_no < max; ++seg_no, ++seg_ptr) {
|
400
|
+
if (*seg_ptr) {
|
401
|
+
return Qfalse;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
return Qtrue;
|
405
|
+
}
|
406
|
+
|
407
|
+
static VALUE rb_bitset_select_bits(VALUE self, VALUE index_array) {
|
408
|
+
int i;
|
409
|
+
Bitset * bs = get_bitset(self);
|
410
|
+
struct RArray *arr = RARRAY(index_array);
|
411
|
+
int blen = bs->len;
|
412
|
+
int alen = RARRAY_LEN(index_array);
|
413
|
+
VALUE *ptr = RARRAY_PTR(index_array);
|
414
|
+
Bitset * new_bs = bitset_new();
|
415
|
+
bitset_setup(new_bs, alen);
|
416
|
+
for (i = 0; i < alen; ++i) {
|
417
|
+
int idx = NUM2INT(ptr[i]);
|
418
|
+
if (idx >= 0 && idx < blen && _get_bit(bs, idx)) {
|
419
|
+
_set_bit(new_bs, i);
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
return Data_Wrap_Struct(cBitset, 0, bitset_free, new_bs);
|
424
|
+
}
|
425
|
+
|
426
|
+
/** This could run a bit faster if you worked at it. */
|
427
|
+
static VALUE rb_bitset_reverse(VALUE self, VALUE index_array) {
|
428
|
+
int i;
|
429
|
+
Bitset * bs = get_bitset(self);
|
430
|
+
int len = bs->len;
|
431
|
+
Bitset * new_bs = bitset_new();
|
432
|
+
bitset_setup(new_bs, len);
|
433
|
+
for (i = 0; i < len; ++i) {
|
434
|
+
if (_get_bit(bs, i)) {
|
435
|
+
_set_bit(new_bs, len - i - 1);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
return Data_Wrap_Struct(cBitset, 0, bitset_free, new_bs);
|
440
|
+
}
|
441
|
+
|
442
|
+
static VALUE rb_bitset_equal(VALUE self, VALUE other) {
|
443
|
+
int i;
|
444
|
+
Bitset * bs = get_bitset(self);
|
445
|
+
Bitset * other_bs = get_bitset(other);
|
446
|
+
|
447
|
+
if (bs->len != other_bs->len)
|
448
|
+
return Qfalse;
|
449
|
+
int max = INTS(bs);
|
450
|
+
for(i = 0; i < max; i++) {
|
451
|
+
if (bs->data[i] != other_bs->data[i]) {
|
452
|
+
return Qfalse;
|
453
|
+
}
|
454
|
+
}
|
455
|
+
return Qtrue;
|
456
|
+
}
|
457
|
+
|
458
|
+
typedef uint64_t (*bitwise_op)(uint64_t, uint64_t);
|
459
|
+
inline uint64_t and(uint64_t a, uint64_t b) { return a & b; }
|
460
|
+
inline uint64_t or(uint64_t a, uint64_t b) { return a | b; }
|
461
|
+
inline uint64_t xor(uint64_t a, uint64_t b) { return a ^ b; }
|
462
|
+
inline uint64_t difference(uint64_t a, uint64_t b) { return a & ~b; }
|
463
|
+
|
464
|
+
static VALUE mutable(VALUE self, VALUE other, bitwise_op operator) {
|
465
|
+
Bitset * bs = get_bitset(self);
|
466
|
+
Bitset * other_bs = get_bitset(other);
|
467
|
+
verify_equal_size(bs, other_bs);
|
468
|
+
|
469
|
+
int max = INTS(bs);
|
470
|
+
int i;
|
471
|
+
for(i = 0; i < max; i++) {
|
472
|
+
uint64_t segment = bs->data[i];
|
473
|
+
uint64_t other_segment = other_bs->data[i];
|
474
|
+
bs->data[i] = operator(segment, other_segment);
|
475
|
+
}
|
476
|
+
|
477
|
+
return self;
|
478
|
+
}
|
479
|
+
|
480
|
+
static VALUE rb_bitset_union_mutable(VALUE self, VALUE other) {
|
481
|
+
return mutable(self, other, &or);
|
482
|
+
}
|
483
|
+
|
484
|
+
static VALUE rb_bitset_intersect_mutable(VALUE self, VALUE other) {
|
485
|
+
return mutable(self, other, &and);
|
486
|
+
}
|
487
|
+
|
488
|
+
static VALUE rb_bitset_xor_mutable(VALUE self, VALUE other) {
|
489
|
+
return mutable(self, other, &xor);
|
490
|
+
}
|
491
|
+
|
492
|
+
static VALUE rb_bitset_difference_mutable(VALUE self, VALUE other) {
|
493
|
+
return mutable(self, other, &difference);
|
494
|
+
}
|
495
|
+
|
496
|
+
static VALUE rb_bitset_reset(VALUE self) {
|
497
|
+
Bitset * bs = get_bitset(self);
|
498
|
+
memset(bs->data, 0, (INTS(bs) * sizeof(uint64_t)) );
|
499
|
+
return self;
|
500
|
+
}
|
501
|
+
|
338
502
|
void Init_bitset() {
|
339
503
|
cBitset = rb_define_class("Bitset", rb_cObject);
|
340
504
|
rb_include_module(cBitset, rb_mEnumerable);
|
341
505
|
rb_define_alloc_func(cBitset, rb_bitset_alloc);
|
342
506
|
rb_define_method(cBitset, "initialize", rb_bitset_initialize, 1);
|
507
|
+
rb_define_method(cBitset, "reset!", rb_bitset_reset, 0);
|
343
508
|
rb_define_method(cBitset, "size", rb_bitset_size, 0);
|
344
509
|
rb_define_method(cBitset, "[]", rb_bitset_aref, 1);
|
345
510
|
rb_define_method(cBitset, "[]=", rb_bitset_aset, 2);
|
@@ -350,13 +515,22 @@ void Init_bitset() {
|
|
350
515
|
rb_define_method(cBitset, "cardinality", rb_bitset_cardinality, 0);
|
351
516
|
rb_define_method(cBitset, "intersect", rb_bitset_intersect, 1);
|
352
517
|
rb_define_alias(cBitset, "&", "intersect");
|
518
|
+
rb_define_alias(cBitset, "and", "intersect");
|
519
|
+
rb_define_method(cBitset, "intersect!", rb_bitset_intersect_mutable, 1);
|
520
|
+
rb_define_alias(cBitset, "and!", "intersect!");
|
353
521
|
rb_define_method(cBitset, "union", rb_bitset_union, 1);
|
354
522
|
rb_define_alias(cBitset, "|", "union");
|
523
|
+
rb_define_alias(cBitset, "or", "union");
|
524
|
+
rb_define_method(cBitset, "union!", rb_bitset_union_mutable, 1);
|
525
|
+
rb_define_alias(cBitset, "or!", "union!");
|
355
526
|
rb_define_method(cBitset, "difference", rb_bitset_difference, 1);
|
356
527
|
rb_define_alias(cBitset, "-", "difference");
|
528
|
+
rb_define_method(cBitset, "difference!", rb_bitset_difference_mutable, 1);
|
357
529
|
rb_define_method(cBitset, "xor", rb_bitset_xor, 1);
|
358
530
|
rb_define_alias(cBitset, "^", "xor");
|
359
531
|
rb_define_alias(cBitset, "symmetric_difference", "xor");
|
532
|
+
rb_define_method(cBitset, "xor!", rb_bitset_xor_mutable, 1);
|
533
|
+
rb_define_alias(cBitset, "symmetric_difference!", "xor!");
|
360
534
|
rb_define_method(cBitset, "not", rb_bitset_not, 0);
|
361
535
|
rb_define_alias(cBitset, "~", "not");
|
362
536
|
rb_define_method(cBitset, "hamming", rb_bitset_hamming, 1);
|
@@ -365,4 +539,11 @@ void Init_bitset() {
|
|
365
539
|
rb_define_singleton_method(cBitset, "from_s", rb_bitset_from_s, 1);
|
366
540
|
rb_define_method(cBitset, "marshal_dump", rb_bitset_marshall_dump, 0);
|
367
541
|
rb_define_method(cBitset, "marshal_load", rb_bitset_marshall_load, 1);
|
542
|
+
rb_define_method(cBitset, "dup", rb_bitset_dup, 0);
|
543
|
+
rb_define_alias(cBitset, "clone", "dup");
|
544
|
+
rb_define_method(cBitset, "each_set", rb_bitset_each_set, 0);
|
545
|
+
rb_define_method(cBitset, "empty?", rb_bitset_empty_p, 0);
|
546
|
+
rb_define_method(cBitset, "select_bits", rb_bitset_select_bits, 1);
|
547
|
+
rb_define_method(cBitset, "reverse", rb_bitset_reverse, 0);
|
548
|
+
rb_define_method(cBitset, "==", rb_bitset_equal, 1);
|
368
549
|
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Bitset
|
2
|
+
|
3
|
+
# Return a string that represents this bitset packed into 8-bit
|
4
|
+
# characters. The first 3 bits represent the number of padding bits
|
5
|
+
# in the final byte of the string.
|
6
|
+
|
7
|
+
# You could make a good case that this is redundant with
|
8
|
+
# Marshal.dump and Marshal.load, but it does save a few bytes.
|
9
|
+
def pack
|
10
|
+
# Number of bits of zero padding in this representation.
|
11
|
+
padding_bits = (size+3) & 7
|
12
|
+
padding_bits = (padding_bits == 0) ? 0 : (8 - padding_bits)
|
13
|
+
[("%03b" % padding_bits) + self.to_s].pack("b*")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Convert a string created using the pack method back into a bitset.
|
17
|
+
def self.unpack str
|
18
|
+
bits = str.unpack("b*")[0]
|
19
|
+
padding_bits = bits[0...3].to_i(2)
|
20
|
+
from_s(bits[3 .. -1 - padding_bits])
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/bitset_spec.rb
CHANGED
@@ -5,10 +5,14 @@ describe Bitset do
|
|
5
5
|
Bitset.new(64)
|
6
6
|
end
|
7
7
|
|
8
|
+
it 'raises ArgumentError wihen initialized with no argument' do
|
9
|
+
expect { Bitset.new }.to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
8
12
|
describe :size do
|
9
13
|
it 'returns the correct size' do
|
10
|
-
Bitset.new(64).size.
|
11
|
-
Bitset.new(73).size.
|
14
|
+
expect(Bitset.new(64).size).to eq(64)
|
15
|
+
expect(Bitset.new(73).size).to eq(73)
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
@@ -16,17 +20,18 @@ describe Bitset do
|
|
16
20
|
it 'returns True for set bits' do
|
17
21
|
bs = Bitset.new(8)
|
18
22
|
bs[0] = true
|
19
|
-
bs[0].
|
23
|
+
expect(bs[0]).to be true
|
20
24
|
end
|
21
25
|
|
22
26
|
it 'returns False for unset bits' do
|
23
27
|
bs = Bitset.new(8)
|
24
|
-
bs[0].
|
28
|
+
expect(bs[0]).to be false
|
25
29
|
end
|
26
30
|
|
27
31
|
it 'raises an error when accessing out of bound indexes' do
|
28
32
|
bs = Bitset.new(8)
|
29
33
|
expect { bs[8] }.to raise_error(IndexError)
|
34
|
+
expect { bs[-1] }.to raise_error(IndexError)
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
@@ -35,23 +40,23 @@ describe Bitset do
|
|
35
40
|
bs = Bitset.new(8)
|
36
41
|
|
37
42
|
bs[0] = true
|
38
|
-
bs[0].
|
43
|
+
expect(bs[0]).to be true
|
39
44
|
|
40
45
|
bs[1] = 123
|
41
|
-
bs[1].
|
46
|
+
expect(bs[1]).to be true
|
42
47
|
|
43
48
|
bs[2] = "woo"
|
44
|
-
bs[2].
|
49
|
+
expect(bs[2]).to be true
|
45
50
|
end
|
46
51
|
|
47
52
|
it 'sets False for falsey values' do
|
48
53
|
bs = Bitset.new(8)
|
49
54
|
|
50
55
|
bs[0] = false
|
51
|
-
bs[0].
|
56
|
+
expect(bs[0]).to be false
|
52
57
|
|
53
58
|
bs[1] = nil
|
54
|
-
bs[1].
|
59
|
+
expect(bs[1]).to be false
|
55
60
|
end
|
56
61
|
|
57
62
|
it 'raises an error when setting out of bound indexes' do
|
@@ -65,9 +70,10 @@ describe Bitset do
|
|
65
70
|
bs = Bitset.new(8)
|
66
71
|
bs.set 1,2,3
|
67
72
|
|
68
|
-
bs[1].
|
69
|
-
bs[
|
70
|
-
bs[
|
73
|
+
expect(bs[1]).to be true
|
74
|
+
expect(bs[0]).to be false
|
75
|
+
expect(bs[4]).to be false
|
76
|
+
expect(bs[3]).to be true
|
71
77
|
end
|
72
78
|
end
|
73
79
|
|
@@ -77,9 +83,9 @@ describe Bitset do
|
|
77
83
|
bs.set 1,2,3
|
78
84
|
bs.clear 1,3
|
79
85
|
|
80
|
-
bs[1].
|
81
|
-
bs[2].
|
82
|
-
bs[3].
|
86
|
+
expect(bs[1]).to be false
|
87
|
+
expect(bs[2]).to be true
|
88
|
+
expect(bs[3]).to be false
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
@@ -87,13 +93,13 @@ describe Bitset do
|
|
87
93
|
it 'returns True if all bits indexed are set' do
|
88
94
|
bs = Bitset.new(8)
|
89
95
|
bs.set 1, 4, 5
|
90
|
-
bs.set?(1,4,5).
|
96
|
+
expect(bs.set?(1,4,5)).to be true
|
91
97
|
end
|
92
98
|
|
93
99
|
it 'returns False if not all bits indexed are set' do
|
94
100
|
bs = Bitset.new(8)
|
95
101
|
bs.set 1, 4
|
96
|
-
bs.set?(1,4,5).
|
102
|
+
expect(bs.set?(1,4,5)).to be false
|
97
103
|
end
|
98
104
|
end
|
99
105
|
|
@@ -101,44 +107,48 @@ describe Bitset do
|
|
101
107
|
it 'returns True if all bits indexed are clear' do
|
102
108
|
bs = Bitset.new(8)
|
103
109
|
bs.set 1, 4, 5
|
104
|
-
bs.clear?(0,2,3,6).
|
110
|
+
expect(bs.clear?(0,2,3,6)).to be true
|
105
111
|
end
|
106
112
|
|
107
113
|
it 'returns works with the full range of 64 bit values' do
|
108
114
|
bs = Bitset.new(68)
|
109
115
|
bs.set 0, 2, 66
|
110
|
-
bs.clear?(32, 33, 34).
|
116
|
+
expect(bs.clear?(32, 33, 34)).to be true
|
111
117
|
end
|
112
118
|
|
113
119
|
it 'returns False if not all bits indexed are clear' do
|
114
120
|
bs = Bitset.new(8)
|
115
121
|
bs.set 1, 4
|
116
|
-
bs.clear?(1,2,6).
|
122
|
+
expect(bs.clear?(1,2,6)).to be false
|
117
123
|
end
|
118
124
|
end
|
119
125
|
|
120
126
|
describe :cardinality do
|
121
127
|
it 'returns the number of bits set' do
|
122
|
-
bs = Bitset.new(
|
123
|
-
bs.cardinality.
|
128
|
+
bs = Bitset.new(64)
|
129
|
+
expect(bs.cardinality).to eq(0)
|
124
130
|
|
125
131
|
bs[0] = true
|
126
|
-
bs.cardinality.
|
132
|
+
expect(bs.cardinality).to eq(1)
|
127
133
|
|
128
134
|
bs[1] = true
|
129
|
-
bs.cardinality.
|
135
|
+
expect(bs.cardinality).to eq(2)
|
130
136
|
|
131
137
|
bs[2] = true
|
132
|
-
bs.cardinality.
|
138
|
+
expect(bs.cardinality).to eq(3)
|
139
|
+
|
140
|
+
expect(bs.not.cardinality).to eq(bs.size - bs.cardinality)
|
133
141
|
end
|
134
142
|
|
135
143
|
it '... even for large numbers of bits' do
|
136
144
|
bs = Bitset.new(10_000)
|
137
|
-
|
138
|
-
bs.
|
145
|
+
size = 5000
|
146
|
+
bs.set(*(0...size).to_a)
|
147
|
+
expect(bs.cardinality).to eq(size)
|
139
148
|
|
140
149
|
bs = Bitset.from_s "01001101000000000000000000000011000010100100000000000000010000101000000000000000100000000100000000000010100100010000000010000100000100000001001000110000000000100010000000010100000000000000110000000000000000000000000100000000100010010000000000000000000001000000000000000000000000000001000000000000000000000000000100000000010010000000000000000000100100000000000000001000000010000001000000000000001000001100010001000000000000001000001000001000000000000001100010000010010001000000010000100000000000110000"
|
141
|
-
bs.cardinality.
|
150
|
+
expect(bs.cardinality).to eq(63)
|
151
|
+
expect(bs.not.cardinality).to eq(bs.size - bs.cardinality)
|
142
152
|
end
|
143
153
|
end
|
144
154
|
|
@@ -151,8 +161,8 @@ describe Bitset do
|
|
151
161
|
bs2.set 1, 2, 4, 6
|
152
162
|
|
153
163
|
bs3 = bs1 & bs2
|
154
|
-
bs3.set?(1,4).
|
155
|
-
bs3.clear?(0,2,3,5,6,7).
|
164
|
+
expect(bs3.set?(1,4)).to be true
|
165
|
+
expect(bs3.clear?(0,2,3,5,6,7)).to be true
|
156
166
|
end
|
157
167
|
end
|
158
168
|
|
@@ -165,8 +175,11 @@ describe Bitset do
|
|
165
175
|
bs2.set 1, 2, 4, 6
|
166
176
|
|
167
177
|
bs3 = bs1 | bs2
|
168
|
-
bs3.set?(1,2,4,6,7).
|
169
|
-
bs3.clear?(0,3,5).
|
178
|
+
expect(bs3.set?(1,2,4,6,7)).to be true
|
179
|
+
expect(bs3.clear?(0,3,5)).to be true
|
180
|
+
end
|
181
|
+
it 'throws if size mismatch' do
|
182
|
+
expect { Bitset.new(3) | Bitset.new(7) }.to raise_error(ArgumentError)
|
170
183
|
end
|
171
184
|
end
|
172
185
|
|
@@ -179,8 +192,11 @@ describe Bitset do
|
|
179
192
|
bs2.set 1, 2, 4, 6
|
180
193
|
|
181
194
|
bs3 = bs1 - bs2
|
182
|
-
bs3.set?(7).
|
183
|
-
bs3.clear?(0,1,2,3,4,5,6).
|
195
|
+
expect(bs3.set?(7)).to be true
|
196
|
+
expect(bs3.clear?(0,1,2,3,4,5,6)).to be true
|
197
|
+
end
|
198
|
+
it 'throws if size mismatch' do
|
199
|
+
expect { Bitset.new(3) - Bitset.new(7) }.to raise_error(ArgumentError)
|
184
200
|
end
|
185
201
|
end
|
186
202
|
|
@@ -193,19 +209,23 @@ describe Bitset do
|
|
193
209
|
bs2.set 1, 2, 4, 6
|
194
210
|
|
195
211
|
bs3 = bs1 ^ bs2
|
196
|
-
bs3.set?(2,6,7).
|
197
|
-
bs3.clear?(0,1,3,4,5).
|
212
|
+
expect(bs3.set?(2,6,7)).to be true
|
213
|
+
expect(bs3.clear?(0,1,3,4,5)).to be true
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'throws if size mismatch' do
|
217
|
+
expect { Bitset.new(3) ^ Bitset.new(7) }.to raise_error(ArgumentError)
|
198
218
|
end
|
199
219
|
end
|
200
220
|
|
201
221
|
describe :not do
|
202
|
-
it "returns a new Bitset
|
222
|
+
it "returns a new Bitset which is the not of one Bitset" do
|
203
223
|
bs1 = Bitset.new(8)
|
204
224
|
bs1.set 1, 4, 7
|
205
225
|
|
206
226
|
bs2 = bs1.not
|
207
|
-
bs2.set?(0, 2, 3, 5, 6).
|
208
|
-
bs2.clear?(1, 4, 7).
|
227
|
+
expect(bs2.set?(0, 2, 3, 5, 6)).to be true
|
228
|
+
expect(bs2.clear?(1, 4, 7)).to be true
|
209
229
|
end
|
210
230
|
end
|
211
231
|
|
@@ -217,7 +237,7 @@ describe Bitset do
|
|
217
237
|
bs2 = Bitset.new(8)
|
218
238
|
bs2.set 1, 2, 4, 6
|
219
239
|
|
220
|
-
bs1.hamming(bs2).
|
240
|
+
expect(bs1.hamming(bs2)).to eq(3)
|
221
241
|
end
|
222
242
|
end
|
223
243
|
|
@@ -228,10 +248,50 @@ describe Bitset do
|
|
228
248
|
|
229
249
|
i = 0
|
230
250
|
bs.each do |bit|
|
231
|
-
bit.
|
251
|
+
expect(bit).to be bs[i]
|
232
252
|
i += 1
|
233
253
|
end
|
234
|
-
i.
|
254
|
+
expect(i).to eq(4)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe :each_set do
|
259
|
+
it 'iterates over each set bit in the Bitset' do
|
260
|
+
bs = Bitset.new(4)
|
261
|
+
sets = [0,3]
|
262
|
+
bs.set(*sets)
|
263
|
+
sets2 = []
|
264
|
+
bs.each_set { |bit| sets2 << bit }
|
265
|
+
expect(sets2).to eq(sets)
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'without a block, it returns an array of set bits' do
|
269
|
+
bs = Bitset.new(4)
|
270
|
+
sets = [0,3]
|
271
|
+
bs.set(*sets)
|
272
|
+
expect(bs.each_set).to eq(sets)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe :empty? do
|
277
|
+
it 'returns empty only if all zeroes' do
|
278
|
+
expect(Bitset.new(225).tap { |bs| bs[133] = true }.empty?).to be false
|
279
|
+
expect(Bitset.new(0).empty?).to be true
|
280
|
+
expect(Bitset.new(225).empty?).to be true
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe :dup do
|
285
|
+
it "returns a duplicate" do
|
286
|
+
bs = Bitset.from_s("11011")
|
287
|
+
expect(bs.dup.tap { |bs| bs.clear 1,3 }.to_s).to eq("10001")
|
288
|
+
expect(bs.to_s).to eq("11011")
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe :clone do
|
293
|
+
it "works" do
|
294
|
+
expect(Bitset.new(0).clone.to_s).to eq("")
|
235
295
|
end
|
236
296
|
end
|
237
297
|
|
@@ -239,18 +299,18 @@ describe Bitset do
|
|
239
299
|
it 'correctly prints out a binary string' do
|
240
300
|
bs = Bitset.new(4)
|
241
301
|
bs.set 0, 2
|
242
|
-
bs.to_s.
|
302
|
+
expect(bs.to_s).to eq("1010")
|
243
303
|
|
244
304
|
bs = Bitset.new(68)
|
245
305
|
bs.set 0, 2, 66
|
246
|
-
bs.to_s.
|
306
|
+
expect(bs.to_s).to eq("101" + ("0" * 63) + "10")
|
247
307
|
end
|
248
308
|
end
|
249
309
|
|
250
310
|
describe :from_s do
|
251
311
|
it 'correctly creates a bitmap from a binary string' do
|
252
312
|
bs = Bitset.from_s("10101")
|
253
|
-
bs.set?(0, 2, 4).
|
313
|
+
expect(bs.set?(0, 2, 4)).to be true
|
254
314
|
end
|
255
315
|
end
|
256
316
|
|
@@ -260,8 +320,65 @@ describe Bitset do
|
|
260
320
|
bs.set 1, 65
|
261
321
|
|
262
322
|
serialized = Marshal.load(Marshal.dump(bs))
|
263
|
-
serialized.set?(1, 65).
|
264
|
-
serialized.cardinality.
|
323
|
+
expect(serialized.set?(1, 65)).to be true
|
324
|
+
expect(serialized.cardinality).to eq(2)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe :union! do
|
329
|
+
it 'acts like |=' do
|
330
|
+
bs = Bitset.from_s "11011"
|
331
|
+
bs2 = Bitset.from_s "01111"
|
332
|
+
bs3 = bs.dup
|
333
|
+
bs.union!(bs2)
|
334
|
+
expect(bs).to eq(bs3 | bs2)
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'throws if size mismatch' do
|
338
|
+
expect { Bitset.new(3).union!(Bitset.new(7)) }.to raise_error(ArgumentError)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe :intersect! do
|
343
|
+
it 'acts like &=' do
|
344
|
+
bs = Bitset.from_s "11011"
|
345
|
+
bs2 = Bitset.from_s "01111"
|
346
|
+
bs3 = bs.dup
|
347
|
+
bs.intersect!(bs2)
|
348
|
+
expect(bs).to eq(bs3 & bs2)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
describe :xor! do
|
353
|
+
it 'acts like ^=' do
|
354
|
+
bs = Bitset.from_s "11011"
|
355
|
+
bs2 = Bitset.from_s "01111"
|
356
|
+
bs3 = bs.dup
|
357
|
+
bs.xor!(bs2)
|
358
|
+
expect(bs).to eq(bs3 ^ bs2)
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'throws if size mismatch' do
|
362
|
+
expect { Bitset.new(3).xor!(Bitset.new(7)) }.to raise_error(ArgumentError)
|
265
363
|
end
|
266
364
|
end
|
365
|
+
|
366
|
+
describe :difference! do
|
367
|
+
it 'acts like -=' do
|
368
|
+
bs = Bitset.from_s "11011"
|
369
|
+
bs2 = Bitset.from_s "01111"
|
370
|
+
bs3 = bs.dup
|
371
|
+
bs.difference!(bs2)
|
372
|
+
expect(bs).to eq(bs3 - bs2)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe :reset! do
|
377
|
+
it 'causes empty? to become true' do
|
378
|
+
bs = Bitset.from_s "11011"
|
379
|
+
bs.reset!
|
380
|
+
expect(bs.empty?).to be true
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
267
384
|
end
|
metadata
CHANGED
@@ -1,72 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitset
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: 0.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Tyler McMullen
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2011-03-03 00:00:00 -08:00
|
18
|
-
default_executable:
|
11
|
+
date: 2017-05-15 00:00:00.000000000 Z
|
19
12
|
dependencies: []
|
20
|
-
|
21
|
-
|
22
|
-
email:
|
13
|
+
description: A fast C-based Bitset. It supports the standard set operations as well
|
14
|
+
as operations you may expect on bit arrays. (popcount, for instance)
|
15
|
+
email: eric.boesch@nist.gov
|
23
16
|
executables: []
|
24
|
-
|
25
|
-
extensions:
|
17
|
+
extensions:
|
26
18
|
- ext/bitset/extconf.rb
|
27
|
-
extra_rdoc_files:
|
19
|
+
extra_rdoc_files:
|
28
20
|
- LICENSE.txt
|
29
|
-
- README.
|
30
|
-
files:
|
21
|
+
- README.markdown
|
22
|
+
files:
|
31
23
|
- LICENSE.txt
|
32
|
-
- README.
|
24
|
+
- README.markdown
|
33
25
|
- Rakefile
|
34
26
|
- VERSION
|
35
27
|
- bitset.gemspec
|
36
28
|
- ext/bitset/bitset.c
|
37
29
|
- ext/bitset/extconf.rb
|
30
|
+
- lib/bitset/bitset.rb
|
38
31
|
- spec/bitset_spec.rb
|
39
|
-
|
40
|
-
|
41
|
-
licenses:
|
32
|
+
homepage: http://github.com/ericboesch/bitset
|
33
|
+
licenses:
|
42
34
|
- MIT
|
35
|
+
metadata: {}
|
43
36
|
post_install_message:
|
44
37
|
rdoc_options: []
|
45
|
-
|
46
|
-
require_paths:
|
38
|
+
require_paths:
|
47
39
|
- lib
|
48
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
-
|
50
|
-
requirements:
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
51
42
|
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
59
47
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
- 0
|
63
|
-
version: "0"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
64
50
|
requirements: []
|
65
|
-
|
66
51
|
rubyforge_project:
|
67
|
-
rubygems_version:
|
52
|
+
rubygems_version: 2.6.12
|
68
53
|
signing_key:
|
69
|
-
specification_version:
|
54
|
+
specification_version: 4
|
70
55
|
summary: Bitset implementation.
|
71
|
-
test_files:
|
72
|
-
- spec/bitset_spec.rb
|
56
|
+
test_files: []
|
data/README.rdoc
DELETED