bitarray 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c79a60a3580af853940651ca520abd24f359fc97
4
+ data.tar.gz: 96cb2ffe5551ac793e33f3eb06563aadcc6cfd1d
5
+ SHA512:
6
+ metadata.gz: bcd93a192a22cf477b45cd582028a3cd60c090dd9cdfbfd5b507a86f4c996a1dede387926d34f0495441cb90b0d899c96d5bb9a34dc8b16b5e933794f0e89bf1
7
+ data.tar.gz: cb2b120ce2abe9242bfc07ac9f1dff0bff7aab271daabaaafca53f39a06be8ce690946575bc6c423e8258fbf99c284ab783301327c0495bb37477798a0def376
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in bitarray.gemspec
1
+ source "https://rubygems.org"
4
2
  gemspec
data/README.md CHANGED
@@ -1,23 +1,65 @@
1
- # BitArray: A simple bit array/bit field library in pure Ruby
1
+ # BitArray: A simple bit-array/bitfield library in pure Ruby
2
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).
3
+ Basic, pure Ruby bit field. Works well for Bloom filters (the use case for which I originally 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
5
+ Originally written in 2007 and left without significant update until 2017, it has now been updated to work within a typical, modern Ruby environment while maintaining the same API.
6
+
7
+ ## Installation
8
+
9
+ ```ruby
10
+ gem install bitarray
11
+ ```
6
12
 
7
13
  ## Examples
8
14
 
9
- Create a bit field 1000 bits wide
10
- bf = BitField.new(1000)
15
+ To use:
16
+
17
+ ```ruby
18
+ require 'bitarray'
19
+ ```
20
+
21
+ Create a bit array 1000 bits wide:
22
+
23
+ ```ruby
24
+ ba = BitArray.new(1000)
25
+ ```
26
+
27
+ Setting and reading bits:
28
+
29
+ ```ruby
30
+ ba[100] = 1
31
+ ba[100]
32
+ #=> 1
33
+
34
+ ba[100] = 0
35
+ ba[100]
36
+ #=> 0
37
+ ```
38
+
39
+ More:
40
+
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
+ - 1.0 in 2017 (updated for modern Ruby, more efficient storage, and 10th birthday)
52
+ - 0.0.1 in 2012 (original v5 released on GitHub)
53
+ - v5 (added support for flags being on by default, instead of off)
54
+ - v4 (fixed bug where setting 0 bits to 0 caused a set to 1)
55
+ - v3 (supports dynamic bitwidths for array elements.. now doing 32 bit widths default)
56
+ - v2 (now uses 1 << y, rather than 2 ** y .. it's 21.8 times faster!)
57
+ - v1 (first release)
11
58
 
12
- Setting and reading bits
13
- bf[100] = 1
14
- bf[100] .. => 1
15
- bf[100] = 0
59
+ ## Thanks
16
60
 
17
- More
18
- bf.to_s = "10101000101010101" (example)
19
- bf.total_set .. => 10 (example - 10 bits are set to "1")
61
+ Thanks to Michael Slade for encouraging me to update this library on its 10th birthday and for suggesting finally using String's getbyte and setbyte methods now that we're all on 1.9+ compatible implementations.
20
62
 
21
63
  ## License
22
64
 
23
- MIT licensed. Copyright 2007-2012 Peter Cooper, yada yada.
65
+ MIT licensed. Copyright 2007-2017 Peter Cooper.
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
 
4
- Rake::TestTask.new # defaults are fine for now
5
- task :default => :test
4
+ Rake::TestTask.new
5
+ task :default => :test
@@ -1,19 +1,22 @@
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"
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"
12
+ s.summary = %q{A simple, pure Ruby bit-array / bitfield implementation.}
13
+ s.description = %q{A simple, pure Ruby bit-array / bitfield implementation.}
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rake"
21
+ s.add_development_dependency "minitest"
19
22
  end
@@ -0,0 +1,43 @@
1
+ class BitArray
2
+ attr_reader :size
3
+ attr_reader :field
4
+ include Enumerable
5
+
6
+ VERSION = "1.0.0"
7
+ ELEMENT_WIDTH = 32
8
+
9
+ def initialize(size, field = nil)
10
+ @size = size
11
+ @field = field || Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
12
+ end
13
+
14
+ # Set a bit (1/0)
15
+ def []=(position, value)
16
+ if value == 1
17
+ @field[position / ELEMENT_WIDTH] |= 1 << (position % ELEMENT_WIDTH)
18
+ elsif (@field[position / ELEMENT_WIDTH]) & (1 << (position % ELEMENT_WIDTH)) != 0
19
+ @field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
20
+ end
21
+ end
22
+
23
+ # Read a bit (1/0)
24
+ def [](position)
25
+ @field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
26
+ end
27
+
28
+ # Iterate over each bit
29
+ def each(&block)
30
+ @size.times { |position| yield self[position] }
31
+ end
32
+
33
+ # Returns the field as a string like "0101010100111100," etc.
34
+ def to_s
35
+ @field.collect{|ea| ("%0#{ELEMENT_WIDTH}b" % ea).reverse}.join[0..@size-1]
36
+ end
37
+
38
+ # Returns the total number of bits that are set
39
+ # (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
40
+ def total_set
41
+ @field.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
42
+ end
43
+ end
@@ -1,41 +1,42 @@
1
1
  class BitArray
2
2
  attr_reader :size
3
+ attr_reader :field
3
4
  include Enumerable
4
-
5
- ELEMENT_WIDTH = 32
6
-
7
- def initialize(size)
5
+
6
+ VERSION = "1.0.0"
7
+
8
+ def initialize(size, field = nil)
8
9
  @size = size
9
- @field = Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
10
+ @field = "\0" * (size / 8 + 1)
10
11
  end
11
-
12
+
12
13
  # Set a bit (1/0)
13
14
  def []=(position, value)
14
15
  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)
16
+ @field.setbyte(position >> 3, @field.getbyte(position >> 3) | (1 << (position % 8)))
17
+ else
18
+ @field.setbyte(position >> 3, @field.getbyte(position >> 3) ^ (1 << (position % 8)))
18
19
  end
19
20
  end
20
-
21
+
21
22
  # Read a bit (1/0)
22
23
  def [](position)
23
- @field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
24
+ (@field.getbyte(position >> 3) & (1 << (position % 8))) > 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.bytes.collect{|ea| ("%08b" % ea).reverse}.join[0, @size]
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
39
- @field.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
40
+ @field.bytes.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
40
41
  end
41
- end
42
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'lib/bitarray'
2
+ require 'memory_profiler'
3
+
4
+ report = MemoryProfiler.report do
5
+ ba = BitArray.new(1000000)
6
+
7
+ 1000000.times do |i|
8
+ ba[rand(100000)] = 1
9
+ ba[rand(100000)] = 0
10
+ end
11
+ end
12
+
13
+ report.pretty_print
@@ -1,62 +1,62 @@
1
- require "test/unit"
1
+ require "minitest/autorun"
2
2
  require "bitarray"
3
3
 
4
- class TestBitArray < Test::Unit::TestCase
4
+ class TestBitArray < Minitest::Test
5
5
  def setup
6
- @public_bf = BitArray.new(1000)
6
+ @public_ba = BitArray.new(1000)
7
7
  end
8
-
8
+
9
9
  def test_basic
10
10
  assert_equal 0, BitArray.new(100)[0]
11
- assert_equal 0, BitArray.new(100)[1]
11
+ assert_equal 0, BitArray.new(100)[99]
12
12
  end
13
-
13
+
14
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]
15
+ @public_ba[100] = 1
16
+ assert_equal 1, @public_ba[100]
17
+ @public_ba[100] = 0
18
+ assert_equal 0, @public_ba[100]
19
19
  end
20
20
 
21
21
  def test_random_setting_and_unsetting
22
22
  100.times do
23
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]
24
+ @public_ba[index] = 1
25
+ assert_equal 1, @public_ba[index]
26
+ @public_ba[index] = 0
27
+ assert_equal 0, @public_ba[index]
28
28
  end
29
29
  end
30
-
30
+
31
31
  def test_multiple_setting
32
32
  1.upto(999) do |pos|
33
- 2.times { @public_bf[pos] = 1 }
34
- assert_equal 1, @public_bf[pos]
33
+ 2.times { @public_ba[pos] = 1 }
34
+ assert_equal 1, @public_ba[pos]
35
35
  end
36
36
  end
37
37
 
38
38
  def test_multiple_unsetting
39
39
  1.upto(999) do |pos|
40
- 2.times { @public_bf[pos] = 0 }
41
- assert_equal 0, @public_bf[pos]
40
+ 2.times { @public_ba[pos] = 0 }
41
+ assert_equal 0, @public_ba[pos]
42
42
  end
43
43
  end
44
-
44
+
45
45
  def test_size
46
- assert_equal 1000, @public_bf.size
46
+ assert_equal 1000, @public_ba.size
47
47
  end
48
-
48
+
49
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
50
+ ba = BitArray.new(35)
51
+ [1, 5, 6, 7, 10, 16, 33].each{|i|ba[i] = 1}
52
+ assert_equal "01000111001000001000000000000000010", ba.to_s
54
53
  end
55
-
54
+
56
55
  def test_total_set
57
- bf = BitArray.new(10)
58
- bf[1] = 1
59
- bf[5] = 1
60
- assert_equal 2, bf.total_set
56
+ ba = BitArray.new(10)
57
+ ba[1] = 1
58
+ ba[5] = 1
59
+ ba[9] = 1
60
+ assert_equal 3, ba.total_set
61
61
  end
62
- end
62
+ end
metadata CHANGED
@@ -1,54 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitarray
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Peter Cooper
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-01-18 00:00:00.000000000 Z
13
- dependencies: []
14
- description: A simple, pure Ruby bit array implementation.
11
+ date: 2017-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A simple, pure Ruby bit-array / bitfield implementation.
15
42
  email:
16
43
  - git@peterc.org
17
44
  executables: []
18
45
  extensions: []
19
46
  extra_rdoc_files: []
20
47
  files:
21
- - .gitignore
48
+ - ".gitignore"
22
49
  - Gemfile
50
+ - Gemfile.lock
23
51
  - README.md
24
52
  - Rakefile
25
53
  - bitarray.gemspec
54
+ - lib/bitarray-array.rb
26
55
  - lib/bitarray.rb
56
+ - memory-test.rb
27
57
  - test/test_bitarray.rb
28
58
  homepage: https://github.com/peterc/bitarray
29
59
  licenses: []
60
+ metadata: {}
30
61
  post_install_message:
31
62
  rdoc_options: []
32
63
  require_paths:
33
64
  - lib
34
65
  required_ruby_version: !ruby/object:Gem::Requirement
35
- none: false
36
66
  requirements:
37
- - - ! '>='
67
+ - - ">="
38
68
  - !ruby/object:Gem::Version
39
69
  version: '0'
40
70
  required_rubygems_version: !ruby/object:Gem::Requirement
41
- none: false
42
71
  requirements:
43
- - - ! '>='
72
+ - - ">="
44
73
  - !ruby/object:Gem::Version
45
74
  version: '0'
46
75
  requirements: []
47
- rubyforge_project: bitarray
48
- rubygems_version: 1.8.10
76
+ rubyforge_project:
77
+ rubygems_version: 2.6.8
49
78
  signing_key:
50
- specification_version: 3
51
- summary: A simple, pure Ruby bit array implementation.
79
+ specification_version: 4
80
+ summary: A simple, pure Ruby bit-array / bitfield implementation.
52
81
  test_files:
53
82
  - test/test_bitarray.rb
54
- has_rdoc: