bits_count 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTJkNThmMzFlZDAwZGY4MTBhYWQwMDMzM2I3MGYyN2JjNTQwNGU2Yg==
5
+ data.tar.gz: !binary |-
6
+ ODRmNmUzNTFiODYwZjJlNzA0NmNiZmIxOGIzOTVmYTlkZGEzNzM1YQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDUxYmJjNzQ4ODEyNzY1ZDI2NWNmOWVlYmJiNDJiMDE0NDI1ZDM3ZDg4NjQz
10
+ NmZiMjQ4ZjFhZWVkZWNlMDkzZDI0MGM4ZTIyMzYxZmIwN2ExMDg0NjIzNDU0
11
+ MmFjYzViM2ExMTJmOTY5MWZjNTk2MjE4NzM2NzAxN2ZkYzI5YTI=
12
+ data.tar.gz: !binary |-
13
+ NDFlZTllZDVmODc1Y2EwNDk4ZDg5ZjdmNGY2NDYyNjA3ZjY5NTY2ZjRmOGM1
14
+ ZDM3ZDFmYmEzYzQzYzIxNDEzYmE0ZjZjYTdmMDliZGU3ODI4ZjIzMTNkYWEz
15
+ NzBiM2M5ZGEyNTNiYjA2NTM2OWY2ZTYyMGUyODg2NTE1MmJlZDU=
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bits_count.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Max Shytikov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # BitsCount
2
+
3
+ Implementations of population count (Hamming weight in binary case)
4
+ using pure ruby.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'bits_count'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install bits_count
19
+
20
+ ## Usage
21
+
22
+ Example: Calculate bits count in file
23
+
24
+ (in IRB)
25
+ ```
26
+ require 'bits_count/irb_helper'
27
+
28
+ count_bits "path/to/some/file.jpg"
29
+ ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/bits_count/test*.rb']
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bits_count/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bits_count"
8
+ spec.version = BitsCount::VERSION
9
+ spec.authors = ["Max Shytikov"]
10
+ spec.email = ["mshytikov@gmail.com"]
11
+ spec.description = "Implementation of population count in pure ruby"
12
+ spec.summary = "Bit counter"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,32 @@
1
+ module BitsCount
2
+ module File
3
+
4
+ class << self
5
+
6
+ def population_count(path, alg = :str)
7
+ ::File.open(path, "rb") do |f|
8
+ case alg
9
+ when :int32
10
+ IO.population_count_int32(f)
11
+ when :str
12
+ IO.population_count_str(f)
13
+ when :map
14
+ IO.population_count_map(f)
15
+ else
16
+ raise NotImplementedError, "#{alg} algorithm is not implemented"
17
+ end
18
+ end
19
+ end
20
+
21
+ def bits_count(path)
22
+ f_size = ::File.size(path)
23
+ bit1_count = population_count(path)
24
+ {
25
+ bit0_count: f_size*8 - bit1_count,
26
+ bit1_count: bit1_count
27
+ }
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ module BitsCount
2
+ module IO
3
+
4
+ BUFFER_SIZE = 256
5
+ UNPACK_PATTERN = "N*"
6
+ BIN_STR_END = [0].pack("N")
7
+
8
+ class << self
9
+
10
+ def population_count_int32(io)
11
+ count = 0
12
+ each_int32(io) {|int| count += Primitive.population_count_int32(int) }
13
+ count
14
+ end
15
+
16
+ def population_count_map(io)
17
+ count = 0
18
+ each_int32(io) {|int| count += Primitive.population_count_map(int) }
19
+ count
20
+ end
21
+
22
+ def population_count_str(io)
23
+ count = 0
24
+ while binstr = io.read(BUFFER_SIZE)
25
+ count += Primitive.population_count_str(binstr)
26
+ end
27
+ count
28
+ end
29
+
30
+ private
31
+ def each_int32(io, &block)
32
+ while binstr = io.read(BUFFER_SIZE)
33
+ binstr << BIN_STR_END if binstr.bytesize < BUFFER_SIZE
34
+ binstr.unpack(UNPACK_PATTERN).each(&block)
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ require 'bits_count'
2
+
3
+ def count_bits path
4
+ stats = BitsCount::File.bits_count(path)
5
+ puts "found %d bits set to 1"%[stats[:bit1_count]]
6
+ puts "found %d bits set to 0"%[stats[:bit0_count]]
7
+ end
@@ -0,0 +1,32 @@
1
+ module BitsCount
2
+ module Primitive
3
+
4
+ UNPACK_PATTERN = "B*"
5
+
6
+ class << self
7
+
8
+ def population_count_int32(i)
9
+ i = i - ((i >> 1) & 0x55555555)
10
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
11
+ i = (i + (i >> 4)) & 0x0F0F0F0F
12
+ i = i + (i >> 8)
13
+ i = i + (i >> 16)
14
+ i & 0x0000003F
15
+ end
16
+
17
+
18
+ def population_count_str(s)
19
+ s.unpack(UNPACK_PATTERN).first.count(?1)
20
+ end
21
+
22
+ def population_count_map(i)
23
+ WORDBITS[i&0xFFFF] + WORDBITS[i>>16]
24
+ end
25
+
26
+ end
27
+
28
+ WORDBITS = Hash[0.upto(2**16-1).map{|i| [i, population_count_int32(i)] }].freeze
29
+
30
+ end
31
+ end
32
+
@@ -0,0 +1,3 @@
1
+ module BitsCount
2
+ VERSION = "0.0.1"
3
+ end
data/lib/bits_count.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "bits_count/version"
2
+ require 'bits_count/primitive'
3
+ require 'bits_count/io'
4
+ require 'bits_count/file'
5
+
6
+ module BitsCount
7
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class TestBitsCountFile < Test::Unit::TestCase
4
+ include Fixtures
5
+
6
+ Fixtures.all.each do |path, bit0_count, bit1_count|
7
+ file_name = File.basename(path)
8
+
9
+ define_method "test_population_count_with_file_#{file_name}" do
10
+ assert_equal(bit1_count, BitsCount::File.population_count(path, :int32), "alg :int32")
11
+ assert_equal(bit1_count, BitsCount::File.population_count(path, :str), "alg :srt")
12
+ assert_equal(bit1_count, BitsCount::File.population_count(path, :map), "alg :srt")
13
+ end
14
+
15
+ define_method "test_bits_count_#{file_name}" do
16
+ expected = { bit0_count: bit0_count, bit1_count: bit1_count }
17
+ assert_equal(expected, BitsCount::File.bits_count(path))
18
+ end
19
+ end
20
+
21
+ def test_population_count_with_unknown_algorithm
22
+ assert_raise NotImplementedError do
23
+ BitsCount::File.population_count(Fixtures.large_bin, :fast)
24
+ end
25
+ end
26
+
27
+ def test_benchmark
28
+ path = Fixtures.large_bin
29
+ Benchmark.bmbm do |x|
30
+ [:int32, :map, :str].each do |alg|
31
+ x.report("File.population_count alg: #{alg}") { BitsCount::File.population_count(path, alg) }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+ require 'stringio'
3
+
4
+ class TestBitsCountIO < Test::Unit::TestCase
5
+ TEST_BIT_STRINGS = {
6
+ "1" => 1,
7
+ "01" => 1,
8
+ "010" => 1,
9
+ "011" => 2,
10
+ "01"*32 => 32,
11
+ "1"*64 => 64,
12
+ "0"<< "1"*63 => 63,
13
+ "01"*64 => 64,
14
+ "0"*512<< "1" => 1
15
+ }
16
+
17
+ TEST_METHODS = BitsCount::IO.methods.grep(/population_count/)
18
+
19
+ TEST_METHODS.each do |method|
20
+ define_method "test_#{method}" do
21
+ TEST_BIT_STRINGS.each do |binstr, expected_count|
22
+ StringIO.open([binstr].pack("b*"), "rb") do |io|
23
+ assert_equal(expected_count, BitsCount::IO.send(method, io), "Bin sring: #{binstr}")
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def test_benchmark
30
+ io = StringIO.new(File.binread(Fixtures.large_bin), 'rb')
31
+ Benchmark.bmbm do |x|
32
+ TEST_METHODS.each do |method|
33
+ x.report("IO.#{method}"){ io.rewind; BitsCount::IO.send(method, io) }
34
+ end
35
+ end
36
+ io.close
37
+ end
38
+ end
39
+
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class TestBitsCountPrimitive < Test::Unit::TestCase
4
+
5
+ def test_population_count_int32
6
+ assert_equal(0, BitsCount::Primitive.population_count_int32(0))
7
+ assert_equal(1, BitsCount::Primitive.population_count_int32(1))
8
+ assert_equal(2, BitsCount::Primitive.population_count_int32(3))
9
+ assert_equal(32, BitsCount::Primitive.population_count_int32(2**32-1))
10
+ end
11
+
12
+ def test_population_count_map
13
+ assert_equal(0, BitsCount::Primitive.population_count_map(0))
14
+ assert_equal(1, BitsCount::Primitive.population_count_map(1))
15
+ assert_equal(2, BitsCount::Primitive.population_count_map(3))
16
+ assert_equal(32, BitsCount::Primitive.population_count_map(2**32-1))
17
+ end
18
+
19
+ def test_population_count_str
20
+ assert_equal(1, BitsCount::Primitive.population_count_str([1].pack("L")))
21
+ assert_equal(32, BitsCount::Primitive.population_count_str([2**32-1].pack("L")))
22
+ assert_equal(64, BitsCount::Primitive.population_count_str([2**64-1].pack("Q")))
23
+ end
24
+
25
+
26
+ def test_benchmark
27
+ n = 10000
28
+ int = 0x55555555
29
+ bstr = [int].pack("N")
30
+ Benchmark.bmbm do |x|
31
+ x.report("Primitive.population_count_map") { n.times{ BitsCount::Primitive.population_count_map(int) } }
32
+ x.report("Primitive.population_count_int32") { n.times{ BitsCount::Primitive.population_count_int32(int) } }
33
+ x.report("Primitive.population_count_str") { n.times{ BitsCount::Primitive.population_count_str(bstr) } }
34
+ end
35
+ end
36
+
37
+ end
File without changes
@@ -0,0 +1 @@
1
+ Y�9%�
@@ -0,0 +1 @@
1
+ @
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
@@ -0,0 +1,35 @@
1
+ require 'test/unit'
2
+ require 'bits_count'
3
+ require 'benchmark'
4
+
5
+ module Fixtures
6
+ ROOT = File.expand_path('fixtures', File.dirname(__FILE__))
7
+
8
+ def fixture_path(name)
9
+ File.expand_path(name.to_s, ROOT)
10
+ end
11
+
12
+ class << self
13
+
14
+ def all
15
+ Dir.glob(File.expand_path("*.bin", ROOT)).map do |path|
16
+ file_name = File.basename(path, '.bin')
17
+ bit0_count = file_name[/bit0-(\d+)/, 1].to_i
18
+ bit1_count = file_name[/bit1-(\d+)/, 1].to_i
19
+ [path, bit0_count, bit1_count]
20
+ end
21
+ end
22
+
23
+
24
+ def large_bin
25
+ path = File.expand_path("tmp/large.bin", ROOT)
26
+ if !File.exists?(path)
27
+ File.open(path, "wb") do |f|
28
+ 1024.times { f.write(([0x55555555] * 256).pack("N*")) }
29
+ end
30
+ end
31
+ path
32
+ end
33
+
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bits_count
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Max Shytikov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
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: Implementation of population count in pure ruby
42
+ email:
43
+ - mshytikov@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - bits_count.gemspec
54
+ - lib/bits_count.rb
55
+ - lib/bits_count/file.rb
56
+ - lib/bits_count/io.rb
57
+ - lib/bits_count/irb_helper.rb
58
+ - lib/bits_count/primitive.rb
59
+ - lib/bits_count/version.rb
60
+ - test/bits_count/test_file.rb
61
+ - test/bits_count/test_io.rb
62
+ - test/bits_count/test_primitive.rb
63
+ - test/fixtures/bit0-0_bit1-0.bin
64
+ - test/fixtures/bit0-25_bit1-15.bin
65
+ - test/fixtures/bit0-7_bit1-1.bin
66
+ - test/fixtures/tmp/.gitignore
67
+ - test/test_helper.rb
68
+ homepage: ''
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.0.3
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Bit counter
92
+ test_files:
93
+ - test/bits_count/test_file.rb
94
+ - test/bits_count/test_io.rb
95
+ - test/bits_count/test_primitive.rb
96
+ - test/fixtures/bit0-0_bit1-0.bin
97
+ - test/fixtures/bit0-25_bit1-15.bin
98
+ - test/fixtures/bit0-7_bit1-1.bin
99
+ - test/fixtures/tmp/.gitignore
100
+ - test/test_helper.rb