File tree 7 files changed +158
-0
lines changed
7 files changed +158
-0
lines changed Original file line number Diff line number Diff line change
1
+ * .gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg /*
Original file line number Diff line number Diff line change
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bitarray.gemspec
4
+ gemspec
Original file line number Diff line number Diff line change
1
+ # BitArray: A simple bit array/bit field library in pure Ruby
2
+
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
+
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
6
+
7
+ ## Examples
8
+
9
+ Create a bit field 1000 bits wide
10
+ bf = BitField.new(1000)
11
+
12
+ Setting and reading bits
13
+ bf[ 100] = 1
14
+ bf[ 100] .. => 1
15
+ bf[ 100] = 0
16
+
17
+ More
18
+ bf.to_s = "10101000101010101" (example)
19
+ bf.total_set .. => 10 (example - 10 bits are set to "1")
20
+
21
+ ## License
22
+
23
+ MIT licensed. Copyright 2007-2012 Peter Cooper, yada yada.
Original file line number Diff line number Diff line change
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake ::TestTask . new # defaults are fine for now
5
+ task :default => :test
Original file line number Diff line number Diff line change
1
+ # -*- encoding: utf-8 -*-
2
+ $:. push File . expand_path ( "../lib" , __FILE__ )
3
+
4
+ Gem ::Specification . new do |s |
5
+ s . name = "bitarray"
6
+ s . version = "0.0.1"
7
+ s . authors = [ "Peter Cooper" ]
8
+
9
+ s . homepage = "https://github.com/peterc/bitarray"
10
+ s . summary = %q{A simple, pure Ruby bit array implementation.}
11
+ s . description = %q{A simple, pure Ruby bit array implementation.}
12
+
13
+ s . rubyforge_project = "bitarray"
14
+
15
+ s . files = `git ls-files` . split ( "\n " )
16
+ s . test_files = `git ls-files -- {test,spec,features}/*` . split ( "\n " )
17
+ s . executables = `git ls-files -- bin/*` . split ( "\n " ) . map { |f | File . basename ( f ) }
18
+ s . require_paths = [ "lib" ]
19
+ end
Original file line number Diff line number Diff line change
1
+ class BitArray
2
+ attr_reader :size
3
+ include Enumerable
4
+
5
+ ELEMENT_WIDTH = 32
6
+
7
+ def initialize ( size )
8
+ @size = size
9
+ @field = Array . new ( ( ( size - 1 ) / ELEMENT_WIDTH ) + 1 , 0 )
10
+ end
11
+
12
+ # Set a bit (1/0)
13
+ def []=( position , value )
14
+ if value == 1
15
+ @field [ position / ELEMENT_WIDTH ] |= 1 << ( position % ELEMENT_WIDTH )
16
+ elsif ( @field [ position / ELEMENT_WIDTH ] ) & ( 1 << ( position % ELEMENT_WIDTH ) ) != 0
17
+ @field [ position / ELEMENT_WIDTH ] ^= 1 << ( position % ELEMENT_WIDTH )
18
+ end
19
+ end
20
+
21
+ # Read a bit (1/0)
22
+ def []( position )
23
+ @field [ position / ELEMENT_WIDTH ] & 1 << ( position % ELEMENT_WIDTH ) > 0 ? 1 : 0
24
+ end
25
+
26
+ # Iterate over each bit
27
+ def each ( &block )
28
+ @size . times { |position | yield self [ position ] }
29
+ end
30
+
31
+ # Returns the field as a string like "0101010100111100," etc.
32
+ def to_s
33
+ inject ( "" ) { |a , b | a + b . to_s }
34
+ end
35
+
36
+ # Returns the total number of bits that are set
37
+ # (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
38
+ def total_set
39
+ @field . inject ( 0 ) { |a , byte | a += byte & 1 and byte >>= 1 until byte == 0 ; a }
40
+ end
41
+ end
Original file line number Diff line number Diff line change
1
+ require "test/unit"
2
+ require "bitarray"
3
+
4
+ class TestBitArray < Test ::Unit ::TestCase
5
+ def setup
6
+ @public_bf = BitArray . new ( 1000 )
7
+ end
8
+
9
+ def test_basic
10
+ assert_equal 0 , BitArray . new ( 100 ) [ 0 ]
11
+ assert_equal 0 , BitArray . new ( 100 ) [ 1 ]
12
+ end
13
+
14
+ 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 ]
19
+ end
20
+
21
+ def test_random_setting_and_unsetting
22
+ 100 . times do
23
+ 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 ]
28
+ end
29
+ end
30
+
31
+ def test_multiple_setting
32
+ 1 . upto ( 999 ) do |pos |
33
+ 2 . times { @public_bf [ pos ] = 1 }
34
+ assert_equal 1 , @public_bf [ pos ]
35
+ end
36
+ end
37
+
38
+ def test_multiple_unsetting
39
+ 1 . upto ( 999 ) do |pos |
40
+ 2 . times { @public_bf [ pos ] = 0 }
41
+ assert_equal 0 , @public_bf [ pos ]
42
+ end
43
+ end
44
+
45
+ def test_size
46
+ assert_equal 1000 , @public_bf . size
47
+ end
48
+
49
+ def test_to_s
50
+ bf = BitArray . new ( 10 )
51
+ bf [ 1 ] = 1
52
+ bf [ 5 ] = 1
53
+ assert_equal "0100010000" , bf . to_s
54
+ end
55
+
56
+ def test_total_set
57
+ bf = BitArray . new ( 10 )
58
+ bf [ 1 ] = 1
59
+ bf [ 5 ] = 1
60
+ assert_equal 2 , bf . total_set
61
+ end
62
+ end
You can’t perform that action at this time.
0 commit comments