bits_count 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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