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.
Files changed (7) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/bitarray.gemspec +3 -3
  4. data/ext/bitarray.c +175 -30
  5. data/test/bm.rb +20 -17
  6. data/test/test.rb +28 -4
  7. 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' << ' BitArray Documentation'
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.2.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.2.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-23}
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", " BitArray Documentation"]
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
- size_t bits = NUM2SIZET(size);
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
- rb_bitarray_clone(VALUE self)
209
+ rb_bitarray_initialize_copy(VALUE self, VALUE orig)
205
210
  {
206
- struct bit_array *ba, *new_ba;
207
- VALUE rb_new_ba;
208
- Data_Get_Struct(self, struct bit_array, ba);
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 = ba->bits;
213
- new_ba->array_size = 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, ba->array, (ba->array_size * UINT_BYTES));
219
+ memcpy(new_ba->array, orig_ba->array, (new_ba->array_size * UINT_BYTES));
217
220
 
218
- return rb_new_ba;
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, VALUE bit)
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
- /* TODO: apparently, we need to define an #initialize_copy method instead
506
- * of clone.
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, "[]", rb_bitarray_get_bit, 1);
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)") { 10000.times { bf.total_set } }
33
- bm.report("BitArray total_set (none)") { 10000.times { ba.total_set } }
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)") { 10000.times { bf.total_set } }
37
- bm.report("BitArray total_set (all)") { 10000.times { ba.total_set } }
38
-
39
- puts "---------------------------- BitArray methods"
40
- bm.report("BitArray set_all_bits") { 10000.times { ba.set_all_bits} }
41
- bm.report("BitArray clear_all_bits") { 10000.times { ba.clear_all_bits } }
42
- bm.report("BitArray toggle_bit") { 10000.times { ba.toggle_bit(1) } }
43
- bm.report("BitArray toggle_all_bits") { 10000.times { ba.toggle_all_bits } }
44
- bm.report("BitArray clone") { 10000.times { ba.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
- bf = BitArray.new(10)
96
- bf[1] = 1
97
- bf[5] = 1
98
- assert_equal 2, bf.total_set
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.2.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-23 00:00:00 -07:00
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
- - " BitArray Documentation"
46
+ - BitArray Documentation
47
47
  require_paths:
48
48
  - ext
49
49
  required_ruby_version: !ruby/object:Gem::Requirement