bitset 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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