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 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: []