bit_utils 0.1.1-java
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 +15 -0
- data/.rspec +2 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/Rakefile +18 -0
- data/benchmark/count.rb +45 -0
- data/benchmark/each_bit.rb +47 -0
- data/benchmark/trailing_zeros.rb +45 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bit_utils.gemspec +35 -0
- data/ext/bit_utils/bit_utils.h +10 -0
- data/ext/bit_utils/count.c +178 -0
- data/ext/bit_utils/count.h +24 -0
- data/ext/bit_utils/each_bit.c +82 -0
- data/ext/bit_utils/each_bit.h +10 -0
- data/ext/bit_utils/extconf.rb +50 -0
- data/ext/bit_utils/funcs.c +57 -0
- data/ext/bit_utils/funcs.h +30 -0
- data/ext/bit_utils/init.c +14 -0
- data/ext/bit_utils/trailing_zeros.c +39 -0
- data/ext/bit_utils/trailing_zeros.h +18 -0
- data/lib/bit_utils.rb +13 -0
- data/lib/bit_utils/core_ext.rb +3 -0
- data/lib/bit_utils/core_ext/each_bit.rb +15 -0
- data/lib/bit_utils/core_ext/popcount.rb +15 -0
- data/lib/bit_utils/core_ext/trailing_zeros.rb +15 -0
- data/lib/bit_utils/cruby.rb +6 -0
- data/lib/bit_utils/jruby.rb +66 -0
- data/lib/bit_utils/jruby_bit_length.rb +23 -0
- data/lib/bit_utils/pure_ruby.rb +54 -0
- data/lib/bit_utils/version.rb +3 -0
- metadata +148 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b3a43f5b1fa5a368f668333525bfbe4e26c81936
|
4
|
+
data.tar.gz: 74a634a4e4d5f2ed55ad6f5d0885b4485520345f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 03ae269c996d32a8ab0577a285a47ea4a57118a30192ed8d234714d8cdec581b4332efe14da2ae69f11a5518fbbd03aebafb59f020bb36e89db371a5f67fd981
|
7
|
+
data.tar.gz: 78079e83d9f89c0a2c98443559368db1a3ecfc64088a76c3365f3d72889bc44871cd8b77be997cbc456ae9a8d32322a41d45e19ea4f12c23fabceb2c5a6a9a76
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Jkr2255
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# BitUtils
|
2
|
+
|
3
|
+
[](https://travis-ci.org/jkr2255/bit_utils)
|
4
|
+
|
5
|
+
Utility methods for bit-wise operations of `Integer`.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'bit_utils'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install bit_utils
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Module `BitUtils` appears after `require 'bit_utils'`.
|
26
|
+
|
27
|
+
Currently `BitUtils` offers three functionalities.
|
28
|
+
|
29
|
+
### `BitUtils.#popcount(num)`
|
30
|
+
Returns popcount (Hamming weight) of the `num`; i.e. equal to `num.to_s(2).count('1')` for non-negative numbers.
|
31
|
+
|
32
|
+
#### for negative numbers
|
33
|
+
Theoretically, Ruby treats negative integers as if *infinite* 1-bits are leaded (`printf '%x', -1` gives `..f` ),
|
34
|
+
so counting 1 bits for negative numbers is meaningless.
|
35
|
+
|
36
|
+
In this implementation, `popcount` for negative number counts *0* bits and negates the result. (distinguishing with positive version) Same in Ruby:
|
37
|
+
```rb
|
38
|
+
return -popcount(~num) if num < 0
|
39
|
+
```
|
40
|
+
|
41
|
+
Note that both `popcount(0)` and `popcount(-1)` still return 0.
|
42
|
+
|
43
|
+
### `BitUtils.#trailing_zeros(num)`
|
44
|
+
Returns the number of 0 bits continuing from least significant bit. If `num == 0`, it returns -1.
|
45
|
+
|
46
|
+
### `BitUtils.#each_bit(num, &block)`
|
47
|
+
Iterate over 1-bit positions in `Integer`. If block is not given, it returns `Enumerator`.
|
48
|
+
|
49
|
+
The yielding order is *unspecified*; may change by platform/version.
|
50
|
+
|
51
|
+
If negative `num` is given, it raises `RangeError`
|
52
|
+
|
53
|
+
### common to all functionalities
|
54
|
+
All of the module functions raise `TypeError` unless the parameter is `Integer`.
|
55
|
+
|
56
|
+
All module functions have `.#xxx_fixnum` and `.#xxx_bignum` (specific for `Fixnum` and `Bignum`), but these are not intended for direct use.
|
57
|
+
|
58
|
+
|
59
|
+
## Development
|
60
|
+
|
61
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
62
|
+
|
63
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
64
|
+
|
65
|
+
### Limitations
|
66
|
+
This gem is mainly developed on x64 GCC environment, so in other environments it may not work or be slow.
|
67
|
+
|
68
|
+
Pull requests for other environments are welcome.
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jkr2255/bit_utils.
|
73
|
+
|
74
|
+
|
75
|
+
## License
|
76
|
+
|
77
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
78
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
if RUBY_PLATFORM =~ /java/
|
7
|
+
task :default => [:spec]
|
8
|
+
else
|
9
|
+
require "rake/extensiontask"
|
10
|
+
|
11
|
+
task :build => :compile
|
12
|
+
|
13
|
+
Rake::ExtensionTask.new("bit_utils") do |ext|
|
14
|
+
ext.lib_dir = "lib/bit_utils"
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:clobber, :compile, :spec]
|
18
|
+
end
|
data/benchmark/count.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'bit_utils'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
puts 'Fixnum'
|
5
|
+
value = 0x1234_5678
|
6
|
+
times = 1_000_000
|
7
|
+
Benchmark.bm 10 do |r|
|
8
|
+
r.report "Pure Ruby" do
|
9
|
+
times.times do
|
10
|
+
BitUtils::PureRuby.count_fixnum value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
r.report "Optimized" do
|
14
|
+
times.times do
|
15
|
+
BitUtils.count value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
puts
|
20
|
+
|
21
|
+
patterns = [
|
22
|
+
{value: (2**128) - (2**32), repeat: 1_000_000, title: '128-bit Bignum' },
|
23
|
+
{value: (2**999) + (2**32), repeat: 100_000, title: '1000-bit Bignum' },
|
24
|
+
]
|
25
|
+
|
26
|
+
|
27
|
+
patterns.each do |h|
|
28
|
+
puts h[:title]
|
29
|
+
value = h[:value]
|
30
|
+
times =
|
31
|
+
Benchmark.bm 10 do |r|
|
32
|
+
r.report "Pure Ruby" do
|
33
|
+
h[:repeat].times do
|
34
|
+
BitUtils::PureRuby.count_bignum value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
r.report "Optimized" do
|
38
|
+
h[:repeat].times do
|
39
|
+
BitUtils.count value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
puts
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'bit_utils'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
puts 'Fixnum'
|
5
|
+
value = 0x1F3C_0A27
|
6
|
+
times = 1_000_000
|
7
|
+
Benchmark.bm 10 do |r|
|
8
|
+
r.report "Pure Ruby" do
|
9
|
+
times.times do
|
10
|
+
BitUtils::PureRuby.each_bit_fixnum(value).to_a
|
11
|
+
end
|
12
|
+
end
|
13
|
+
r.report "Optimized" do
|
14
|
+
times.times do
|
15
|
+
BitUtils.each_bit(value).to_a
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
puts
|
21
|
+
|
22
|
+
patterns = [
|
23
|
+
{value: (2**128) - (2**32), repeat: 100_000, title: '128-bit Bignum' },
|
24
|
+
{value: (2**999) + (2**32), repeat: 100_000, title: '1000-bit Bignum (sparse)' },
|
25
|
+
{value: (2**1000) - (2**40), repeat: 10_000, title: '1000-bit Bignum' },
|
26
|
+
]
|
27
|
+
|
28
|
+
|
29
|
+
patterns.each do |h|
|
30
|
+
puts h[:title]
|
31
|
+
value = h[:value]
|
32
|
+
times =
|
33
|
+
Benchmark.bm 10 do |r|
|
34
|
+
r.report "Pure Ruby" do
|
35
|
+
h[:repeat].times do
|
36
|
+
BitUtils::PureRuby.each_bit_bignum(value).to_a
|
37
|
+
end
|
38
|
+
end
|
39
|
+
r.report "Optimized" do
|
40
|
+
h[:repeat].times do
|
41
|
+
BitUtils.each_bit(value).to_a
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
puts
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'bit_utils'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
puts 'Fixnum'
|
5
|
+
value = 0x1000_0000
|
6
|
+
times = 1_000_000
|
7
|
+
Benchmark.bm 10 do |r|
|
8
|
+
r.report "Pure Ruby" do
|
9
|
+
times.times do
|
10
|
+
BitUtils::PureRuby.trailing_zeros_fixnum value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
r.report "Optimized" do
|
14
|
+
times.times do
|
15
|
+
BitUtils.trailing_zeros value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
puts
|
20
|
+
|
21
|
+
patterns = [
|
22
|
+
{value: (2**128) - (2**32), repeat: 1_000_000, title: '128-bit Bignum' },
|
23
|
+
{value: (2**999) + (2**32), repeat: 100_000, title: '1000-bit Bignum' },
|
24
|
+
]
|
25
|
+
|
26
|
+
|
27
|
+
patterns.each do |h|
|
28
|
+
puts h[:title]
|
29
|
+
value = h[:value]
|
30
|
+
times =
|
31
|
+
Benchmark.bm 10 do |r|
|
32
|
+
r.report "Pure Ruby" do
|
33
|
+
h[:repeat].times do
|
34
|
+
BitUtils::PureRuby.trailing_zeros_bignum value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
r.report "Optimized" do
|
38
|
+
h[:repeat].times do
|
39
|
+
BitUtils.trailing_zeros value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
puts
|
44
|
+
end
|
45
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "bit_utils"
|
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
|
data/bin/setup
ADDED
data/bit_utils.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bit_utils/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'bit_utils'
|
8
|
+
spec.version = BitUtils::VERSION
|
9
|
+
spec.authors = %w[Jkr2255]
|
10
|
+
spec.email = %w[magnesium.oxide.play@gmail.com]
|
11
|
+
|
12
|
+
spec.summary = 'Utility methods for manipulating bits within Integer.'
|
13
|
+
spec.homepage = 'https://github.com/jkr2255/bit_utils'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'exe'
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = %w[lib]
|
20
|
+
spec.required_ruby_version = '>= 1.9.3'
|
21
|
+
|
22
|
+
spec.add_dependency 'function_module', '>= 0.1.1'
|
23
|
+
|
24
|
+
if RUBY_PLATFORM =~ /java/
|
25
|
+
spec.platform = 'java'
|
26
|
+
else
|
27
|
+
spec.extensions = %w[ext/bit_utils/extconf.rb]
|
28
|
+
spec.add_dependency 'backports', '>= 3.6.6'
|
29
|
+
end
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
32
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
33
|
+
spec.add_development_dependency 'rake-compiler'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#include "count.h"
|
2
|
+
|
3
|
+
static VALUE bitutils_cimpl_count_fixnum(VALUE self, VALUE num){
|
4
|
+
long l_num = NUM2LONG(num);
|
5
|
+
int val = POPCOUNTL(l_num);
|
6
|
+
if(l_num < 0) val -= sizeof(long) * CHAR_BIT;
|
7
|
+
return INT2FIX(val);
|
8
|
+
}
|
9
|
+
|
10
|
+
#ifdef HAVE_POPCNT_GCC_ASM
|
11
|
+
static VALUE bitutils_cimpl_count_fixnum_asm(VALUE self, VALUE num){
|
12
|
+
long l_num = NUM2LONG(num);
|
13
|
+
long val;
|
14
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(val): "r"(l_num) : );
|
15
|
+
if(l_num < 0) val -= sizeof(long) * CHAR_BIT;
|
16
|
+
return LONG2FIX(val);
|
17
|
+
}
|
18
|
+
#define ASM_POPCOUNT 1
|
19
|
+
#else
|
20
|
+
static VALUE bitutils_cimpl_count_fixnum_asm(VALUE self, VALUE num){
|
21
|
+
/* dummy function for C compiler, never called from Ruby */
|
22
|
+
return Qnil;
|
23
|
+
}
|
24
|
+
#define ASM_POPCOUNT 0
|
25
|
+
#endif
|
26
|
+
|
27
|
+
/* for bignum */
|
28
|
+
static VALUE bitutils_cimpl_count_bignum(VALUE self, VALUE num){
|
29
|
+
int negated = 0;
|
30
|
+
unsigned long * packed;
|
31
|
+
VALUE abs_num;
|
32
|
+
size_t words, i;
|
33
|
+
LONG_LONG ret = 0;
|
34
|
+
if(FIXNUM_P(num)){
|
35
|
+
return bitutils_cimpl_count_fixnum(self, num);
|
36
|
+
}
|
37
|
+
Check_Type(num, T_BIGNUM);
|
38
|
+
if(RBIGNUM_NEGATIVE_P(num)){
|
39
|
+
negated = 1;
|
40
|
+
abs_num = BIG_NEG(num);
|
41
|
+
}else{
|
42
|
+
abs_num = num;
|
43
|
+
}
|
44
|
+
words = BIGNUM_IN_ULONG(abs_num);
|
45
|
+
if(words < ALLOCA_THRESHOLD){
|
46
|
+
packed = ALLOCA_N(unsigned long, words);
|
47
|
+
}else{
|
48
|
+
packed = ALLOC_N(unsigned long, words);
|
49
|
+
}
|
50
|
+
BIG_PACK(abs_num, packed, words);
|
51
|
+
for(i = 0; i < words; ++i){
|
52
|
+
ret += POPCOUNTL(packed[i]);
|
53
|
+
}
|
54
|
+
if(negated) ret = -ret;
|
55
|
+
if(words >= ALLOCA_THRESHOLD) xfree(packed);
|
56
|
+
return LL2NUM(ret);
|
57
|
+
}
|
58
|
+
|
59
|
+
#if defined(HAVE_POPCNT_GCC_ASM) && defined(HAVE_POPCNT_LL_GCC_ASM) && (SIZEOF_LONG_LONG == SIZEOF_LONG * 2)
|
60
|
+
/* for Windows */
|
61
|
+
union ull_punning{
|
62
|
+
unsigned long long ull;
|
63
|
+
unsigned long ul[2];
|
64
|
+
};
|
65
|
+
|
66
|
+
static VALUE bitutils_cimpl_count_bignum_asm(VALUE self, VALUE num){
|
67
|
+
int negated = 0;
|
68
|
+
unsigned long * packed;
|
69
|
+
union ull_punning * ull_packed;
|
70
|
+
unsigned long long ull_o = 0, ull_o2 = 0;
|
71
|
+
unsigned long long ull_i, ull_i2;
|
72
|
+
VALUE abs_num;
|
73
|
+
size_t words, i, ull_dwords;
|
74
|
+
LONG_LONG ret = 0, ret2 = 0;
|
75
|
+
if(FIXNUM_P(num)){
|
76
|
+
return bitutils_cimpl_count_fixnum_asm(self, num);
|
77
|
+
}
|
78
|
+
Check_Type(num, T_BIGNUM);
|
79
|
+
if(RBIGNUM_NEGATIVE_P(num)){
|
80
|
+
negated = 1;
|
81
|
+
abs_num = BIG_NEG(num);
|
82
|
+
}else{
|
83
|
+
abs_num = num;
|
84
|
+
}
|
85
|
+
words = BIGNUM_IN_ULONG(abs_num);
|
86
|
+
if(words < ALLOCA_THRESHOLD){
|
87
|
+
packed = ALLOCA_N(unsigned long, words);
|
88
|
+
}else{
|
89
|
+
packed = ALLOC_N(unsigned long, words);
|
90
|
+
}
|
91
|
+
BIG_PACK(abs_num, packed, words);
|
92
|
+
ull_dwords = words / 4;
|
93
|
+
ull_packed = (union ull_punning *) packed;
|
94
|
+
for(i = 0; i < ull_dwords * 2; i += 2){
|
95
|
+
ull_i = ull_packed[i].ull;
|
96
|
+
ull_i2 = ull_packed[i+1].ull;
|
97
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ull_o): "r"(ull_i) : );
|
98
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ull_o2): "r"(ull_i2) : );
|
99
|
+
ret += ull_o;
|
100
|
+
ret2 += ull_o2;
|
101
|
+
}
|
102
|
+
ret += ret2;
|
103
|
+
for(i *= 2; i < words; ++i){
|
104
|
+
unsigned long ul_out = 0;
|
105
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ul_out): "r"(packed[i]) : );
|
106
|
+
ret += ul_out;
|
107
|
+
}
|
108
|
+
if(negated) ret = -ret;
|
109
|
+
if(words >= ALLOCA_THRESHOLD) xfree(packed);
|
110
|
+
return LL2NUM(ret);
|
111
|
+
}
|
112
|
+
|
113
|
+
#elif defined(HAVE_POPCNT_GCC_ASM)
|
114
|
+
static VALUE bitutils_cimpl_count_bignum_asm(VALUE self, VALUE num){
|
115
|
+
int negated = 0;
|
116
|
+
unsigned long * packed;
|
117
|
+
unsigned long ul_i, ul_o = 0;
|
118
|
+
unsigned long ul_i2, ul_o2 = 0;
|
119
|
+
VALUE abs_num;
|
120
|
+
size_t words, dwords, i;
|
121
|
+
LONG_LONG ret = 0, ret2 = 0;
|
122
|
+
if(FIXNUM_P(num)){
|
123
|
+
return bitutils_cimpl_count_fixnum_asm(self, num);
|
124
|
+
}
|
125
|
+
Check_Type(num, T_BIGNUM);
|
126
|
+
if(RBIGNUM_NEGATIVE_P(num)){
|
127
|
+
negated = 1;
|
128
|
+
abs_num = BIG_NEG(num);
|
129
|
+
}else{
|
130
|
+
abs_num = num;
|
131
|
+
}
|
132
|
+
words = BIGNUM_IN_ULONG(abs_num);
|
133
|
+
if(words < ALLOCA_THRESHOLD){
|
134
|
+
packed = ALLOCA_N(unsigned long, words);
|
135
|
+
}else{
|
136
|
+
packed = ALLOC_N(unsigned long, words);
|
137
|
+
}
|
138
|
+
BIG_PACK(abs_num, packed, words);
|
139
|
+
dwords = words / 2;
|
140
|
+
for(i = 0; i < dwords * 2; i += 2){
|
141
|
+
ul_i = packed[i];
|
142
|
+
ul_i2 = packed[i+1];
|
143
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ul_o): "r"(ul_i) : );
|
144
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ul_o2): "r"(ul_i2) : );
|
145
|
+
ret += ul_o;
|
146
|
+
ret2 += ul_o2;
|
147
|
+
}
|
148
|
+
ret += ret2;
|
149
|
+
if(words & 1){
|
150
|
+
__asm__ volatile ("POPCNT %1, %0;": "=r"(ul_o): "r"(packed[i]) : );
|
151
|
+
ret += ul_o;
|
152
|
+
}
|
153
|
+
if(negated) ret = -ret;
|
154
|
+
if(words >= ALLOCA_THRESHOLD) xfree(packed);
|
155
|
+
return LL2NUM(ret);
|
156
|
+
}
|
157
|
+
#else
|
158
|
+
static VALUE bitutils_cimpl_count_bignum_asm(VALUE self, VALUE num){
|
159
|
+
/* dummy function for C compiler, never called from Ruby */
|
160
|
+
return Qnil;
|
161
|
+
}
|
162
|
+
|
163
|
+
#endif
|
164
|
+
|
165
|
+
|
166
|
+
void register_count(VALUE mod){
|
167
|
+
VALUE have_cpu_popcnt;
|
168
|
+
have_cpu_popcnt = my_popcnt_p(mod);
|
169
|
+
if(ASM_POPCOUNT && have_cpu_popcnt){
|
170
|
+
rb_define_module_function(mod, "popcount_fixnum", bitutils_cimpl_count_fixnum_asm, 1);
|
171
|
+
rb_define_module_function(mod, "popcount_bignum", bitutils_cimpl_count_bignum_asm, 1);
|
172
|
+
rb_define_module_function(mod, "popcount", bitutils_cimpl_count_bignum_asm, 1);
|
173
|
+
}else{
|
174
|
+
rb_define_module_function(mod, "popcount_fixnum", bitutils_cimpl_count_fixnum, 1);
|
175
|
+
rb_define_module_function(mod, "popcount_bignum", bitutils_cimpl_count_bignum, 1);
|
176
|
+
rb_define_module_function(mod, "popcount", bitutils_cimpl_count_bignum, 1);
|
177
|
+
}
|
178
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#ifndef COUNT_H_INCLUDED
|
2
|
+
#define COUNT_H_INCLUDED 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "funcs.h"
|
6
|
+
|
7
|
+
#ifdef HAVE___BUILTIN_POPCOUNTL
|
8
|
+
#define POPCOUNTL(x) __builtin_popcountl(x)
|
9
|
+
#else
|
10
|
+
int my_popcountl(unsigned long x);
|
11
|
+
#define POPCOUNTL(x) my_popcountl(x)
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifdef HAVE_RB_BIG_XOR
|
15
|
+
#define BIG_NEG(val) rb_big_xor(val, INT2FIX(-1))
|
16
|
+
#else
|
17
|
+
#define BIG_NEG(val) rb_funcall(val, rb_intern("~"), 0)
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#define ALLOCA_THRESHOLD (1024 / sizeof(unsigned long))
|
21
|
+
|
22
|
+
void register_count(VALUE mod);
|
23
|
+
|
24
|
+
#endif
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include "each_bit.h"
|
2
|
+
|
3
|
+
static const char * mes = "Negative value is not accepted";
|
4
|
+
|
5
|
+
static VALUE bitutils_cimpl_each_bit_fixnum(VALUE self, VALUE num){
|
6
|
+
long l_num = NUM2LONG(num);
|
7
|
+
unsigned long ul_num = (unsigned long) l_num;
|
8
|
+
int shifted = 0, pos;
|
9
|
+
|
10
|
+
if(l_num < 0){
|
11
|
+
rb_raise(rb_eRangeError, mes);
|
12
|
+
}
|
13
|
+
|
14
|
+
RETURN_ENUMERATOR(self, 1, &num);
|
15
|
+
|
16
|
+
while(ul_num){
|
17
|
+
pos = CTZL(ul_num);
|
18
|
+
rb_yield(INT2FIX(pos + shifted));
|
19
|
+
++pos;
|
20
|
+
ul_num >>= pos;
|
21
|
+
shifted += pos;
|
22
|
+
}
|
23
|
+
return Qnil;
|
24
|
+
}
|
25
|
+
|
26
|
+
static VALUE bitutils_cimpl_each_bit_bignum(VALUE self, VALUE num){
|
27
|
+
unsigned long * packed;
|
28
|
+
long long_num = 0;
|
29
|
+
unsigned long line, one_line;
|
30
|
+
int is_fixnum = 0;
|
31
|
+
size_t words, i;
|
32
|
+
VALUE tmp_buf = Qnil;
|
33
|
+
if(FIXNUM_P(num)){
|
34
|
+
is_fixnum = 1;
|
35
|
+
long_num = FIX2LONG(num);
|
36
|
+
}else{
|
37
|
+
Check_Type(num, T_BIGNUM);
|
38
|
+
}
|
39
|
+
|
40
|
+
if(long_num < 0 || (is_fixnum == 0 && RBIGNUM_NEGATIVE_P(num))){
|
41
|
+
rb_raise(rb_eRangeError, mes);
|
42
|
+
}
|
43
|
+
|
44
|
+
RETURN_ENUMERATOR(self, 1, &num);
|
45
|
+
|
46
|
+
if(is_fixnum){
|
47
|
+
one_line = (unsigned long) long_num;
|
48
|
+
packed = &one_line;
|
49
|
+
words = 1;
|
50
|
+
}else{
|
51
|
+
words = BIGNUM_IN_ULONG(num);
|
52
|
+
if(words < ALLOCA_THRESHOLD){
|
53
|
+
packed = ALLOCA_N(unsigned long, words);
|
54
|
+
}else{
|
55
|
+
packed = rb_alloc_tmp_buffer(&tmp_buf, sizeof(unsigned long) * words);
|
56
|
+
}
|
57
|
+
BIG_PACK(num, packed, words);
|
58
|
+
}
|
59
|
+
|
60
|
+
for(i = 0; i < words; ++i){
|
61
|
+
int shifted = 0, pos;
|
62
|
+
line = packed[i];
|
63
|
+
while(line){
|
64
|
+
pos = CTZL(line);
|
65
|
+
rb_yield(INT2FIX(pos + shifted + i * sizeof(unsigned long) * CHAR_BIT));
|
66
|
+
++pos;
|
67
|
+
line >>= pos;
|
68
|
+
shifted += pos;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
if(tmp_buf != Qnil){
|
73
|
+
rb_free_tmp_buffer(&tmp_buf);
|
74
|
+
}
|
75
|
+
return Qnil;
|
76
|
+
}
|
77
|
+
|
78
|
+
void register_each_bit(VALUE mod){
|
79
|
+
rb_define_module_function(mod, "each_bit_fixnum", bitutils_cimpl_each_bit_fixnum, 1);
|
80
|
+
rb_define_module_function(mod, "each_bit_bignum", bitutils_cimpl_each_bit_bignum, 1);
|
81
|
+
rb_define_module_function(mod, "each_bit", bitutils_cimpl_each_bit_bignum, 1);
|
82
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
have_func('__builtin_popcountl(1)')
|
4
|
+
have_func('rb_absint_numwords')
|
5
|
+
have_func('rb_big_pack')
|
6
|
+
have_func('rb_integer_pack')
|
7
|
+
have_func('rb_big_xor')
|
8
|
+
have_header('cpuid.h') && have_func('__get_cpuid', 'cpuid.h')
|
9
|
+
check_sizeof('long')
|
10
|
+
check_sizeof('long long')
|
11
|
+
message 'checking for usability of POPCNT in GCC-style inline assembler... '
|
12
|
+
gcc_popcount = try_compile <<SRC
|
13
|
+
int main(){
|
14
|
+
long a=1, b=2;
|
15
|
+
__asm__ volatile ("POPCNT %1, %0;"
|
16
|
+
:"=r"(b)
|
17
|
+
:"r"(a)
|
18
|
+
:
|
19
|
+
);
|
20
|
+
return 0;
|
21
|
+
}
|
22
|
+
SRC
|
23
|
+
if gcc_popcount
|
24
|
+
message "yes\n"
|
25
|
+
$defs << '-DHAVE_POPCNT_GCC_ASM'
|
26
|
+
message 'checking for usability of POPCNT for long long in GCC-style inline assembler... '
|
27
|
+
gcc_ll_popcount = try_compile <<SRC
|
28
|
+
int main(){
|
29
|
+
long long a=1, b=2;
|
30
|
+
__asm__ volatile ("POPCNT %1, %0;"
|
31
|
+
:"=r"(b)
|
32
|
+
:"r"(a)
|
33
|
+
:
|
34
|
+
);
|
35
|
+
return 0;
|
36
|
+
}
|
37
|
+
SRC
|
38
|
+
if gcc_ll_popcount
|
39
|
+
message "yes\n"
|
40
|
+
$defs << '-DHAVE_POPCNT_LL_GCC_ASM'
|
41
|
+
else
|
42
|
+
message "no\n"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
message "no\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
have_func('__builtin_ctzl(1)')
|
49
|
+
|
50
|
+
create_makefile("bit_utils/bit_utils")
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#include "funcs.h"
|
2
|
+
|
3
|
+
#if SIZEOF_LONG == 8
|
4
|
+
int my_popcountl(unsigned long x){
|
5
|
+
x = ((x & 0xaaaaaaaaaaaaaaaaUL) >> 1)
|
6
|
+
+ (x & 0x5555555555555555UL);
|
7
|
+
x = ((x & 0xccccccccccccccccUL) >> 2)
|
8
|
+
+ (x & 0x3333333333333333UL);
|
9
|
+
x = ((x & 0xf0f0f0f0f0f0f0f0UL) >> 4)
|
10
|
+
+ (x & 0x0f0f0f0f0f0f0f0fUL);
|
11
|
+
x = ((x & 0xff00ff00ff00ff00UL) >> 8)
|
12
|
+
+ (x & 0x00ff00ff00ff00ffUL);
|
13
|
+
x = ((x & 0xffff0000ffff0000UL) >> 16)
|
14
|
+
+ (x & 0x0000ffff0000ffffUL);
|
15
|
+
x = ((x & 0xffffffff00000000UL) >> 32)
|
16
|
+
+ (x & 0x00000000ffffffffUL);
|
17
|
+
return (int) x;
|
18
|
+
}
|
19
|
+
#elif SIZEOF_LONG == 4
|
20
|
+
int my_popcountl(unsigned long x){
|
21
|
+
x = ((x & 0xaaaaaaaaUL) >> 1)
|
22
|
+
+ (x & 0x55555555UL);
|
23
|
+
x = ((x & 0xccccccccUL) >> 2)
|
24
|
+
+ (x & 0x33333333UL);
|
25
|
+
x = ((x & 0xf0f0f0f0UL) >> 4)
|
26
|
+
+ (x & 0x0f0f0f0fUL);
|
27
|
+
x = ((x & 0xff00ff00UL) >> 8)
|
28
|
+
+ (x & 0x00ff00ffUL);
|
29
|
+
x = ((x & 0xffff0000UL) >> 16)
|
30
|
+
+ (x & 0x0000ffffUL);
|
31
|
+
return (int) x;
|
32
|
+
}
|
33
|
+
#else
|
34
|
+
#error Unsupported architecture
|
35
|
+
#endif
|
36
|
+
|
37
|
+
size_t my_bignum_in_ulong(VALUE v){
|
38
|
+
static ID size_id = 0;
|
39
|
+
VALUE ret_val;
|
40
|
+
if(!size_id){
|
41
|
+
size_id = rb_intern("size");
|
42
|
+
}
|
43
|
+
ret_val = rb_funcall(v, size_id, 0);
|
44
|
+
return (NUM2SIZET(ret_val) + sizeof(unsigned long) - 1) / sizeof(unsigned long);
|
45
|
+
}
|
46
|
+
|
47
|
+
#ifdef HAVE___GET_CPUID
|
48
|
+
VALUE my_popcnt_p(VALUE self){
|
49
|
+
unsigned int eax, ebx, ecx = 0, edx;
|
50
|
+
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
|
51
|
+
return (ecx & bit_POPCNT) ? Qtrue : Qfalse;
|
52
|
+
}
|
53
|
+
#else
|
54
|
+
VALUE my_popcnt_p(VALUE self){
|
55
|
+
return Qfalse;
|
56
|
+
}
|
57
|
+
#endif
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#ifndef FUNCS_H_INCLUDED
|
2
|
+
#define FUNCS_H_INCLUDED 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
#ifdef HAVE_CPUID_H
|
7
|
+
#include <cpuid.h>
|
8
|
+
#endif
|
9
|
+
|
10
|
+
VALUE my_popcnt_p(VALUE self);
|
11
|
+
|
12
|
+
#ifdef HAVE_RB_BIG_PACK
|
13
|
+
#define BIG_PACK(val, ptr, cnt) rb_big_pack(val, ptr, cnt)
|
14
|
+
#elif defined(HAVE_RB_INTEGER_PACK)
|
15
|
+
#define BIG_PACK(val, ptr, cnt) rb_integer_pack(val, ptr, cnt, sizeof(long), 0, \
|
16
|
+
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER| \
|
17
|
+
INTEGER_PACK_2COMP)
|
18
|
+
#else
|
19
|
+
#error This Ruby is not supported.
|
20
|
+
#endif
|
21
|
+
|
22
|
+
|
23
|
+
#ifdef HAVE_RB_ABSINT_NUMWORDS
|
24
|
+
#define BIGNUM_IN_ULONG(v) rb_absint_numwords(v, sizeof(unsigned long), NULL)
|
25
|
+
#else
|
26
|
+
size_t my_bignum_in_ulong(VALUE v);
|
27
|
+
#define BIGNUM_IN_ULONG(v) my_bignum_in_ulong(v)
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#endif
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#include "bit_utils.h"
|
2
|
+
|
3
|
+
VALUE rb_mBitUtils;
|
4
|
+
|
5
|
+
void
|
6
|
+
Init_bit_utils(void)
|
7
|
+
{
|
8
|
+
VALUE rb_mCImpl;
|
9
|
+
rb_mBitUtils = rb_define_module("BitUtils");
|
10
|
+
rb_mCImpl = rb_define_module_under(rb_mBitUtils, "CImpl");
|
11
|
+
register_count(rb_mCImpl);
|
12
|
+
register_trailing_zeros(rb_mCImpl);
|
13
|
+
register_each_bit(rb_mCImpl);
|
14
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#include "trailing_zeros.h"
|
2
|
+
|
3
|
+
#define VAL_CTZL(n) INT2FIX((n) ? CTZL(n) : -1)
|
4
|
+
|
5
|
+
static VALUE bitutils_cimpl_trailing_zeros_fixnum(VALUE self, VALUE num){
|
6
|
+
// using only bit pattern
|
7
|
+
unsigned long ul_num = (unsigned long) NUM2LONG(num);
|
8
|
+
return VAL_CTZL(ul_num);
|
9
|
+
}
|
10
|
+
|
11
|
+
static VALUE bitutils_cimpl_trailing_zeros_bignum(VALUE self, VALUE num){
|
12
|
+
unsigned long * packed;
|
13
|
+
size_t words, i, ret;
|
14
|
+
if(FIXNUM_P(num)){
|
15
|
+
unsigned long ul_num = (unsigned long) FIX2LONG(num);
|
16
|
+
return VAL_CTZL(ul_num);
|
17
|
+
}
|
18
|
+
Check_Type(num, T_BIGNUM);
|
19
|
+
if(rb_big_cmp(num, INT2FIX(0)) == 0) return INT2FIX(-1);
|
20
|
+
words = BIGNUM_IN_ULONG(num);
|
21
|
+
if(words < ALLOCA_THRESHOLD){
|
22
|
+
packed = ALLOCA_N(unsigned long, words);
|
23
|
+
}else{
|
24
|
+
packed = ALLOC_N(unsigned long, words);
|
25
|
+
}
|
26
|
+
BIG_PACK(num, packed, words);
|
27
|
+
for( i= 0; !packed[i] ;++i){
|
28
|
+
/* do nothing */
|
29
|
+
}
|
30
|
+
ret = i * sizeof(long) * CHAR_BIT + CTZL(packed[i]);
|
31
|
+
if(words >= ALLOCA_THRESHOLD) xfree(packed);
|
32
|
+
return SIZET2NUM(ret);
|
33
|
+
}
|
34
|
+
|
35
|
+
void register_trailing_zeros(VALUE mod){
|
36
|
+
rb_define_module_function(mod, "trailing_zeros_fixnum", bitutils_cimpl_trailing_zeros_fixnum, 1);
|
37
|
+
rb_define_module_function(mod, "trailing_zeros_bignum", bitutils_cimpl_trailing_zeros_bignum, 1);
|
38
|
+
rb_define_module_function(mod, "trailing_zeros", bitutils_cimpl_trailing_zeros_bignum, 1);
|
39
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef TRAILING_ZEROS_H
|
2
|
+
#define TRAILING_ZEROS_H 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "count.h"
|
6
|
+
#include "funcs.h"
|
7
|
+
|
8
|
+
void register_trailing_zeros(VALUE mod);
|
9
|
+
|
10
|
+
#ifdef HAVE___BUILTIN_CTZL
|
11
|
+
# define CTZL(val) __builtin_ctzl(val)
|
12
|
+
#else
|
13
|
+
static inline int CTZL(unsigned long val){
|
14
|
+
return POPCOUNTL((val & (-val)) - 1);
|
15
|
+
}
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#endif
|
data/lib/bit_utils.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bit_utils/version'
|
2
|
+
require 'function_module'
|
3
|
+
|
4
|
+
require 'bit_utils/pure_ruby'
|
5
|
+
|
6
|
+
if RUBY_PLATFORM =~ /java/
|
7
|
+
require 'bit_utils/jruby_bit_length'
|
8
|
+
require 'bit_utils/jruby'
|
9
|
+
else
|
10
|
+
require 'backports/2.1.0/fixnum/bit_length'
|
11
|
+
require 'backports/2.1.0/bignum/bit_length'
|
12
|
+
require 'bit_utils/cruby'
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bit_utils'
|
2
|
+
|
3
|
+
# Core Extension for Fixnum
|
4
|
+
class Fixnum
|
5
|
+
def each_bit(&block)
|
6
|
+
BitUtils.each_bit_fixnum self, &block
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Core Extension for Bignum
|
11
|
+
class Bignum
|
12
|
+
def each_bit(&block)
|
13
|
+
BitUtils.each_bit_bignum self, &block
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bit_utils'
|
2
|
+
|
3
|
+
# Core Extension for Fixnum
|
4
|
+
class Fixnum
|
5
|
+
def trailing_zeros
|
6
|
+
BitUtils.trailing_zeros_fixnum self
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Core Extension for Bignum
|
11
|
+
class Bignum
|
12
|
+
def trailing_zeros
|
13
|
+
BitUtils.trailing_zeros_bignum self
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'function_module'
|
3
|
+
|
4
|
+
#
|
5
|
+
# module for bit utilities
|
6
|
+
#
|
7
|
+
module BitUtils
|
8
|
+
|
9
|
+
#
|
10
|
+
# module for Java-specific codes of BitUtils.
|
11
|
+
# @note not intended for direct use.
|
12
|
+
#
|
13
|
+
module JavaImpl
|
14
|
+
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def popcount(num)
|
18
|
+
case num
|
19
|
+
when Fixnum
|
20
|
+
popcount_fixnum num
|
21
|
+
when Bignum
|
22
|
+
popcount_bignum num
|
23
|
+
else
|
24
|
+
raise TypeError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def popcount_fixnum(num)
|
29
|
+
raise TypeError unless num.is_a?(::Fixnum)
|
30
|
+
count = Java::JavaLang::Long.bitCount(num)
|
31
|
+
num >= 0 ? count : count - 64
|
32
|
+
end
|
33
|
+
|
34
|
+
def popcount_bignum(num)
|
35
|
+
raise TypeError unless num.is_a?(::Bignum)
|
36
|
+
count = num.to_java.bitCount
|
37
|
+
num >= 0 ? count : -count
|
38
|
+
end
|
39
|
+
|
40
|
+
def trailing_zeros(num)
|
41
|
+
case num
|
42
|
+
when Fixnum
|
43
|
+
trailing_zeros_fixnum num
|
44
|
+
when Bignum
|
45
|
+
trailing_zeros_bignum num
|
46
|
+
else
|
47
|
+
raise TypeError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def trailing_zeros_fixnum(num)
|
53
|
+
raise TypeError unless num.is_a?(::Fixnum)
|
54
|
+
return -1 if num == 0
|
55
|
+
Java::JavaLang::Long.numberOfTrailingZeros(num)
|
56
|
+
end
|
57
|
+
|
58
|
+
def trailing_zeros_bignum(num)
|
59
|
+
raise TypeError unless num.is_a?(::Bignum)
|
60
|
+
num.to_java.getLowestSetBit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
include_module_functions JavaImpl
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
# for Bignum
|
4
|
+
|
5
|
+
unless Bignum.method_defined?(:bit_length)
|
6
|
+
class Bignum #:nodoc:
|
7
|
+
def bit_length
|
8
|
+
to_java.bitLength
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# for Fixnum
|
14
|
+
|
15
|
+
unless Fixnum.method_defined?(:bit_length) && -1.bit_length == 0
|
16
|
+
class Fixnum #:nodoc:
|
17
|
+
def bit_length
|
18
|
+
val = self < 0 ? ~self : self
|
19
|
+
64 - Java::JavaLang::Long.numberOfLeadingZeros(val)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'function_module'
|
2
|
+
|
3
|
+
#
|
4
|
+
# module for bit utilities
|
5
|
+
#
|
6
|
+
module BitUtils
|
7
|
+
|
8
|
+
#
|
9
|
+
# module for pure Ruby code of BitUtils.
|
10
|
+
# @note not intended for direct use.
|
11
|
+
#
|
12
|
+
module PureRuby
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def popcount(num)
|
17
|
+
raise TypeError unless num.is_a?(::Integer)
|
18
|
+
return -popcount(~num) if num < 0
|
19
|
+
num.to_s(2).count('1')
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_module_function :popcount_fixnum, :popcount
|
23
|
+
alias_module_function :popcount_bignum, :popcount
|
24
|
+
|
25
|
+
def trailing_zeros(num)
|
26
|
+
raise TypeError unless num.is_a?(::Integer)
|
27
|
+
return -1 if num == 0
|
28
|
+
(num & -num).bit_length - 1
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_module_function :trailing_zeros_fixnum, :trailing_zeros
|
32
|
+
alias_module_function :trailing_zeros_bignum, :trailing_zeros
|
33
|
+
|
34
|
+
def each_bit(num)
|
35
|
+
raise TypeError unless num.is_a?(::Integer)
|
36
|
+
raise RangeError if num < 0
|
37
|
+
return enum_for(__method__, num) { BitUtils.count(num) } unless block_given?
|
38
|
+
shift = 0
|
39
|
+
loop do
|
40
|
+
return if num == 0
|
41
|
+
pos = BitUtils.trailing_zeros num
|
42
|
+
yield shift + pos
|
43
|
+
num >>= pos + 1
|
44
|
+
shift += pos + 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_module_function :each_bit_fixnum, :each_bit
|
49
|
+
alias_module_function :each_bit_bignum, :each_bit
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
include_module_functions PureRuby
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bit_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Jkr2255
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 0.1.1
|
19
|
+
name: function_module
|
20
|
+
prerelease: false
|
21
|
+
type: :runtime
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.11'
|
33
|
+
name: bundler
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '10.0'
|
47
|
+
name: rake
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
name: rake-compiler
|
62
|
+
prerelease: false
|
63
|
+
type: :development
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.0'
|
75
|
+
name: rspec
|
76
|
+
prerelease: false
|
77
|
+
type: :development
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- magnesium.oxide.play@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- benchmark/count.rb
|
98
|
+
- benchmark/each_bit.rb
|
99
|
+
- benchmark/trailing_zeros.rb
|
100
|
+
- bin/console
|
101
|
+
- bin/setup
|
102
|
+
- bit_utils.gemspec
|
103
|
+
- ext/bit_utils/bit_utils.h
|
104
|
+
- ext/bit_utils/count.c
|
105
|
+
- ext/bit_utils/count.h
|
106
|
+
- ext/bit_utils/each_bit.c
|
107
|
+
- ext/bit_utils/each_bit.h
|
108
|
+
- ext/bit_utils/extconf.rb
|
109
|
+
- ext/bit_utils/funcs.c
|
110
|
+
- ext/bit_utils/funcs.h
|
111
|
+
- ext/bit_utils/init.c
|
112
|
+
- ext/bit_utils/trailing_zeros.c
|
113
|
+
- ext/bit_utils/trailing_zeros.h
|
114
|
+
- lib/bit_utils.rb
|
115
|
+
- lib/bit_utils/core_ext.rb
|
116
|
+
- lib/bit_utils/core_ext/each_bit.rb
|
117
|
+
- lib/bit_utils/core_ext/popcount.rb
|
118
|
+
- lib/bit_utils/core_ext/trailing_zeros.rb
|
119
|
+
- lib/bit_utils/cruby.rb
|
120
|
+
- lib/bit_utils/jruby.rb
|
121
|
+
- lib/bit_utils/jruby_bit_length.rb
|
122
|
+
- lib/bit_utils/pure_ruby.rb
|
123
|
+
- lib/bit_utils/version.rb
|
124
|
+
homepage: https://github.com/jkr2255/bit_utils
|
125
|
+
licenses:
|
126
|
+
- MIT
|
127
|
+
metadata: {}
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 1.9.3
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubyforge_project:
|
144
|
+
rubygems_version: 2.6.4
|
145
|
+
signing_key:
|
146
|
+
specification_version: 4
|
147
|
+
summary: Utility methods for manipulating bits within Integer.
|
148
|
+
test_files: []
|