File tree Expand file tree Collapse file tree 7 files changed +158
-0
lines changed Expand file tree Collapse file tree 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+ s . email = [ "git@peterc.org" ]
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