bitwise 0.1.2 → 0.2.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.
- data/README.md +53 -15
- data/VERSION +1 -1
- data/bitwise.gemspec +1 -1
- data/ext/bitwise/bitwise.c +37 -15
- data/lib/bitwise.rb +15 -0
- data/spec/bitwise_spec.rb +73 -17
- metadata +9 -9
data/README.md
CHANGED
@@ -38,32 +38,70 @@ b.to_bits
|
|
38
38
|
=> "00001000"
|
39
39
|
```
|
40
40
|
|
41
|
-
|
41
|
+
String-based assignment and retrieval:
|
42
42
|
|
43
43
|
```ruby
|
44
44
|
b = Bitwise.new
|
45
|
-
b.
|
45
|
+
b.value = "abc"
|
46
46
|
|
47
|
-
b.
|
48
|
-
=> "01000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000"
|
49
|
-
|
50
|
-
b.cardinality
|
47
|
+
b.size
|
51
48
|
=> 3
|
49
|
+
b.to_bits
|
50
|
+
=> "011000010110001001100011"
|
51
|
+
b.value.unpack('C*')
|
52
|
+
=> [97, 98, 99]
|
53
|
+
```
|
52
54
|
|
53
|
-
|
54
|
-
=> 13
|
55
|
+
Index-based assignment and retrieval:
|
55
56
|
|
56
|
-
|
57
|
+
```ruby
|
58
|
+
b = Bitwise.new
|
59
|
+
b.indexes = [1, 2, 4, 8, 16]
|
57
60
|
|
58
61
|
b.to_bits
|
59
|
-
=> "
|
62
|
+
=> "011010001000000010000000"
|
63
|
+
b.indexes
|
64
|
+
=> [1, 2, 4, 8, 16]
|
65
|
+
b.cardinality
|
66
|
+
=> 5
|
60
67
|
|
61
|
-
b.
|
62
|
-
=> [64, 32, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]
|
68
|
+
b.set_at(10)
|
63
69
|
|
70
|
+
b.to_bits
|
71
|
+
=> "011010001010000010000000"
|
72
|
+
b.indexes
|
73
|
+
=> [1, 2, 4, 8, 10, 16]
|
64
74
|
b.cardinality
|
65
|
-
=>
|
75
|
+
=> 6
|
76
|
+
```
|
66
77
|
|
67
|
-
|
68
|
-
|
78
|
+
NOT, OR, AND and XOR:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
b1 = Bitwise.new
|
82
|
+
b2 = Bitwise.new
|
83
|
+
b1.indexes = [1, 2, 3, 5, 6]
|
84
|
+
b2.indexes = [1, 2, 4, 8, 16]
|
85
|
+
|
86
|
+
(~b1).indexes
|
87
|
+
=> [0, 4, 7]
|
88
|
+
(b1 | b2).indexes
|
89
|
+
=> [1, 2, 3, 4, 5, 6, 8, 16]
|
90
|
+
(b1 & b2).indexes
|
91
|
+
=> [1, 2]
|
92
|
+
(b1 ^ b2).indexes
|
93
|
+
=> [3, 4, 5, 6, 8, 16]
|
94
|
+
```
|
95
|
+
|
96
|
+
As a bonus, `Bitwise#string_not`, `Bitwise#string_union`, `Bitwise#string_intersect`, and `Bitwise#string_xor` can be used as a standalone method to work with any binary string.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Bitwise.string_not "\xF0"
|
100
|
+
=> "\x0F"
|
101
|
+
Bitwise.string_union "\xF0","\xFF"
|
102
|
+
=> "\xFF"
|
103
|
+
Bitwise.string_intersect "\xF0","\xFF"
|
104
|
+
=> "\xF0"
|
105
|
+
Bitwise.string_xor "\xF0","\xFF"
|
106
|
+
=> "\x0F"
|
69
107
|
```
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bitwise.gemspec
CHANGED
data/ext/bitwise/bitwise.c
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#include
|
1
|
+
#include <ruby.h>
|
2
2
|
|
3
3
|
VALUE BitwiseClass;
|
4
4
|
|
5
|
-
int COUNT_TABLE[] = {
|
5
|
+
static int COUNT_TABLE[] = {
|
6
6
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
7
7
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
8
8
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
@@ -21,20 +21,39 @@ int COUNT_TABLE[] = {
|
|
21
21
|
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
|
22
22
|
};
|
23
23
|
|
24
|
+
static VALUE bw_population_count(VALUE self, VALUE str) {
|
25
|
+
int count, i;
|
26
|
+
unsigned char *buffer = RSTRING_PTR(str);
|
27
|
+
count = 0;
|
28
|
+
for (i = 0; i < RSTRING_LEN(str); i++) {
|
29
|
+
count += COUNT_TABLE[buffer[i]];
|
30
|
+
}
|
31
|
+
return INT2NUM(count);
|
32
|
+
}
|
33
|
+
|
34
|
+
static VALUE bw_string_not(VALUE self, VALUE str)
|
35
|
+
{
|
36
|
+
VALUE result = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
|
37
|
+
int i;
|
38
|
+
for (i = 0; i < RSTRING_LEN(str); i++) {
|
39
|
+
RSTRING_PTR(result)[i] = ~RSTRING_PTR(str)[i];
|
40
|
+
}
|
41
|
+
return result;
|
42
|
+
}
|
43
|
+
|
24
44
|
static VALUE bw_string_union(VALUE self, VALUE max, VALUE min)
|
25
45
|
{
|
26
|
-
VALUE result = rb_str_new(RSTRING_PTR(max), RSTRING_LEN(max));
|
46
|
+
VALUE result = rb_str_new(RSTRING_PTR(max), RSTRING_LEN(max));
|
27
47
|
int i;
|
28
|
-
|
29
|
-
|
30
|
-
RSTRING_PTR(result)[i] |= ((i < min_len) ? RSTRING_PTR(min)[i] : 0);
|
48
|
+
for (i = 0; i < RSTRING_LEN(min); i++) {
|
49
|
+
RSTRING_PTR(result)[i] |= RSTRING_PTR(min)[i];
|
31
50
|
}
|
32
51
|
return result;
|
33
52
|
}
|
34
53
|
|
35
54
|
static VALUE bw_string_intersect(VALUE self, VALUE max, VALUE min)
|
36
55
|
{
|
37
|
-
VALUE result = rb_str_new(RSTRING_PTR(min), RSTRING_LEN(min));
|
56
|
+
VALUE result = rb_str_new(RSTRING_PTR(min), RSTRING_LEN(min));
|
38
57
|
int i;
|
39
58
|
for (i = 0; i < RSTRING_LEN(min); i++) {
|
40
59
|
RSTRING_PTR(result)[i] &= RSTRING_PTR(max)[i];
|
@@ -42,20 +61,23 @@ static VALUE bw_string_intersect(VALUE self, VALUE max, VALUE min)
|
|
42
61
|
return result;
|
43
62
|
}
|
44
63
|
|
45
|
-
static VALUE
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
64
|
+
static VALUE bw_string_xor(VALUE self, VALUE max, VALUE min)
|
65
|
+
{
|
66
|
+
VALUE result = rb_str_new(RSTRING_PTR(max), RSTRING_LEN(max));
|
67
|
+
int i;
|
68
|
+
int min_len = RSTRING_LEN(min);
|
69
|
+
for (i = 0; i < RSTRING_LEN(max); i++) {
|
70
|
+
RSTRING_PTR(result)[i] ^= ((i < min_len) ? RSTRING_PTR(min)[i] : 0);
|
51
71
|
}
|
52
|
-
return
|
72
|
+
return result;
|
53
73
|
}
|
54
74
|
|
55
75
|
void Init_bitwise()
|
56
76
|
{
|
57
77
|
BitwiseClass = rb_define_class("Bitwise", rb_cObject);
|
78
|
+
rb_define_singleton_method(BitwiseClass, "population_count", bw_population_count, 1);
|
79
|
+
rb_define_singleton_method(BitwiseClass, "string_not", bw_string_not, 1);
|
58
80
|
rb_define_singleton_method(BitwiseClass, "string_union", bw_string_union, 2);
|
59
81
|
rb_define_singleton_method(BitwiseClass, "string_intersect", bw_string_intersect, 2);
|
60
|
-
rb_define_singleton_method(BitwiseClass, "
|
82
|
+
rb_define_singleton_method(BitwiseClass, "string_xor", bw_string_xor, 2);
|
61
83
|
}
|
data/lib/bitwise.rb
CHANGED
@@ -50,6 +50,13 @@ class Bitwise
|
|
50
50
|
@byte = @value.getbyte(@div)
|
51
51
|
end
|
52
52
|
|
53
|
+
def not
|
54
|
+
result = Bitwise.new
|
55
|
+
result.value = Bitwise.string_not(self.value)
|
56
|
+
result
|
57
|
+
end
|
58
|
+
alias :~ :not
|
59
|
+
|
53
60
|
def intersect(other)
|
54
61
|
min, max = [ self.value, other.value ].sort_by{|i| i.bytesize }
|
55
62
|
result = Bitwise.new
|
@@ -66,6 +73,14 @@ class Bitwise
|
|
66
73
|
end
|
67
74
|
alias :| :union
|
68
75
|
|
76
|
+
def xor(other)
|
77
|
+
min, max = [ self.value, other.value ].sort_by{|i| i.bytesize }
|
78
|
+
result = Bitwise.new
|
79
|
+
result.value = Bitwise.string_xor(max, min)
|
80
|
+
result
|
81
|
+
end
|
82
|
+
alias :^ :xor
|
83
|
+
|
69
84
|
def value=(string)
|
70
85
|
@value = string.force_encoding(Encoding::ASCII_8BIT)
|
71
86
|
@value.bytesize
|
data/spec/bitwise_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# coding: ascii-8bit
|
2
|
+
|
1
3
|
require 'bitwise'
|
2
4
|
require 'set'
|
3
5
|
|
@@ -6,27 +8,81 @@ describe Bitwise do
|
|
6
8
|
@bitwise = Bitwise.new(1)
|
7
9
|
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
+
describe "assignment and retrieval" do
|
12
|
+
it "bit-based" do
|
13
|
+
@bitwise.to_bits.should == '00000000'
|
14
|
+
|
15
|
+
@bitwise.set_at 1
|
16
|
+
@bitwise.set_at 4
|
17
|
+
@bitwise.to_bits.should == '01001000'
|
18
|
+
@bitwise.cardinality.should == 2
|
11
19
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@bitwise.to_bits.should == '01110100'
|
17
|
-
@bitwise.cardinality.should == 4
|
20
|
+
@bitwise.clear_at(1)
|
21
|
+
@bitwise.to_bits.should == '00001000'
|
22
|
+
@bitwise.cardinality.should == 1
|
23
|
+
end
|
18
24
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
25
|
+
it "string-based" do
|
26
|
+
@bitwise.value = 'abc'
|
27
|
+
@bitwise.size.should == 3
|
28
|
+
@bitwise.to_bits.should == '011000010110001001100011'
|
29
|
+
@bitwise.cardinality.should == 10
|
30
|
+
end
|
31
|
+
|
32
|
+
it "index-based" do
|
33
|
+
@bitwise.indexes = [1, 2, 4, 8, 16]
|
34
|
+
@bitwise.to_bits.should == '011010001000000010000000'
|
35
|
+
@bitwise.indexes.should == [1, 2, 4, 8, 16]
|
36
|
+
@bitwise.cardinality.should == 5
|
37
|
+
@bitwise.set_at 10
|
38
|
+
@bitwise.to_bits.should == '011010001010000010000000'
|
39
|
+
@bitwise.indexes.should == [1, 2, 4, 8, 10, 16]
|
40
|
+
@bitwise.cardinality.should == 6
|
41
|
+
end
|
23
42
|
end
|
24
43
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
44
|
+
describe "operators" do
|
45
|
+
before do
|
46
|
+
@b1 = Bitwise.new
|
47
|
+
@b2 = Bitwise.new
|
48
|
+
@b1.indexes = [1, 2, 3, 5, 6]
|
49
|
+
@b2.indexes = [1, 2, 4, 8, 16]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "NOT" do
|
53
|
+
@b1.not.indexes.should == [0, 4, 7]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "OR" do
|
57
|
+
@b1.union(@b2).indexes.should == [1, 2, 3, 4, 5, 6, 8, 16]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "AND" do
|
61
|
+
@b1.intersect(@b2).indexes.should == [1, 2]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "XOR" do
|
65
|
+
@b1.xor(@b2).indexes.should == [3, 4, 5, 6, 8, 16]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "standalone" do
|
70
|
+
it "NOT" do
|
71
|
+
Bitwise.string_not("\xF0").should == "\x0F"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "OR" do
|
75
|
+
Bitwise.string_union("\xF0","\xFF").should == "\xFF"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "AND" do
|
79
|
+
Bitwise.string_intersect("\xF0","\xFF").should == "\xF0"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "XOR" do
|
83
|
+
Bitwise.string_xor("\xF0","\xFF").should == "\x0F"
|
84
|
+
end
|
85
|
+
|
30
86
|
end
|
31
87
|
|
32
88
|
describe "benchmark" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitwise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-12-13 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2159343420 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2159343420
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &2159341700 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2159341700
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: jeweler
|
38
|
-
requirement: &
|
38
|
+
requirement: &2159340960 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2159340960
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake-compiler
|
49
|
-
requirement: &
|
49
|
+
requirement: &2159340120 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2159340120
|
58
58
|
description: Fast, memory efficient bitwise operations on large binary strings
|
59
59
|
email: kenn.ejima@gmail.com
|
60
60
|
executables: []
|