bitwise 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|