Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

TLC #1

Merged
merged 12 commits into from

2 participants

Matthew McEachen Peter Cooper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 18, 2012
  1. Matthew McEachen

    First commit

    mceachen authored
  2. Matthew McEachen

    fixed gemspec name

    mceachen authored
  3. Matthew McEachen

    removed README stub

    mceachen authored
  4. Matthew McEachen
  5. Matthew McEachen

    fixed name, added to readme

    mceachen authored
  6. Matthew McEachen

    doc twiddle

    mceachen authored
  7. Matthew McEachen

    hate the .md

    mceachen authored
  8. Matthew McEachen

    hate the .md

    mceachen authored
  9. Matthew McEachen

    hate the .md

    mceachen authored
  10. Matthew McEachen

    rename to cleanup merge

    mceachen authored
  11. Matthew McEachen

    Merge remote-tracking branch 'peterc/master'

    mceachen authored
    Conflicts:
    	.gitignore
    	Gemfile
    	README.md
    	Rakefile
    	bitarray.gemspec
    	lib/bitarray.rb
    	test/test_bitarray.rb
  12. Matthew McEachen
This page is out of date. Refresh to see the latest.
2  Gemfile
View
@@ -1,4 +1,2 @@
source "http://rubygems.org"
-
-# Specify your gem's dependencies in bitarray.gemspec
gemspec
20 Gemfile.lock
View
@@ -0,0 +1,20 @@
+PATH
+ remote: .
+ specs:
+ bitarray (0.0.5)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ rake (0.9.2.2)
+ test-unit (2.4.5)
+ yard (0.7.4)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bitarray!
+ rake
+ test-unit
+ yard
45 README.md
View
@@ -2,32 +2,57 @@
Basic, pure Ruby bit field. Pretty fast (for what it is) and memory efficient. Works well for Bloom filters (the reason I wrote it).
-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.
+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.
## Installation
- gem install bitarray
+```ruby
+gem install bitarray
+```
## Examples
To use:
- require 'bitarray'
+```ruby
+require 'bitarray'
+```
-Create a bit field 1000 bits wide:
+Create a bit array 1000 bits wide:
- ba = BitArray.new(1000)
+```ruby
+ba = BitArray.new(1000)
+```
Setting and reading bits:
- ba[100] = 1
- ba[100] .. => 1
- ba[100] = 0
+```ruby
+ba[100] = 1
+ba[100]
+#=> 1
+
+ba[100] = 0
+ba[100]
+#=> 0
+```
More:
- ba.to_s = "10101000101010101" (example)
- ba.total_set .. => 10 (example - 10 bits are set to "1")
+```ruby
+ba = BitArray.new(20)
+[1,3,5,9,11,13,15].each { |i| ba[i] = 1 }
+ba.to_s
+#=> "01010100010101010000"
+ba.total_set
+#=> 7
+```
+
+## History
+- v5 (added support for flags being on by default, instead of off)
+- v4 (fixed bug where setting 0 bits to 0 caused a set to 1)
+- v3 (supports dynamic bitwidths for array elements.. now doing 32 bit widths default)
+- v2 (now uses 1 << y, rather than 2 ** y .. it's 21.8 times faster!)
+- v1 (first release)
## License
8 bitarray.gemspec
View
@@ -1,9 +1,11 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
+require 'bitarray'
+
Gem::Specification.new do |s|
s.name = "bitarray"
- s.version = "0.0.1"
+ s.version = BitArray::VERSION
s.authors = ["Peter Cooper"]
s.email = ["git@peterc.org"]
s.homepage = "https://github.com/peterc/bitarray"
@@ -16,4 +18,8 @@ Gem::Specification.new do |s|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
+
+ s.add_development_dependency "rake"
+ s.add_development_dependency "yard"
+ s.add_development_dependency "test-unit"
end
19 lib/bitarray.rb
View
@@ -1,14 +1,15 @@
class BitArray
attr_reader :size
include Enumerable
-
+ VERSION = "0.0.5"
ELEMENT_WIDTH = 32
-
- def initialize(size)
+
+ def initialize(size, default_value = 0)
@size = size
@field = Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
+ @field.map!{|i| ~i} if (default_value == 1)
end
-
+
# Set a bit (1/0)
def []=(position, value)
if value == 1
@@ -17,22 +18,22 @@ def []=(position, value)
@field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
end
end
-
+
# Read a bit (1/0)
def [](position)
@field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
end
-
+
# Iterate over each bit
def each(&block)
@size.times { |position| yield self[position] }
end
-
+
# Returns the field as a string like "0101010100111100," etc.
def to_s
- inject("") { |a, b| a + b.to_s }
+ @field.collect{|ea| ("%032b" % ea).reverse}.join[0..@size-1]
end
-
+
# Returns the total number of bits that are set
# (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
def total_set
75 test/test_bitarray.rb
View
@@ -2,61 +2,78 @@
require "bitarray"
class TestBitArray < Test::Unit::TestCase
+
def setup
- @public_bf = BitArray.new(1000)
+ @public_ba = BitArray.new(1000)
end
-
+
def test_basic
assert_equal 0, BitArray.new(100)[0]
assert_equal 0, BitArray.new(100)[1]
end
-
+
def test_setting_and_unsetting
- @public_bf[100] = 1
- assert_equal 1, @public_bf[100]
- @public_bf[100] = 0
- assert_equal 0, @public_bf[100]
+ @public_ba[100] = 1
+ assert_equal 1, @public_ba[100]
+ @public_ba[100] = 0
+ assert_equal 0, @public_ba[100]
end
def test_random_setting_and_unsetting
100.times do
index = rand(1000)
- @public_bf[index] = 1
- assert_equal 1, @public_bf[index]
- @public_bf[index] = 0
- assert_equal 0, @public_bf[index]
+ @public_ba[index] = 1
+ assert_equal 1, @public_ba[index]
+ @public_ba[index] = 0
+ assert_equal 0, @public_ba[index]
end
end
-
+
+ def test_random_side_effects
+ ba2 = BitArray.new(@public_ba.size, 1)
+
+ on = (@public_ba.size / 2).times.collect do
+ index = rand(@public_ba.size)
+ @public_ba[index] = 1
+ ba2[index] = 0
+ index
+ end
+ assert_equal(@public_ba.to_s, @public_ba.to_s_fast)
+
+ @public_ba.size.times do |i|
+ assert_equal(@public_ba[i], on.include?(i) ? 1 : 0)
+ assert_equal(ba2[i], on.include?(i) ? 0 : 1)
+ end
+ end
+
def test_multiple_setting
1.upto(999) do |pos|
- 2.times { @public_bf[pos] = 1 }
- assert_equal 1, @public_bf[pos]
+ 2.times { @public_ba[pos] = 1 }
+ assert_equal 1, @public_ba[pos]
end
end
def test_multiple_unsetting
1.upto(999) do |pos|
- 2.times { @public_bf[pos] = 0 }
- assert_equal 0, @public_bf[pos]
+ 2.times { @public_ba[pos] = 0 }
+ assert_equal 0, @public_ba[pos]
end
end
-
+
def test_size
- assert_equal 1000, @public_bf.size
+ assert_equal 1000, @public_ba.size
end
-
+
def test_to_s
- bf = BitArray.new(10)
- bf[1] = 1
- bf[5] = 1
- assert_equal "0100010000", bf.to_s
+ ba = BitArray.new(35)
+ [1, 5, 6, 7, 10, 16, 33].each{|i|ba[i] = 1}
+ assert_equal "01000111001000001000000000000000010", ba.to_s
end
-
+
def test_total_set
- bf = BitArray.new(10)
- bf[1] = 1
- bf[5] = 1
- assert_equal 2, bf.total_set
+ ba = BitArray.new(10)
+ ba[1] = 1
+ ba[5] = 1
+ assert_equal 2, ba.total_set
end
-end
+end
Something went wrong with that request. Please try again.