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 CHANGED
@@ -38,32 +38,70 @@ b.to_bits
38
38
  => "00001000"
39
39
  ```
40
40
 
41
- Index assignment and retrieval:
41
+ String-based assignment and retrieval:
42
42
 
43
43
  ```ruby
44
44
  b = Bitwise.new
45
- b.indexes = [1, 10, 100]
45
+ b.value = "abc"
46
46
 
47
- b.to_bits
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
- b.size
54
- => 13
55
+ Index-based assignment and retrieval:
55
56
 
56
- b.set_at(20)
57
+ ```ruby
58
+ b = Bitwise.new
59
+ b.indexes = [1, 2, 4, 8, 16]
57
60
 
58
61
  b.to_bits
59
- => "01000000001000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001000"
62
+ => "011010001000000010000000"
63
+ b.indexes
64
+ => [1, 2, 4, 8, 16]
65
+ b.cardinality
66
+ => 5
60
67
 
61
- b.value.unpack('C*')
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
- => 4
75
+ => 6
76
+ ```
66
77
 
67
- b.indexes
68
- => [1, 10, 20, 100]
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.2
1
+ 0.2.0
data/bitwise.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "bitwise"
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kenn Ejima"]
@@ -1,8 +1,8 @@
1
- #include "ruby.h"
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
- int min_len = RSTRING_LEN(min);
29
- for (i = 0; i < RSTRING_LEN(max); i++) {
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 bw_population_count(VALUE self, VALUE str) {
46
- int count, i;
47
- unsigned char *buffer = RSTRING_PTR(str);
48
- count = 0;
49
- for (i = 0; i < RSTRING_LEN(str); i++) {
50
- count += COUNT_TABLE[buffer[i]];
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 INT2NUM(count);
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, "population_count", bw_population_count, 1);
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
- it "should set and clear" do
10
- @bitwise.to_bits.should == '00000000'
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
- @bitwise.set_at 1
13
- @bitwise.set_at 2
14
- @bitwise.set_at 3
15
- @bitwise.set_at 5
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
- @bitwise.clear_at(1)
20
- @bitwise.clear_at(3)
21
- @bitwise.to_bits.should == '00100100'
22
- @bitwise.cardinality.should == 2
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
- it "should set by indexes" do
26
- @bitwise.indexes = [1,10]
27
- @bitwise.indexes.should == [1,10]
28
- @bitwise.to_bits.should == '0100000000100000'
29
- @bitwise.cardinality.should == 2
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.1.2
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: &2156349640 !ruby/object:Gem::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: *2156349640
24
+ version_requirements: *2159343420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &2156102560 !ruby/object:Gem::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: *2156102560
35
+ version_requirements: *2159341700
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jeweler
38
- requirement: &2156099600 !ruby/object:Gem::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: *2156099600
46
+ version_requirements: *2159340960
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake-compiler
49
- requirement: &2156095000 !ruby/object:Gem::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: *2156095000
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: []