bitcount 0.1.0
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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.travis.yml +32 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +27 -0
- data/benchmark/bitcount.yml +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bitcount.gemspec +29 -0
- data/ext/bitcount_ext/include/bitcount_ext.h +28 -0
- data/ext/bitcount_ext/src/bitcount_ext.c +46 -0
- data/ext/bitcount_ext/src/helpers.c +114 -0
- data/ext/depend +1 -0
- data/ext/extconf.rb +34 -0
- data/lib/bitcount.rb +45 -0
- data/lib/bitcount/integer.rb +17 -0
- data/lib/bitcount/native.rb +68 -0
- data/lib/bitcount/pure.rb +43 -0
- data/lib/bitcount/version.rb +3 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 00044fb7d9178864fb0805b0ca619c0e52aca752f2300114cc31b49535bb8c50
|
4
|
+
data.tar.gz: 6edadce559de31f3620cb84c15129462fb4e7657d48dd7350a4ec822467ead89
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 71ffad74ea1e03ced6f59c74086f2682c6f034f339bfcc1f12f27c308f46e6485902221902255a75a07c230cdc485ddc1bc4101ac201cdfe7a727e44c2a8087f
|
7
|
+
data.tar.gz: f351d06612197586fdd763ef2a843d581176342e8091025f5107a31f4e4fae42c1cf39e677843f806e9900785dceda7f15cf6ddaabff0925658a758ab0007e80
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
|
5
|
+
script: bundle exec rake test
|
6
|
+
|
7
|
+
rvm:
|
8
|
+
- 2.3
|
9
|
+
- 2.7
|
10
|
+
- jruby-9.2.9.0
|
11
|
+
- truffleruby
|
12
|
+
- ruby-head
|
13
|
+
- jruby-head
|
14
|
+
|
15
|
+
matrix:
|
16
|
+
include:
|
17
|
+
- name: benchmark-ruby
|
18
|
+
rvm: 2.7
|
19
|
+
script:
|
20
|
+
- bundle exec rake compile:bitcount_ext
|
21
|
+
- bundle exec ruby -S benchmark-driver benchmark/bitcount.yml
|
22
|
+
- name: benchmark-jruby
|
23
|
+
rvm: jruby-head
|
24
|
+
script:
|
25
|
+
- bundle exec rake compile:bitcount_ext
|
26
|
+
- bundle exec ruby -S benchmark-driver benchmark/bitcount.yml
|
27
|
+
allow_failures:
|
28
|
+
- rvm: ruby-head
|
29
|
+
- rvm: jruby-head
|
30
|
+
- rvm: truffleruby
|
31
|
+
- name: benchmark-ruby
|
32
|
+
- name: benchmark-jruby
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
|
4
|
+
|
5
|
+
## [0.1.1] - Unreleased
|
6
|
+
|
7
|
+
## [0.1.0] - 2020-02-09
|
8
|
+
### Added
|
9
|
+
- init
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 Pavel Rosický
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Bitcount
|
2
|
+
|
3
|
+
__builtin_popcount - Returns the number of 1 bits
|
4
|
+
```ruby
|
5
|
+
1 => 00000000000000000000000000000001 => 1
|
6
|
+
2147483648 => 10000000000000000000000000000000 => 1
|
7
|
+
2147500033 => 10000000000000000100000000000001 => 3
|
8
|
+
```
|
9
|
+
|
10
|
+
__builtin_clz - Returns leading zeros
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
1 => 00000000000000000000000000000001 => 31
|
14
|
+
2147483648 => 10000000000000000000000000000000 => 0
|
15
|
+
2147500033 => 10000000000000000100000000000001 => 0
|
16
|
+
```
|
17
|
+
|
18
|
+
__builtin_ctz - Returns trailing zeros
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
1 => 00000000000000000000000000000001 => 0
|
22
|
+
2147483648 => 10000000000000000000000000000000 => 31
|
23
|
+
2147500033 => 10000000000000000100000000000001 => 0
|
24
|
+
```
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'bitcount'
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle install
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install bitcount
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
```ruby
|
44
|
+
require 'bitcount'
|
45
|
+
Bitcount.popcount(1)
|
46
|
+
=> 1
|
47
|
+
|
48
|
+
Bitcount.nlz(1)
|
49
|
+
=> 63
|
50
|
+
|
51
|
+
Bitcount.ntz(1)
|
52
|
+
=> 0
|
53
|
+
```
|
54
|
+
|
55
|
+
or
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'bitcount/integer'
|
59
|
+
1.popcount
|
60
|
+
=> 1
|
61
|
+
|
62
|
+
1.nlz
|
63
|
+
=> 63
|
64
|
+
|
65
|
+
1.ntz
|
66
|
+
=> 0
|
67
|
+
```
|
68
|
+
|
69
|
+
you can specify a different layout, but if the layout doesn't match your platform a slower version will be used
|
70
|
+
```ruby
|
71
|
+
1.nlz(32)
|
72
|
+
=> 31
|
73
|
+
|
74
|
+
Bitcount::Native.layout_size
|
75
|
+
=> 64
|
76
|
+
```
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ahorek/bitcount.
|
81
|
+
|
82
|
+
|
83
|
+
## License
|
84
|
+
|
85
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
require 'rake/extensiontask'
|
6
|
+
|
7
|
+
gem_spec = Gem::Specification.load("bitcount.gemspec")
|
8
|
+
|
9
|
+
module FixRequiredRubyVersion
|
10
|
+
def required_ruby_version=(*); end
|
11
|
+
end
|
12
|
+
Gem::Specification.send(:prepend, FixRequiredRubyVersion)
|
13
|
+
|
14
|
+
Rake::ExtensionTask.new('bitcount_ext', gem_spec) do |ext|
|
15
|
+
ext.name = 'bitcount_ext'
|
16
|
+
ext.ext_dir = 'ext'
|
17
|
+
ext.lib_dir = 'lib/bitcount_ext'
|
18
|
+
end
|
19
|
+
|
20
|
+
CLEAN.include 'lib/bitcount_ext/bitcount_ext.{so,bundle,dll}',
|
21
|
+
'ext/*.{o,so,bundle,dll}', 'ext/Makefile', 'tmp'
|
22
|
+
|
23
|
+
RSpec::Core::RakeTask.new(:spec)
|
24
|
+
task test: 'compile:bitcount_ext' do
|
25
|
+
Rake::Task['spec'].invoke
|
26
|
+
end
|
27
|
+
task default: :test
|
@@ -0,0 +1,8 @@
|
|
1
|
+
prelude: require 'bitcount'
|
2
|
+
benchmark:
|
3
|
+
native_popcount: Bitcount::Native.popcount(122)
|
4
|
+
native_nlz: Bitcount::Native.nlz(122)
|
5
|
+
native_ntz: Bitcount::Native.ntz(122)
|
6
|
+
ruby_popcount: Bitcount::Pure.popcount(122)
|
7
|
+
ruby_nlz: Bitcount::Pure.nlz(122)
|
8
|
+
ruby_ntz: Bitcount::Pure.ntz(122)
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "bitcount"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/bitcount.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'lib/bitcount/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "bitcount"
|
5
|
+
spec.version = Bitcount::VERSION
|
6
|
+
spec.authors = ["Pavel Rosický"]
|
7
|
+
spec.email = ["pdahorek@seznam.cz"]
|
8
|
+
|
9
|
+
spec.summary = %q{Bitcount helper methods.}
|
10
|
+
spec.homepage = "https://github.com/ahorek/bitcount"
|
11
|
+
spec.license = "MIT"
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
13
|
+
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
16
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
|
17
|
+
|
18
|
+
spec.platform = Gem::Platform::RUBY
|
19
|
+
spec.extensions = ["ext/extconf.rb"]
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
|
25
|
+
end
|
26
|
+
spec.require_paths = ["lib", "lib/bitcount"]
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'ffi'
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#include <limits.h>
|
2
|
+
#include <stdint.h>
|
3
|
+
#include <stddef.h>
|
4
|
+
|
5
|
+
#ifndef GCC_VERSION_SINCE
|
6
|
+
# if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
|
7
|
+
# define GCC_VERSION_SINCE(major, minor, patchlevel) \
|
8
|
+
((__GNUC__ > (major)) || \
|
9
|
+
((__GNUC__ == (major) && \
|
10
|
+
((__GNUC_MINOR__ > (minor)) || \
|
11
|
+
(__GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel))))))
|
12
|
+
# else
|
13
|
+
# define GCC_VERSION_SINCE(major, minor, patchlevel) 0
|
14
|
+
# endif
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#ifndef __has_builtin
|
18
|
+
#if GCC_VERSION_SINCE(4, 8, 0)
|
19
|
+
# define __has_builtin(x) 1
|
20
|
+
# else
|
21
|
+
# define __has_builtin(x) 0
|
22
|
+
#endif
|
23
|
+
#endif
|
24
|
+
|
25
|
+
size_t ext_layout();
|
26
|
+
size_t ext_popcount(size_t x);
|
27
|
+
size_t ext_nlz(size_t x);
|
28
|
+
size_t ext_ntz(size_t x);
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#include "bitcount_ext.h"
|
2
|
+
#include "helpers.c"
|
3
|
+
|
4
|
+
size_t ext_layout()
|
5
|
+
{
|
6
|
+
return sizeof(size_t) * CHAR_BIT;
|
7
|
+
}
|
8
|
+
|
9
|
+
size_t ext_popcount(size_t x)
|
10
|
+
{
|
11
|
+
if (sizeof(size_t) * CHAR_BIT == 64) {
|
12
|
+
return ext_popcount64((uint64_t)x);
|
13
|
+
}
|
14
|
+
else if (sizeof(size_t) * CHAR_BIT == 32) {
|
15
|
+
return ext_popcount32((uint32_t)x);
|
16
|
+
}
|
17
|
+
else {
|
18
|
+
__builtin_unreachable();
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
size_t ext_nlz(size_t x)
|
23
|
+
{
|
24
|
+
if (sizeof(size_t) * CHAR_BIT == 32) {
|
25
|
+
return nlz_int32((uint32_t)x);
|
26
|
+
}
|
27
|
+
else if (sizeof(size_t) * CHAR_BIT == 64) {
|
28
|
+
return nlz_int64((uint64_t)x);
|
29
|
+
}
|
30
|
+
else {
|
31
|
+
__builtin_unreachable();
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
size_t ext_ntz(size_t x)
|
36
|
+
{
|
37
|
+
if (sizeof(size_t) * CHAR_BIT == 64) {
|
38
|
+
return ntz_int64((uint64_t)x);
|
39
|
+
}
|
40
|
+
else if (sizeof(size_t) * CHAR_BIT == 32) {
|
41
|
+
return ntz_int32((uint32_t)x);
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
__builtin_unreachable();
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
unsigned int ext_popcount64(uint64_t x)
|
2
|
+
{
|
3
|
+
#if __has_builtin(__builtin_popcount)
|
4
|
+
if (sizeof(long) * CHAR_BIT == 64) {
|
5
|
+
return (unsigned int)__builtin_popcountl((unsigned long)x);
|
6
|
+
}
|
7
|
+
else if (sizeof(long long) * CHAR_BIT == 64) {
|
8
|
+
return (unsigned int)__builtin_popcountll((unsigned long long)x);
|
9
|
+
}
|
10
|
+
else {
|
11
|
+
__builtin_unreachable();
|
12
|
+
}
|
13
|
+
#else
|
14
|
+
x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
|
15
|
+
x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
|
16
|
+
x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707);
|
17
|
+
x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
|
18
|
+
x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
|
19
|
+
x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
|
20
|
+
return (unsigned int)x;
|
21
|
+
|
22
|
+
#endif
|
23
|
+
}
|
24
|
+
|
25
|
+
unsigned int ext_popcount32(uint32_t x)
|
26
|
+
{
|
27
|
+
#if __has_builtin(__builtin_popcount)
|
28
|
+
return (unsigned int)__builtin_popcount(x);
|
29
|
+
|
30
|
+
#else
|
31
|
+
x = (x & 0x55555555) + (x >> 1 & 0x55555555);
|
32
|
+
x = (x & 0x33333333) + (x >> 2 & 0x33333333);
|
33
|
+
x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f);
|
34
|
+
x = (x & 0x001f001f) + (x >> 8 & 0x001f001f);
|
35
|
+
x = (x & 0x0000003f) + (x >>16 & 0x0000003f);
|
36
|
+
return (unsigned int)x;
|
37
|
+
#endif
|
38
|
+
}
|
39
|
+
|
40
|
+
unsigned int nlz_int32(uint32_t x)
|
41
|
+
{
|
42
|
+
#if __has_builtin(__builtin_clz)
|
43
|
+
return (unsigned int)__builtin_clz(x);
|
44
|
+
|
45
|
+
#else
|
46
|
+
uint32_t y;
|
47
|
+
unsigned n = 32;
|
48
|
+
y = x >> 16; if (y) {n -= 16; x = y;}
|
49
|
+
y = x >> 8; if (y) {n -= 8; x = y;}
|
50
|
+
y = x >> 4; if (y) {n -= 4; x = y;}
|
51
|
+
y = x >> 2; if (y) {n -= 2; x = y;}
|
52
|
+
y = x >> 1; if (y) {return n - 2;}
|
53
|
+
return (unsigned int)(n - x);
|
54
|
+
#endif
|
55
|
+
}
|
56
|
+
|
57
|
+
unsigned int nlz_int64(uint64_t x)
|
58
|
+
{
|
59
|
+
#if __has_builtin(__builtin_clzl)
|
60
|
+
if (x == 0) {
|
61
|
+
return 64;
|
62
|
+
}
|
63
|
+
else if (sizeof(long) * CHAR_BIT == 64) {
|
64
|
+
return (unsigned int)__builtin_clzl((unsigned long)x);
|
65
|
+
}
|
66
|
+
else if (sizeof(long long) * CHAR_BIT == 64) {
|
67
|
+
return (unsigned int)__builtin_clzll((unsigned long long)x);
|
68
|
+
}
|
69
|
+
else {
|
70
|
+
__builtin_unreachable();
|
71
|
+
}
|
72
|
+
|
73
|
+
#else
|
74
|
+
uint64_t y;
|
75
|
+
unsigned int n = 64;
|
76
|
+
y = x >> 32; if (y) {n -= 32; x = y;}
|
77
|
+
y = x >> 16; if (y) {n -= 16; x = y;}
|
78
|
+
y = x >> 8; if (y) {n -= 8; x = y;}
|
79
|
+
y = x >> 4; if (y) {n -= 4; x = y;}
|
80
|
+
y = x >> 2; if (y) {n -= 2; x = y;}
|
81
|
+
y = x >> 1; if (y) {return n - 2;}
|
82
|
+
return (unsigned int)(n - x);
|
83
|
+
|
84
|
+
#endif
|
85
|
+
}
|
86
|
+
|
87
|
+
unsigned int ntz_int32(uint32_t x)
|
88
|
+
{
|
89
|
+
#if __has_builtin(__builtin_ctz)
|
90
|
+
return (unsigned)__builtin_ctz(x);
|
91
|
+
#else
|
92
|
+
return ext_popcount32((~x) & (x-1));
|
93
|
+
#endif
|
94
|
+
}
|
95
|
+
|
96
|
+
unsigned int ntz_int64(uint64_t x)
|
97
|
+
{
|
98
|
+
#if __has_builtin(__builtin_ctzl)
|
99
|
+
if (x == 0) {
|
100
|
+
return 64;
|
101
|
+
}
|
102
|
+
else if (sizeof(long) * CHAR_BIT == 64) {
|
103
|
+
return (unsigned)__builtin_ctzl((unsigned long)x);
|
104
|
+
}
|
105
|
+
else if (sizeof(long long) * CHAR_BIT == 64) {
|
106
|
+
return (unsigned)__builtin_ctzll((unsigned long long)x);
|
107
|
+
}
|
108
|
+
else {
|
109
|
+
__builtin_unreachable();
|
110
|
+
}
|
111
|
+
#else
|
112
|
+
return ext_popcount64((~x) & (x-1));
|
113
|
+
#endif
|
114
|
+
}
|
data/ext/depend
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$(OBJS): $(HDRS)
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mkmf'
|
4
|
+
|
5
|
+
$CFLAGS << ' -std=c99'
|
6
|
+
|
7
|
+
if enable_config('march-tune-native', false)
|
8
|
+
$CFLAGS << ' -march=native -mtune=native'
|
9
|
+
end
|
10
|
+
|
11
|
+
if enable_config('lto', false)
|
12
|
+
$CFLAGS << ' -flto'
|
13
|
+
$LDFLAGS << ' -flto'
|
14
|
+
end
|
15
|
+
|
16
|
+
$warnflags = ''
|
17
|
+
$CFLAGS.gsub!(/[\s+](-ansi|-std=[^\s]+)/, '')
|
18
|
+
|
19
|
+
dir_config 'bitcount_ext'
|
20
|
+
|
21
|
+
$INCFLAGS << " -I$(srcdir)/bitcount_ext/include"
|
22
|
+
$VPATH << "$(srcdir)/bitcount_ext/src"
|
23
|
+
Dir.chdir(__dir__) do
|
24
|
+
$VPATH += Dir['bitcount_ext/src/*/'].map { |p| "$(srcdir)/#{p}" }
|
25
|
+
$srcs = Dir['bitcount_ext/src/bitcount_ext.c']
|
26
|
+
end
|
27
|
+
|
28
|
+
$LIBRUBYARG = nil
|
29
|
+
MakeMakefile::LINK_SO << "\nstrip -x $@"
|
30
|
+
|
31
|
+
MakeMakefile.send(:remove_const, :EXPORT_PREFIX)
|
32
|
+
MakeMakefile::EXPORT_PREFIX = nil
|
33
|
+
|
34
|
+
create_makefile 'bitcount/bitcount_ext'
|
data/lib/bitcount.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bitcount/version"
|
4
|
+
require "bitcount/pure"
|
5
|
+
begin
|
6
|
+
require "bitcount/native"
|
7
|
+
rescue LoadError
|
8
|
+
puts 'bitcount_ext not loaded'
|
9
|
+
end
|
10
|
+
|
11
|
+
module Bitcount
|
12
|
+
class << self
|
13
|
+
def popcount(n)
|
14
|
+
type_error unless n.is_a?(Integer)
|
15
|
+
negative_error if n < 0
|
16
|
+
implementation.popcount(n)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ntz(n, size = nil)
|
20
|
+
type_error unless n.is_a?(Integer)
|
21
|
+
negative_error if n < 0
|
22
|
+
implementation.ntz(n, size)
|
23
|
+
end
|
24
|
+
|
25
|
+
def nlz(n, size = nil)
|
26
|
+
type_error unless n.is_a?(Integer)
|
27
|
+
negative_error if n < 0
|
28
|
+
implementation.nlz(n, size)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def implementation
|
34
|
+
defined?(:"Bitcount::Native") ? Bitcount::Native : Bitcount::Pure
|
35
|
+
end
|
36
|
+
|
37
|
+
def type_error
|
38
|
+
raise TypeError, 'not a number'
|
39
|
+
end
|
40
|
+
|
41
|
+
def negative_error
|
42
|
+
raise ArgumentError, 'number is negative'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ffi"
|
4
|
+
|
5
|
+
module Bitcount
|
6
|
+
module Native
|
7
|
+
class << self
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
dl_ext = RbConfig::MAKEFILE_CONFIG['DLEXT']
|
11
|
+
begin
|
12
|
+
ffi_lib File.expand_path("../bitcount_ext/bitcount_ext.#{dl_ext}", __dir__)
|
13
|
+
rescue LoadError
|
14
|
+
ffi_lib File.expand_path("bitcount_ext.#{dl_ext}", "#{__dir__}/../../ext")
|
15
|
+
end
|
16
|
+
|
17
|
+
attach_function :ext_layout, [], :size_t
|
18
|
+
attach_function :ext_popcount, [:size_t], :size_t
|
19
|
+
attach_function :ext_nlz, [:size_t], :size_t
|
20
|
+
attach_function :ext_ntz, [:size_t], :size_t
|
21
|
+
|
22
|
+
def layout_size
|
23
|
+
ext_layout
|
24
|
+
rescue
|
25
|
+
64
|
26
|
+
end
|
27
|
+
|
28
|
+
def popcount(n)
|
29
|
+
return Bitcount::Pure.popcount(n) if defined?(JRUBY_VERSION) && n > max_value
|
30
|
+
begin
|
31
|
+
ext_popcount(n)
|
32
|
+
rescue
|
33
|
+
Bitcount::Pure.popcount(n)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def ntz(n, size = nil)
|
38
|
+
size ||= layout_size
|
39
|
+
return Bitcount::Pure.ntz(n, size) if layout_size != size || (defined?(JRUBY_VERSION) && n > max_value)
|
40
|
+
begin
|
41
|
+
ext_ntz(n)
|
42
|
+
rescue
|
43
|
+
Bitcount::Pure.ntz(n, size)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def nlz(n, size = nil)
|
48
|
+
size ||= layout_size
|
49
|
+
return Bitcount::Pure.nlz(n, size) if layout_size != size || (defined?(JRUBY_VERSION) && n > max_value)
|
50
|
+
begin
|
51
|
+
ext_nlz(n)
|
52
|
+
rescue
|
53
|
+
Bitcount::Pure.nlz(n, size)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def max_value
|
60
|
+
(2 ** layout_size) - 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def layout_error
|
64
|
+
raise RangeError, 'number is too large'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitcount
|
4
|
+
module Pure
|
5
|
+
class << self
|
6
|
+
def layout_size
|
7
|
+
64
|
8
|
+
end
|
9
|
+
|
10
|
+
def popcount(n)
|
11
|
+
n.to_s(2).count("1")
|
12
|
+
end
|
13
|
+
|
14
|
+
def ntz(n, size = nil)
|
15
|
+
size ||= layout_size
|
16
|
+
count = 0
|
17
|
+
bits = n.to_s(2)
|
18
|
+
layout_error if bits.size > size
|
19
|
+
bits.rjust(size, "0").reverse.each_char do |b|
|
20
|
+
(b == '0') ? count += 1 : break
|
21
|
+
end
|
22
|
+
count
|
23
|
+
end
|
24
|
+
|
25
|
+
def nlz(n, size = nil)
|
26
|
+
size ||= layout_size
|
27
|
+
count = 0
|
28
|
+
bits = n.to_s(2)
|
29
|
+
layout_error if bits.size > size
|
30
|
+
bits.rjust(size, "0").each_char do |b|
|
31
|
+
(b == '0') ? count += 1 : break
|
32
|
+
end
|
33
|
+
count
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def layout_error
|
39
|
+
raise RangeError, 'number is too large'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitcount
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pavel Rosický
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- pdahorek@seznam.cz
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/extconf.rb
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- ".rspec"
|
37
|
+
- ".travis.yml"
|
38
|
+
- CHANGELOG.md
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- benchmark/bitcount.yml
|
44
|
+
- bin/console
|
45
|
+
- bin/setup
|
46
|
+
- bitcount.gemspec
|
47
|
+
- ext/bitcount_ext/include/bitcount_ext.h
|
48
|
+
- ext/bitcount_ext/src/bitcount_ext.c
|
49
|
+
- ext/bitcount_ext/src/helpers.c
|
50
|
+
- ext/depend
|
51
|
+
- ext/extconf.rb
|
52
|
+
- lib/bitcount.rb
|
53
|
+
- lib/bitcount/integer.rb
|
54
|
+
- lib/bitcount/native.rb
|
55
|
+
- lib/bitcount/pure.rb
|
56
|
+
- lib/bitcount/version.rb
|
57
|
+
homepage: https://github.com/ahorek/bitcount
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata:
|
61
|
+
homepage_uri: https://github.com/ahorek/bitcount
|
62
|
+
source_code_uri: https://github.com/ahorek/bitcount
|
63
|
+
changelog_uri: https://github.com/ahorek/bitcount/CHANGELOG.md
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
- lib/bitcount
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 2.3.0
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubygems_version: 3.1.2
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Bitcount helper methods.
|
84
|
+
test_files: []
|