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.
@@ -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
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.6
6
+ - 2.2.4
7
+ - 2.3.1
8
+ - jruby-1.7.20
9
+ - jruby-9.0.4.0
10
+ - jruby-9.1.0.0
11
+ - rbx-3.27
12
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bit_utils.gemspec
4
+ gemspec
@@ -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.
@@ -0,0 +1,78 @@
1
+ # BitUtils
2
+
3
+ [![Build Status](https://travis-ci.org/jkr2255/bit_utils.svg?branch=master)](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
+
@@ -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
@@ -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
+
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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,10 @@
1
+ #ifndef BIT_UTILS_H
2
+ #define BIT_UTILS_H 1
3
+
4
+ #include "ruby.h"
5
+ #include "count.h"
6
+ #include "trailing_zeros.h"
7
+ #include "funcs.h"
8
+ #include "each_bit.h"
9
+
10
+ #endif /* BIT_UTILS_H */
@@ -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,10 @@
1
+ #ifndef EACH_BIT_H_INCLUDED
2
+ #define EACH_BIT_H_INCLUDED 1
3
+
4
+ #include "ruby.h"
5
+ #include "funcs.h"
6
+ #include "trailing_zeros.h"
7
+
8
+ void register_each_bit(VALUE mod);
9
+
10
+ #endif
@@ -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
@@ -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,3 @@
1
+ require 'bit_utils/core_ext/popcount'
2
+ require 'bit_utils/core_ext/each_bit'
3
+ require 'bit_utils/core_ext/trailing_zeros'
@@ -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 popcount
6
+ BitUtils.popcount_fixnum self
7
+ end
8
+ end
9
+
10
+ # Core Extension for Bignum
11
+ class Bignum
12
+ def popcount
13
+ BitUtils.popcount_bignum self
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,6 @@
1
+ require 'bit_utils/bit_utils'
2
+ require 'function_module'
3
+
4
+ module BitUtils
5
+ include_module_functions CImpl
6
+ 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
@@ -0,0 +1,3 @@
1
+ module BitUtils
2
+ VERSION = "0.1.1"
3
+ 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: []