ingramj-bitarray 0.2.0 → 0.3.1
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.
- 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
|