Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #1 from mceachen/master

TLC
  • Loading branch information...
commit 467499032c4b852d410262f73681db56d4f1728b 2 parents 9fe36be + 265f33b
Peter Cooper authored January 21, 2012
2  Gemfile
... ...
@@ -1,4 +1,2 @@
1 1
 source "http://rubygems.org"
2  
-
3  
-# Specify your gem's dependencies in bitarray.gemspec
4 2
 gemspec
20  Gemfile.lock
... ...
@@ -0,0 +1,20 @@
  1
+PATH
  2
+  remote: .
  3
+  specs:
  4
+    bitarray (0.0.5)
  5
+
  6
+GEM
  7
+  remote: http://rubygems.org/
  8
+  specs:
  9
+    rake (0.9.2.2)
  10
+    test-unit (2.4.5)
  11
+    yard (0.7.4)
  12
+
  13
+PLATFORMS
  14
+  ruby
  15
+
  16
+DEPENDENCIES
  17
+  bitarray!
  18
+  rake
  19
+  test-unit
  20
+  yard
45  README.md
Source Rendered
@@ -2,32 +2,57 @@
2 2
 
3 3
 Basic, pure Ruby bit field. Pretty fast (for what it is) and memory efficient. Works well for Bloom filters (the reason I wrote it).
4 4
 
5  
-Written in 2007 and not updated since then, just bringing it on to GitHub by user request. It used to be called Bitfield and was hosted at http://snippets.dzone.com/posts/show/4234 .. I will review the code and bring the docs up to date in due course.
  5
+Written in 2007 and not updated since then, just bringing it on to GitHub by user request. It used to be called BitField and was hosted at http://snippets.dzone.com/posts/show/4234 .. I will review the code and bring the docs up to date in due course.
6 6
 
7 7
 ## Installation
8 8
 
9  
-    gem install bitarray
  9
+```ruby
  10
+gem install bitarray
  11
+```
10 12
 
11 13
 ## Examples
12 14
 
13 15
 To use:
14 16
 
15  
-    require 'bitarray'
  17
+```ruby
  18
+require 'bitarray'
  19
+```
16 20
 
17  
-Create a bit field 1000 bits wide:
  21
+Create a bit array 1000 bits wide:
18 22
 
19  
-    ba = BitArray.new(1000)
  23
+```ruby
  24
+ba = BitArray.new(1000)
  25
+```
20 26
 
21 27
 Setting and reading bits:
22 28
 
23  
-    ba[100] = 1
24  
-    ba[100]    .. => 1
25  
-    ba[100] = 0
  29
+```ruby
  30
+ba[100] = 1
  31
+ba[100]
  32
+#=> 1
  33
+
  34
+ba[100] = 0
  35
+ba[100]
  36
+#=> 0
  37
+```
26 38
 
27 39
 More:
28 40
 
29  
-    ba.to_s = "10101000101010101"  (example)
30  
-    ba.total_set         .. => 10  (example - 10 bits are set to "1")
  41
+```ruby
  42
+ba = BitArray.new(20)
  43
+[1,3,5,9,11,13,15].each { |i| ba[i] = 1 }
  44
+ba.to_s
  45
+#=> "01010100010101010000"
  46
+ba.total_set
  47
+#=> 7
  48
+```
  49
+
  50
+## History
  51
+- v5 (added support for flags being on by default, instead of off)
  52
+- v4 (fixed bug where setting 0 bits to 0 caused a set to 1)
  53
+- v3 (supports dynamic bitwidths for array elements.. now doing 32 bit widths default)
  54
+- v2 (now uses 1 << y, rather than 2 ** y .. it's 21.8 times faster!)
  55
+- v1 (first release)
31 56
 
32 57
 ## License
33 58
 
8  bitarray.gemspec
... ...
@@ -1,9 +1,11 @@
1 1
 # -*- encoding: utf-8 -*-
2 2
 $:.push File.expand_path("../lib", __FILE__)
3 3
 
  4
+require 'bitarray'
  5
+
4 6
 Gem::Specification.new do |s|
5 7
   s.name        = "bitarray"
6  
-  s.version     = "0.0.1"
  8
+  s.version     = BitArray::VERSION
7 9
   s.authors     = ["Peter Cooper"]
8 10
   s.email       = ["git@peterc.org"]
9 11
   s.homepage    = "https://github.com/peterc/bitarray"
@@ -16,4 +18,8 @@ Gem::Specification.new do |s|
16 18
   s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
17 19
   s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18 20
   s.require_paths = ["lib"]
  21
+  
  22
+  s.add_development_dependency "rake"
  23
+  s.add_development_dependency "yard"
  24
+  s.add_development_dependency "test-unit"
19 25
 end
19  lib/bitarray.rb
... ...
@@ -1,14 +1,15 @@
1 1
 class BitArray
2 2
   attr_reader :size
3 3
   include Enumerable
4  
-  
  4
+  VERSION = "0.0.5"
5 5
   ELEMENT_WIDTH = 32
6  
-  
7  
-  def initialize(size)
  6
+
  7
+  def initialize(size, default_value = 0)
8 8
     @size = size
9 9
     @field = Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
  10
+    @field.map!{|i| ~i} if (default_value == 1)
10 11
   end
11  
-  
  12
+
12 13
   # Set a bit (1/0)
13 14
   def []=(position, value)
14 15
     if value == 1
@@ -17,22 +18,22 @@ def []=(position, value)
17 18
       @field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
18 19
     end
19 20
   end
20  
-  
  21
+
21 22
   # Read a bit (1/0)
22 23
   def [](position)
23 24
     @field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
24 25
   end
25  
-  
  26
+
26 27
   # Iterate over each bit
27 28
   def each(&block)
28 29
     @size.times { |position| yield self[position] }
29 30
   end
30  
-  
  31
+
31 32
   # Returns the field as a string like "0101010100111100," etc.
32 33
   def to_s
33  
-    inject("") { |a, b| a + b.to_s }
  34
+    @field.collect{|ea| ("%032b" % ea).reverse}.join[0..@size-1]
34 35
   end
35  
-  
  36
+
36 37
   # Returns the total number of bits that are set
37 38
   # (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
38 39
   def total_set
75  test/test_bitarray.rb
@@ -2,61 +2,78 @@
2 2
 require "bitarray"
3 3
 
4 4
 class TestBitArray < Test::Unit::TestCase
  5
+
5 6
   def setup
6  
-    @public_bf = BitArray.new(1000)
  7
+    @public_ba = BitArray.new(1000)
7 8
   end
8  
-  
  9
+
9 10
   def test_basic
10 11
     assert_equal 0, BitArray.new(100)[0]
11 12
     assert_equal 0, BitArray.new(100)[1]
12 13
   end
13  
-  
  14
+
14 15
   def test_setting_and_unsetting
15  
-    @public_bf[100] = 1
16  
-    assert_equal 1, @public_bf[100]
17  
-    @public_bf[100] = 0
18  
-    assert_equal 0, @public_bf[100]
  16
+    @public_ba[100] = 1
  17
+    assert_equal 1, @public_ba[100]
  18
+    @public_ba[100] = 0
  19
+    assert_equal 0, @public_ba[100]
19 20
   end
20 21
 
21 22
   def test_random_setting_and_unsetting
22 23
     100.times do
23 24
       index = rand(1000)
24  
-      @public_bf[index] = 1
25  
-      assert_equal 1, @public_bf[index]
26  
-      @public_bf[index] = 0
27  
-      assert_equal 0, @public_bf[index]
  25
+      @public_ba[index] = 1
  26
+      assert_equal 1, @public_ba[index]
  27
+      @public_ba[index] = 0
  28
+      assert_equal 0, @public_ba[index]
28 29
     end
29 30
   end
30  
-  
  31
+
  32
+  def test_random_side_effects
  33
+    ba2 = BitArray.new(@public_ba.size, 1)
  34
+
  35
+    on = (@public_ba.size / 2).times.collect do
  36
+      index = rand(@public_ba.size)
  37
+      @public_ba[index] = 1
  38
+      ba2[index] = 0
  39
+      index
  40
+    end
  41
+    assert_equal(@public_ba.to_s, @public_ba.to_s_fast)
  42
+
  43
+    @public_ba.size.times do |i|
  44
+      assert_equal(@public_ba[i], on.include?(i) ? 1 : 0)
  45
+      assert_equal(ba2[i], on.include?(i) ? 0 : 1)
  46
+    end
  47
+  end
  48
+
31 49
   def test_multiple_setting
32 50
     1.upto(999) do |pos|
33  
-      2.times { @public_bf[pos] = 1 }
34  
-      assert_equal 1, @public_bf[pos]
  51
+      2.times { @public_ba[pos] = 1 }
  52
+      assert_equal 1, @public_ba[pos]
35 53
     end
36 54
   end
37 55
 
38 56
   def test_multiple_unsetting
39 57
     1.upto(999) do |pos|
40  
-      2.times { @public_bf[pos] = 0 }
41  
-      assert_equal 0, @public_bf[pos]
  58
+      2.times { @public_ba[pos] = 0 }
  59
+      assert_equal 0, @public_ba[pos]
42 60
     end
43 61
   end
44  
-  
  62
+
45 63
   def test_size
46  
-    assert_equal 1000, @public_bf.size
  64
+    assert_equal 1000, @public_ba.size
47 65
   end
48  
-  
  66
+
49 67
   def test_to_s
50  
-    bf = BitArray.new(10)
51  
-    bf[1] = 1
52  
-    bf[5] = 1
53  
-    assert_equal "0100010000", bf.to_s
  68
+    ba = BitArray.new(35)
  69
+    [1, 5, 6, 7, 10, 16, 33].each{|i|ba[i] = 1}
  70
+    assert_equal "01000111001000001000000000000000010", ba.to_s
54 71
   end
55  
-  
  72
+
56 73
   def test_total_set
57  
-    bf = BitArray.new(10)
58  
-    bf[1] = 1
59  
-    bf[5] = 1
60  
-    assert_equal 2, bf.total_set
  74
+    ba = BitArray.new(10)
  75
+    ba[1] = 1
  76
+    ba[5] = 1
  77
+    assert_equal 2, ba.total_set
61 78
   end
62  
-end
  79
+end

0 notes on commit 4674990

Please sign in to comment.
Something went wrong with that request. Please try again.