ingramj-bitarray 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bitarray.gemspec +3 -3
- data/ext/bitarray.c +175 -30
- data/test/bm.rb +20 -17
- data/test/test.rb +28 -4
- metadata +3 -3
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ EOF
|
|
14
14
|
gem.require_paths = ["ext"]
|
15
15
|
gem.extensions = ["ext/extconf.rb"]
|
16
16
|
gem.required_ruby_version = ">= 1.9.1"
|
17
|
-
gem.rdoc_options << '--exclude' << 'ext/Makefile' << '--title' << '
|
17
|
+
gem.rdoc_options << '--exclude' << 'ext/Makefile' << '--title' << 'BitArray Documentation'
|
18
18
|
end
|
19
19
|
rescue LoadError
|
20
20
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.1
|
data/bitarray.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{bitarray}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.3.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["James E. Ingram"]
|
9
|
-
s.date = %q{2009-05-
|
9
|
+
s.date = %q{2009-05-24}
|
10
10
|
s.description = %q{A bit array class for Ruby, implemented as a C extension. Includes methods for setting and clearing individual bits, and all bits at once. Also has the standard array access methods, [] and []=, and it mixes in Enumerable.}
|
11
11
|
s.email = %q{ingramj@gmail.com}
|
12
12
|
s.extensions = ["ext/extconf.rb"]
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
]
|
31
31
|
s.has_rdoc = true
|
32
32
|
s.homepage = %q{http://github.com/ingramj/bitarray}
|
33
|
-
s.rdoc_options = ["--charset=UTF-8", "--exclude", "ext/Makefile", "--title", "
|
33
|
+
s.rdoc_options = ["--charset=UTF-8", "--exclude", "ext/Makefile", "--title", "BitArray Documentation"]
|
34
34
|
s.require_paths = ["ext"]
|
35
35
|
s.required_ruby_version = Gem::Requirement.new(">= 1.9.1")
|
36
36
|
s.rubygems_version = %q{1.3.1}
|
data/ext/bitarray.c
CHANGED
@@ -183,7 +183,12 @@ rb_bitarray_initialize(VALUE self, VALUE size)
|
|
183
183
|
struct bit_array *ba;
|
184
184
|
Data_Get_Struct(self, struct bit_array, ba);
|
185
185
|
|
186
|
-
|
186
|
+
ptrdiff_t bits = NUM2SSIZET(size);
|
187
|
+
if (bits <= 0) {
|
188
|
+
ba->bits = 0;
|
189
|
+
ba->array_size = 0;
|
190
|
+
return self;
|
191
|
+
}
|
187
192
|
size_t array_size = ((bits - 1) / UINT_BITS) + 1;
|
188
193
|
|
189
194
|
ba->bits = bits;
|
@@ -201,21 +206,62 @@ rb_bitarray_initialize(VALUE self, VALUE size)
|
|
201
206
|
* Produces a copy of _bitarray_.
|
202
207
|
*/
|
203
208
|
static VALUE
|
204
|
-
|
209
|
+
rb_bitarray_initialize_copy(VALUE self, VALUE orig)
|
205
210
|
{
|
206
|
-
struct bit_array *
|
207
|
-
|
208
|
-
Data_Get_Struct(
|
209
|
-
rb_new_ba = Data_Make_Struct(rb_bitarray_class, struct bit_array, NULL,
|
210
|
-
rb_bitarray_free, new_ba);
|
211
|
+
struct bit_array *new_ba, *orig_ba;
|
212
|
+
Data_Get_Struct(self, struct bit_array, new_ba);
|
213
|
+
Data_Get_Struct(orig, struct bit_array, orig_ba);
|
211
214
|
|
212
|
-
new_ba->bits =
|
213
|
-
new_ba->array_size =
|
215
|
+
new_ba->bits = orig_ba->bits;
|
216
|
+
new_ba->array_size = orig_ba->array_size;
|
214
217
|
new_ba->array = ruby_xcalloc(new_ba->array_size, UINT_BYTES);
|
215
218
|
|
216
|
-
memcpy(new_ba->array,
|
219
|
+
memcpy(new_ba->array, orig_ba->array, (new_ba->array_size * UINT_BYTES));
|
217
220
|
|
218
|
-
return
|
221
|
+
return self;
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
/* call-seq:
|
226
|
+
* bitarray + other_bitarray -> a_bitarray
|
227
|
+
*
|
228
|
+
* Concatenation---Return a new BitArray built by concatenating the two
|
229
|
+
* BitArrays.
|
230
|
+
*/
|
231
|
+
static VALUE
|
232
|
+
rb_bitarray_concat(VALUE x, VALUE y)
|
233
|
+
{
|
234
|
+
/* Get the bit_arrays from x and y */
|
235
|
+
struct bit_array *x_ba, *y_ba;
|
236
|
+
Data_Get_Struct(x, struct bit_array, x_ba);
|
237
|
+
Data_Get_Struct(y, struct bit_array, y_ba);
|
238
|
+
|
239
|
+
/* Create a new BitArray, and its bit_array */
|
240
|
+
VALUE z;
|
241
|
+
struct bit_array *z_ba;
|
242
|
+
z = rb_bitarray_alloc(rb_bitarray_class);
|
243
|
+
rb_bitarray_initialize(z, SIZET2NUM(x_ba->bits + y_ba->bits));
|
244
|
+
Data_Get_Struct(z, struct bit_array, z_ba);
|
245
|
+
|
246
|
+
/* For each bit set in x and y, set the corresponding bit in z.
|
247
|
+
*
|
248
|
+
* It might be faster to memcpy x_ba->array to the beginning of
|
249
|
+
* z_ba->array, then set the rest of the bits by looping over y...
|
250
|
+
*/
|
251
|
+
size_t z_index = 0;
|
252
|
+
size_t i;
|
253
|
+
for (i = 0; i < x_ba->bits; i++, z_index++) {
|
254
|
+
if (get_bit(x_ba, i) == 1) {
|
255
|
+
set_bit(z_ba, z_index);
|
256
|
+
}
|
257
|
+
}
|
258
|
+
for (i = 0; i < y_ba->bits; i++, z_index++) {
|
259
|
+
if (get_bit(y_ba, i) == 1) {
|
260
|
+
set_bit(z_ba, z_index);
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
return z;
|
219
265
|
}
|
220
266
|
|
221
267
|
|
@@ -376,22 +422,13 @@ rb_bitarray_toggle_all_bits(VALUE self)
|
|
376
422
|
}
|
377
423
|
}
|
378
424
|
|
379
|
-
|
380
|
-
/* call-seq:
|
381
|
-
* bitarray[index] -> value
|
382
|
-
*
|
383
|
-
* Bit Reference---Returns the bit at _index_. Negative indices count backwards
|
384
|
-
* from the end of _bitarray_. If _index_ is greater than the capacity of
|
385
|
-
* _bitarray_, an +IndexError+ is raised.
|
386
|
-
*/
|
425
|
+
/* Return an individual bit. */
|
387
426
|
static VALUE
|
388
|
-
rb_bitarray_get_bit(VALUE self,
|
427
|
+
rb_bitarray_get_bit(VALUE self, ptrdiff_t index)
|
389
428
|
{
|
390
429
|
struct bit_array *ba;
|
391
430
|
Data_Get_Struct(self, struct bit_array, ba);
|
392
431
|
|
393
|
-
ptrdiff_t index = NUM2SSIZET(bit);
|
394
|
-
|
395
432
|
int bit_value = get_bit(ba, index);
|
396
433
|
|
397
434
|
if (bit_value >= 0) {
|
@@ -402,6 +439,117 @@ rb_bitarray_get_bit(VALUE self, VALUE bit)
|
|
402
439
|
}
|
403
440
|
|
404
441
|
|
442
|
+
/* Create a new BitArray from a subsequence of x. */
|
443
|
+
static VALUE
|
444
|
+
rb_bitarray_subseq(VALUE x, ptrdiff_t beg, ptrdiff_t len)
|
445
|
+
{
|
446
|
+
|
447
|
+
struct bit_array *x_ba;
|
448
|
+
Data_Get_Struct(x, struct bit_array, x_ba);
|
449
|
+
|
450
|
+
/* Quick exit - a negative length, or a beginning past the end of the
|
451
|
+
* array returns nil.
|
452
|
+
*/
|
453
|
+
if (beg < 0) {
|
454
|
+
beg += x_ba->bits;
|
455
|
+
}
|
456
|
+
if (len < 0 || beg > x_ba->bits) {
|
457
|
+
return Qnil;
|
458
|
+
}
|
459
|
+
|
460
|
+
/* Make sure that we don't try getting more bits than x has. We handle this
|
461
|
+
* the same way as Array; if beg+len is past the end of x, shorten len.
|
462
|
+
*/
|
463
|
+
if (x_ba->bits < len || x_ba->bits < (beg + len)) {
|
464
|
+
len = x_ba->bits - beg;
|
465
|
+
}
|
466
|
+
|
467
|
+
/* Create a new BitArray of the appropriate size. */
|
468
|
+
VALUE y;
|
469
|
+
y = rb_bitarray_alloc(rb_bitarray_class);
|
470
|
+
rb_bitarray_initialize(y, SSIZET2NUM(len));
|
471
|
+
/* If our length is 0, we can just return now. */
|
472
|
+
if (len == 0) {
|
473
|
+
return y;
|
474
|
+
}
|
475
|
+
struct bit_array *y_ba;
|
476
|
+
Data_Get_Struct(y, struct bit_array, y_ba);
|
477
|
+
|
478
|
+
/* For each set bit in x[beg..len], set the corresponding bit in y. */
|
479
|
+
size_t x_index, y_index;
|
480
|
+
for (x_index = beg, y_index = 0;
|
481
|
+
x_index < beg + len;
|
482
|
+
x_index++, y_index++)
|
483
|
+
{
|
484
|
+
if (get_bit(x_ba, x_index) == 1) {
|
485
|
+
set_bit(y_ba, y_index);
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
489
|
+
return y;
|
490
|
+
}
|
491
|
+
|
492
|
+
|
493
|
+
/* call-seq:
|
494
|
+
* bitarray[index] -> value
|
495
|
+
* bitarray[beg, len] -> a_bitarray
|
496
|
+
* bitarray[range] -> a_bitarray
|
497
|
+
*
|
498
|
+
* Bit Reference---Returns the bit at _index_, or returns a subarray starting
|
499
|
+
* at _beg_, and continuing for _len_ bits, or returns a subarray specified by
|
500
|
+
* _range_. _Negative indices count backwards from the end of _bitarray_. If
|
501
|
+
* _index_ is greater than the capacity of _bitarray_, an +IndexError+ is
|
502
|
+
* raised.
|
503
|
+
*/
|
504
|
+
|
505
|
+
static VALUE
|
506
|
+
rb_bitarray_bitref(int argc, VALUE *argv, VALUE self)
|
507
|
+
{
|
508
|
+
/* We follow a form similar to rb_ary_aref in array.c */
|
509
|
+
|
510
|
+
/* Two arguments means we have a beginning and a length */
|
511
|
+
if (argc == 2) {
|
512
|
+
ptrdiff_t beg = NUM2SSIZET(argv[0]);
|
513
|
+
ptrdiff_t len = NUM2SSIZET(argv[1]);
|
514
|
+
return rb_bitarray_subseq(self, beg, len);
|
515
|
+
}
|
516
|
+
|
517
|
+
/* Make sure we have either 1 or 2 arguments. */
|
518
|
+
if (argc != 1) {
|
519
|
+
rb_scan_args(argc, argv, "11", 0, 0);
|
520
|
+
}
|
521
|
+
|
522
|
+
/* If we have a single argument, it can be either an index, or a range. */
|
523
|
+
VALUE arg = argv[0];
|
524
|
+
|
525
|
+
/* rb_ary_aref treats a fixnum argument specially, for a speedup in the
|
526
|
+
* most common case. We'll do the same.
|
527
|
+
*/
|
528
|
+
if (FIXNUM_P(arg)) {
|
529
|
+
return rb_bitarray_get_bit(self, FIX2LONG(arg));
|
530
|
+
}
|
531
|
+
|
532
|
+
struct bit_array *ba;
|
533
|
+
Data_Get_Struct(self, struct bit_array, ba);
|
534
|
+
/* Next we see if arg is a range. rb_range_beg_len is defined in range.c
|
535
|
+
* If arg is not a range, it returns Qfalse. If arg is a range, but it
|
536
|
+
* refers to invalid indices, it returns Qnil. Otherwise, it sets beg and
|
537
|
+
* end to the appropriate values.
|
538
|
+
*/
|
539
|
+
long beg, len;
|
540
|
+
switch (rb_range_beg_len(arg, &beg, &len, ba->bits, 0)) {
|
541
|
+
case Qfalse:
|
542
|
+
break;
|
543
|
+
case Qnil:
|
544
|
+
return Qnil;
|
545
|
+
default:
|
546
|
+
return rb_bitarray_subseq(self, beg, len);
|
547
|
+
}
|
548
|
+
|
549
|
+
return rb_bitarray_get_bit(self, NUM2SSIZET(arg));
|
550
|
+
}
|
551
|
+
|
552
|
+
|
405
553
|
/* call-seq:
|
406
554
|
* bitarray[index] = value -> value
|
407
555
|
*
|
@@ -498,15 +646,11 @@ Init_bitarray()
|
|
498
646
|
{
|
499
647
|
rb_bitarray_class = rb_define_class("BitArray", rb_cObject);
|
500
648
|
rb_define_alloc_func(rb_bitarray_class, rb_bitarray_alloc);
|
501
|
-
|
502
649
|
rb_define_method(rb_bitarray_class, "initialize",
|
503
650
|
rb_bitarray_initialize, 1);
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
*/
|
508
|
-
rb_define_method(rb_bitarray_class, "clone", rb_bitarray_clone, 0);
|
509
|
-
rb_define_alias(rb_bitarray_class, "dup", "clone");
|
651
|
+
rb_define_method(rb_bitarray_class, "initialize_copy",
|
652
|
+
rb_bitarray_initialize_copy, 1);
|
653
|
+
rb_define_method(rb_bitarray_class, "+", rb_bitarray_concat, 1);
|
510
654
|
rb_define_method(rb_bitarray_class, "size", rb_bitarray_size, 0);
|
511
655
|
rb_define_alias(rb_bitarray_class, "length", "size");
|
512
656
|
rb_define_method(rb_bitarray_class, "total_set", rb_bitarray_total_set, 0);
|
@@ -520,7 +664,8 @@ Init_bitarray()
|
|
520
664
|
rb_bitarray_toggle_bit, 1);
|
521
665
|
rb_define_method(rb_bitarray_class, "toggle_all_bits",
|
522
666
|
rb_bitarray_toggle_all_bits, 0);
|
523
|
-
rb_define_method(rb_bitarray_class, "[]",
|
667
|
+
rb_define_method(rb_bitarray_class, "[]", rb_bitarray_bitref, -1);
|
668
|
+
rb_define_alias(rb_bitarray_class, "slice", "[]");
|
524
669
|
rb_define_method(rb_bitarray_class, "[]=", rb_bitarray_assign_bit, 2);
|
525
670
|
rb_define_method(rb_bitarray_class, "inspect", rb_bitarray_inspect, 0);
|
526
671
|
rb_define_alias(rb_bitarray_class, "to_s", "inspect");
|
data/test/bm.rb
CHANGED
@@ -3,44 +3,47 @@ require 'bitarray'
|
|
3
3
|
require 'benchmark'
|
4
4
|
|
5
5
|
Benchmark.bm(28) { |bm|
|
6
|
-
puts "---------------------------- Object instantiation
|
6
|
+
puts "---------------------------- Object instantiation (10,000 iterations)"
|
7
7
|
bm.report("BitField initialize") { 10000.times { BitField.new(256) } }
|
8
8
|
bm.report("BitArray initialize") { 10000.times { BitArray.new(256) } }
|
9
9
|
|
10
10
|
bf = BitField.new(256)
|
11
11
|
ba = BitArray.new(256)
|
12
12
|
|
13
|
-
puts "---------------------------- Element Reading"
|
13
|
+
puts "---------------------------- Element Reading (10,000 iterations)"
|
14
14
|
bm.report("BitField []") { 10000.times { bf[rand(256)] } }
|
15
15
|
bm.report("BitArray []") { 10000.times { ba[rand(256)] } }
|
16
16
|
|
17
|
-
puts "---------------------------- Element Writing"
|
17
|
+
puts "---------------------------- Element Writing (10,000 iterations)"
|
18
18
|
bm.report("BitField []=") { 10000.times { bf[rand(256)] = [0,1][rand(2)] } }
|
19
19
|
bm.report("BitArray []=") { 10000.times { ba[rand(256)] = [0,1][rand(2)] } }
|
20
20
|
|
21
|
-
puts "---------------------------- Element Enumeration"
|
21
|
+
puts "---------------------------- Element Enumeration (10,000 iterations)"
|
22
22
|
bm.report("BitField each") { 10000.times { bf.each {|b| b } } }
|
23
23
|
bm.report("BitArray each") { 10000.times { ba.each {|b| b } } }
|
24
24
|
|
25
|
-
puts "---------------------------- To String"
|
25
|
+
puts "---------------------------- To String (10,000 iterations)"
|
26
26
|
bm.report("BitField to_s") { 10000.times { bf.to_s } }
|
27
27
|
bm.report("BitArray to_s") { 10000.times { ba.to_s } }
|
28
28
|
|
29
|
-
puts "---------------------------- Total Set"
|
29
|
+
puts "---------------------------- Total Set (100,000 iterations)"
|
30
30
|
bf = BitField.new(256)
|
31
31
|
ba = BitArray.new(256)
|
32
|
-
bm.report("BitField total_set (none)") {
|
33
|
-
bm.report("BitArray total_set (none)") {
|
32
|
+
bm.report("BitField total_set (none)") { 100000.times { bf.total_set } }
|
33
|
+
bm.report("BitArray total_set (none)") { 100000.times { ba.total_set } }
|
34
34
|
bf.each {|b| b = 1}
|
35
35
|
ba.set_all_bits
|
36
|
-
bm.report("BitField total_set (all)") {
|
37
|
-
bm.report("BitArray total_set (all)") {
|
38
|
-
|
39
|
-
puts "---------------------------- BitArray methods"
|
40
|
-
bm.report("BitArray set_all_bits") {
|
41
|
-
bm.report("BitArray clear_all_bits") {
|
42
|
-
bm.report("BitArray toggle_bit") {
|
43
|
-
bm.report("BitArray toggle_all_bits") {
|
44
|
-
bm.report("BitArray clone") {
|
36
|
+
bm.report("BitField total_set (all)") { 100000.times { bf.total_set } }
|
37
|
+
bm.report("BitArray total_set (all)") { 100000.times { ba.total_set } }
|
38
|
+
|
39
|
+
puts "---------------------------- BitArray methods (100,000 iterations)"
|
40
|
+
bm.report("BitArray set_all_bits") { 100000.times { ba.set_all_bits} }
|
41
|
+
bm.report("BitArray clear_all_bits") { 100000.times { ba.clear_all_bits } }
|
42
|
+
bm.report("BitArray toggle_bit") { 100000.times { ba.toggle_bit(1) } }
|
43
|
+
bm.report("BitArray toggle_all_bits") { 100000.times { ba.toggle_all_bits } }
|
44
|
+
bm.report("BitArray clone") { 100000.times { ba.clone } }
|
45
|
+
bm.report("BitArray slice (beg,len)") { 100000.times { ba[17, 230] } }
|
46
|
+
bm.report("BitArray slice (range)") { 100000.times { ba[17..247] } }
|
47
|
+
bm.report("BitArray +") { 100000.times { ba + ba } }
|
45
48
|
}
|
46
49
|
|
data/test/test.rb
CHANGED
@@ -92,10 +92,34 @@ class TestLibraryFileName < Test::Unit::TestCase
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def test_total_set
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
assert_equal 2,
|
95
|
+
ba = BitArray.new(10)
|
96
|
+
ba[1] = 1
|
97
|
+
ba[5] = 1
|
98
|
+
assert_equal 2, ba.total_set
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_slice_beg_len
|
102
|
+
ba = BitArray.new(10)
|
103
|
+
ba[1] = 1
|
104
|
+
ba[5] = 1
|
105
|
+
assert_equal "10001", ba[1,5].to_s
|
106
|
+
assert_equal "10000", ba[-5,5].to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_slice_range
|
110
|
+
ba = BitArray.new(10)
|
111
|
+
ba[1] = 1
|
112
|
+
ba[5] = 1
|
113
|
+
assert_equal "10001", ba[1..5].to_s
|
114
|
+
assert_equal "10000", ba[-5..-1].to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_concatenation
|
118
|
+
ba1 = BitArray.new(5)
|
119
|
+
ba2 = BitArray.new(5)
|
120
|
+
ba2.set_all_bits
|
121
|
+
ba3 = ba1 + ba2
|
122
|
+
assert_equal "0000011111", ba3.to_s
|
99
123
|
end
|
100
124
|
end
|
101
125
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ingramj-bitarray
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James E. Ingram
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-24 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -43,7 +43,7 @@ rdoc_options:
|
|
43
43
|
- --exclude
|
44
44
|
- ext/Makefile
|
45
45
|
- --title
|
46
|
-
-
|
46
|
+
- BitArray Documentation
|
47
47
|
require_paths:
|
48
48
|
- ext
|
49
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|