fast_xor 1.0.1 → 1.1.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.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = String XOR Ruby Extension
2
2
 
3
- +fast_xor+ is a simple extension which provides fast in-place String XOR functions (suitable for cryptography).
3
+ +fast_xor+ is a simple extension which provides fast in-place String XOR functions, suitable for cryptography.
4
4
 
5
5
  == How do you use it?
6
6
 
@@ -18,16 +18,16 @@
18
18
 
19
19
  == How fast is "Fast"?
20
20
 
21
- On my computer, about 1,000x faster than pure Ruby (your mileage my vary):
21
+ Almost 50,000x faster than pure Ruby, on my machine (your mileage my vary):
22
22
 
23
- $ ruby test/benchmark.rb
24
- user system total real
25
- Ruby: 2.070000 0.930000 3.000000 ( 3.004088)
26
- C : 0.010000 0.000000 0.010000 ( 0.003045)
23
+ $ ./benchmark
24
+ user system total real
25
+ Ruby : 6.100000 0.010000 6.110000 ( 6.307756)
26
+ C (x1000): 0.140000 0.000000 0.140000 ( 0.144665)
27
27
 
28
28
 
29
29
  Author:: Steve Sloan (mailto:steve@finagle.org)
30
30
  Website:: http://github.com/CodeMonkeySteve/fast_xor
31
- Copyright:: Copyright (c) 2009 Steve Sloan
31
+ Copyright:: Copyright (c) 2009-2010 Steve Sloan
32
32
  License:: MIT
33
33
 
data/benchmark ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.dirname(__FILE__)+'/lib'
3
+ require 'benchmark'
4
+ require 'xor'
5
+
6
+ class String
7
+ def slow_xor!(other)
8
+ i = 0
9
+ other.each_byte.with_index { |b, i| self[i] = (self[i].ord ^ b).chr }
10
+ end
11
+
12
+ require 'xor'
13
+ alias_method :fast_xor!, :xor!
14
+ end
15
+
16
+ a = ([255].pack('C')) * (2**17) # 128k
17
+ b = a.dup
18
+ n = (ARGV.first || 10).to_i
19
+
20
+ Benchmark.bm do |x|
21
+ x.report('Ruby :') do n.times { a.slow_xor! b } end
22
+ x.report('C (x1000):') do (n*1000).times { a.fast_xor! b } end
23
+ end
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile 'xor'
@@ -1,6 +1,14 @@
1
1
  #include <stdio.h>
2
2
  #include <ruby.h>
3
3
 
4
+ /* Backward compatibility with Ruby 1.8 */
5
+ #ifndef RSTRING_PTR
6
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
7
+ #endif
8
+ #ifndef RSTRING_LEN
9
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
10
+ #endif
11
+
4
12
  VALUE string_xor( int argc, VALUE *argv, VALUE self ) {
5
13
  const char *src = 0;
6
14
  char *dest = 0 ;
@@ -11,12 +19,12 @@ VALUE string_xor( int argc, VALUE *argv, VALUE self ) {
11
19
  return Qnil;
12
20
  }
13
21
 
14
- dest = STR2CSTR(self);
15
- length = RSTRING(self)->len;
22
+ dest = RSTRING_PTR(self);
23
+ length = RSTRING_LEN(self);
16
24
 
17
25
  if ( TYPE(argv[0]) == T_STRING ) {
18
- src = STR2CSTR(argv[0]);
19
- size_t l = RSTRING(argv[0])->len;
26
+ src = RSTRING_PTR(argv[0]);
27
+ size_t l = RSTRING_LEN(argv[0]);
20
28
  if ( l < length )
21
29
  length = l;
22
30
  } else {
@@ -32,8 +40,8 @@ VALUE string_xor( int argc, VALUE *argv, VALUE self ) {
32
40
  const char *src2 = 0;
33
41
 
34
42
  if ( TYPE(argv[1]) == T_STRING ) {
35
- src2 = STR2CSTR(argv[1]);
36
- size_t l = RSTRING(argv[1])->len;
43
+ src2 = RSTRING_PTR(argv[1]);
44
+ size_t l = RSTRING_LEN(argv[1]);
37
45
  if ( l < length )
38
46
  length = l;
39
47
  } else {
data/spec/xor_spec.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'xor'
2
+
3
+ describe String do
4
+ before do
5
+ @len = 16
6
+ @zero = [0x00].pack('C') * @len
7
+ @one = [0xFF].pack('C') * @len
8
+ @x = (0...@len).collect { rand 256 }.pack('C*')
9
+ @invx = (0...@len).collect { |i| @x[i].ord ^ 0xFF }.pack('C*')
10
+ end
11
+
12
+ it 'XORs two strings' do
13
+ @x.dup.xor!(@x) .should == @zero
14
+ @x.dup.xor!(@invx).should == @one
15
+ @x.dup.xor!(@zero).should == @x
16
+ @x.dup.xor!(@one) .should == @invx
17
+ end
18
+
19
+ it 'XORs three strings' do
20
+ @x.dup.xor!(@x, @x) .should == @x
21
+ @x.dup.xor!(@x, @invx).should == @invx
22
+ @x.dup.xor!(@x, @zero).should == @zero
23
+ @x.dup.xor!(@x, @one) .should == @one
24
+
25
+ @x.dup.xor!(@invx, @x) .should == @invx
26
+ @x.dup.xor!(@invx, @invx).should == @x
27
+ @x.dup.xor!(@invx, @zero).should == @one
28
+ @x.dup.xor!(@invx, @one) .should == @zero
29
+
30
+ @x.dup.xor!(@zero, @x) .should == @zero
31
+ @x.dup.xor!(@zero, @invx).should == @one
32
+ @x.dup.xor!(@zero, @one) .should == @invx
33
+ @x.dup.xor!(@zero, @zero).should == @x
34
+
35
+ @x.dup.xor!(@one, @x) .should == @one
36
+ @x.dup.xor!(@one, @invx).should == @zero
37
+ @x.dup.xor!(@one, @zero).should == @invx
38
+ @x.dup.xor!(@one, @one) .should == @x
39
+ end
40
+ end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_xor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ - 0
9
+ version: 1.1.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Steve Sloan
@@ -9,25 +14,65 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-10-26 00:00:00 -07:00
17
+ date: 2010-10-29 00:00:00 -07:00
13
18
  default_executable:
14
- dependencies: []
15
-
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rake-compiler
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 2
55
+ - 0
56
+ - 1
57
+ version: 2.0.1
58
+ type: :development
59
+ prerelease: false
60
+ version_requirements: *id003
16
61
  description: Provides a C-optimized method for in-place XORing of two (or three) strings
17
62
  email: steve@finagle.org
18
63
  executables: []
19
64
 
20
65
  extensions:
21
- - Rakefile
66
+ - ext/xor/extconf.rb
22
67
  extra_rdoc_files:
23
68
  - README.rdoc
24
69
  files:
25
70
  - MIT-LICENSE
26
71
  - README.rdoc
27
- - ext/xor.c
28
- - rake/extensiontask.rb
29
- - test/benchmark.rb
30
- - test/test_xor.rb
72
+ - benchmark
73
+ - ext/xor/xor.c
74
+ - ext/xor/extconf.rb
75
+ - spec/xor_spec.rb
31
76
  has_rdoc: true
32
77
  homepage: http://github.com/CodeMonkeySteve/fast_xor
33
78
  licenses: []
@@ -36,26 +81,31 @@ post_install_message:
36
81
  rdoc_options:
37
82
  - --charset=UTF-8
38
83
  require_paths:
39
- - ext
84
+ - lib/fast_xor
40
85
  required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
41
87
  requirements:
42
88
  - - ">="
43
89
  - !ruby/object:Gem::Version
90
+ hash: 1119320670912771159
91
+ segments:
92
+ - 0
44
93
  version: "0"
45
- version:
46
94
  required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
47
96
  requirements:
48
97
  - - ">="
49
98
  - !ruby/object:Gem::Version
99
+ hash: 1119320670912771159
100
+ segments:
101
+ - 0
50
102
  version: "0"
51
- version:
52
103
  requirements: []
53
104
 
54
105
  rubyforge_project:
55
- rubygems_version: 1.3.5
106
+ rubygems_version: 1.3.7
56
107
  signing_key:
57
108
  specification_version: 3
58
109
  summary: Fast String XOR operator
59
110
  test_files:
60
- - test/benchmark.rb
61
- - test/test_xor.rb
111
+ - spec/xor_spec.rb
data/Rakefile DELETED
@@ -1,46 +0,0 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/extensiontask'
4
- require 'rake/testtask'
5
- require 'jeweler'
6
-
7
- namespace 'xor' do
8
- desc "Build the XOR extension"
9
- Rake::ExtensionTask.new :xor do |t|
10
- t.dir = 'ext'
11
- end
12
- end
13
-
14
- task :test => 'xor:xor'
15
- Rake::TestTask.new do |t|
16
- t.libs << 'ext'
17
- t.test_files = FileList['test/test_*.rb']
18
- t.verbose = true
19
- end
20
-
21
- task :all => ['xor:xor', :test]
22
- task :default => :all
23
-
24
- Jeweler::Tasks.new do |g|
25
- g.name = 'fast_xor'
26
- g.summary = 'Fast String XOR operator'
27
- g.description = 'Provides a C-optimized method for in-place XORing of two (or three) strings'
28
- g.email = 'steve@finagle.org'
29
- g.homepage = 'http://github.com/CodeMonkeySteve/fast_xor'
30
- g.authors = ['Steve Sloan']
31
-
32
- g.files = %w(
33
- README.rdoc MIT-LICENSE
34
- rake/extensiontask.rb
35
- ext/xor.c
36
- test/test_xor.rb
37
- test/benchmark.rb
38
- )
39
- g.extensions = ['Rakefile']
40
- g.require_paths = %w(ext)
41
-
42
- # g.has_rdoc = true
43
- # g.rdoc_options = %w| --line-numbers --inline-source --main README.rdoc |
44
- # g.extra_rdoc_files = %w| README.rdoc |
45
- end
46
- Jeweler::GemcutterTasks.new
@@ -1,191 +0,0 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/tasklib'
4
-
5
- # Rake tasks to build Ruby extensions
6
-
7
- module Rake
8
-
9
- # Create a build task that will generate a Ruby extension (e.g. .so) from one or more
10
- # C (.c) or C++ (.cc, .cpp, .cxx) files, and is intended as a replcaement for mkmf.
11
- # It determines platform-specific settings (e.g. file extensions, compiler flags, etc.)
12
- # from rbconfig (note: examples assume *nix file extensions).
13
- #
14
- # *Note*: Strings vs Symbols
15
- # In places where filenames are expected (e.g. lib_name and objs), Strings are used
16
- # as verbatim filenames, while, Symbols have the platform-dependant extension
17
- # appended (e.g. '.so' for libraries and '.o' for objects). Also, only Symbols
18
- # have #dir prepended to them.
19
- #
20
- # Example:
21
- # desc "build sample extension"
22
- # # build sample.so (from foo.{c,cc,cxx,cpp}, through foo.o)
23
- # Rake::ExtensionTask.new :sample => :foo do |t|
24
- # # all extension files under this directory
25
- # t.dir = 'ext'
26
- # # link libraries (libbar.so)
27
- # t.link_libs << 'bar'
28
- # end
29
- #
30
- # Author:: Steve Sloan (mailto:steve@finagle.org)
31
- # Copyright:: Copyright (c) 2006 Steve Sloan
32
- # License:: GPL
33
-
34
- class ExtensionTask < Rake::TaskLib
35
- # The name of the extension
36
- attr_accessor :name
37
-
38
- # The filename of the extension library file (e.g. 'extension.so')
39
- attr_accessor :lib_name
40
-
41
- # Object files to build and link into the extension.
42
- attr_accessor :objs
43
-
44
- # The directory where the extension files (source, output, and
45
- # intermediate) are stored.
46
- attr_accessor :dir
47
-
48
- # Environment configuration -- i.e. CONFIG from rbconfig, with a few other
49
- # settings, and converted to lowercase-symbols.
50
- attr_accessor :env
51
-
52
- # Additional link libraries
53
- attr_accessor :link_libs
54
-
55
- # Same arguments as Rake::define_task
56
- def initialize( args, &blk )
57
- @env = @@DefaultEnv.dup
58
- @name, @objs = resolve_args(args)
59
- set_defaults
60
- yield self if block_given?
61
- define_tasks
62
- end
63
-
64
- # Generate default values. This is called from initialize _before_ the
65
- # yield block.
66
- #
67
- # Defaults:
68
- # - lib_name: name.so
69
- # - objs: name.o (<- name.{c,cxx,cpp,cc})
70
- # - dir: .
71
- # - link_libs: <none>
72
- def set_defaults
73
- @lib_name ||= name.to_sym
74
- @objs = [name.to_sym] unless @objs and @objs.any?
75
- @dir ||= '.'
76
- @link_libs ||= []
77
- end
78
-
79
- # Defines the library task.
80
- def define_tasks
81
- output_objs = @objs.collect { |obj| filepath obj, :objext }
82
- output_lib = filepath lib_name, :dlext
83
-
84
- task name => output_lib
85
-
86
- file output_lib => output_objs do |t|
87
- sh_cmd :ldshared, :dldflags, :ldflags,
88
- {'-L' => :libdirs}, '-o', output_lib,
89
- output_objs.join(' '),
90
- link_libs.join(' '),
91
- :libs, :dldlibs, :librubyarg_shared
92
- end
93
-
94
- CLEAN.include output_objs
95
- CLOBBER.include output_lib
96
- define_rules
97
- end
98
-
99
- # Defines C and C++ source-to-object rules, using the source extensions from env.
100
- def define_rules
101
- for ext in env[:c_exts]
102
- Rake::Task.create_rule '.'+env[:objext] => '.'+ext do |r|
103
- sh_cmd :cc, :cflags, :cppflags, {'-D' => :defines}, {'-I' => :includedirs}, {'-I' => :topdir},
104
- '-c', '-o', r.name, r.sources
105
- end
106
- end
107
-
108
- for ext in env[:cpp_exts]
109
- Rake::Task.create_rule '.'+env[:objext] => '.'+ext do |r|
110
- sh_cmd :cxx, :cxxflags, :cppflags, {'-D' => :defines}, {'-I' => :includedirs}, {'-I' => :topdir},
111
- '-o', r.name, '-c', r.sources
112
- end
113
- end
114
- end
115
-
116
- class << self
117
- # The default environment for all extensions.
118
- @@DefaultEnv = {}
119
- def env
120
- @@DefaultEnv
121
- end
122
- def env=(e)
123
- @@DefaultEnv = e
124
- end
125
-
126
- Config::CONFIG.merge(ENV).each { |k, v| @@DefaultEnv[k.downcase.to_sym] = v }
127
- @@DefaultEnv = {
128
- :cxx => 'c++',
129
- :cxxflags => '',
130
- :c_exts => ['c'],
131
- :cpp_exts => ['cc', 'cxx', 'cpp'],
132
- :includedirs => [],
133
- :libdirs => [],
134
- }.update(@@DefaultEnv)
135
- end
136
-
137
- protected
138
-
139
- # Handles convenience filenames:
140
- # * f (String) => f
141
- # * f (Symbol) => dir/f.ext
142
- def filepath( f, ext )
143
- ext = env[ext] if Symbol === ext
144
- Symbol === f ? File.join( dir, "#{f}.#{ext}" ) : f
145
- end
146
-
147
- # Convenience function for cnstructing command lines for build tools.
148
- def optify( *opts )
149
- return optify(*opts.first) if opts.size == 1 and opts.first.kind_of? Array
150
- opts.collect do |opt|
151
- case opt
152
- when String then opt
153
- when Symbol then optify env[opt]
154
- when Hash
155
- opt.collect do |k, v|
156
- v = env[v] if v.kind_of? Symbol
157
- if v.kind_of? Array
158
- optify v.collect { |w| k.to_s + w.to_s }
159
- elsif v
160
- k.to_s + v.to_s
161
- end
162
- end
163
- else
164
- opt.to_s
165
- end
166
- end.join(' ').squeeze(' ')
167
- end
168
-
169
- def sh_cmd( cmd, *opts )
170
- sh optify( cmd, *opts )
171
- end
172
-
173
- # For some reason, Rake::TaskManager.resolve_args can't be found, so snarf it.
174
- def resolve_args(args)
175
- case args
176
- when Hash
177
- fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
178
- fail "No Task Name Given" if args.size < 1
179
- task_name = args.keys[0]
180
- deps = args[task_name]
181
- deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
182
- else
183
- task_name = args
184
- deps = []
185
- end
186
- [task_name, deps]
187
- end
188
-
189
- end
190
-
191
- end
data/test/benchmark.rb DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $: << File.dirname($0) + '/../ext'
3
- require 'benchmark'
4
-
5
- class String
6
- def slow_xor!(other)
7
- i = 0
8
- other.each_byte { |b| self[i] ^= b ; i += 1 }
9
- end
10
-
11
- require 'xor'
12
- alias_method :fast_xor!, :xor!
13
- end
14
-
15
- a = ([255].pack('C')) * (2**17) # 128k
16
- b = a.dup
17
-
18
- n = 10
19
- Benchmark.bm do |x|
20
- x.report('Ruby:') do n.times { a.slow_xor! b } end
21
- x.report('C :') do n.times { a.fast_xor! b } end
22
- end
23
-
data/test/test_xor.rb DELETED
@@ -1,45 +0,0 @@
1
- require 'test/unit'
2
- require 'xor'
3
-
4
- class XORTest < Test::Unit::TestCase
5
- def setup
6
- @len = 16
7
- @zero = [0x00].pack('C') * @len
8
- @one = [0xFF].pack('C') * @len
9
- @x = (0...@len).collect { rand 256 }.pack('C*')
10
- @invx = (0...@len).collect { |i| @x[i] ^ 0xFF }.pack('C*')
11
- end
12
-
13
- def assert_equal( a, b )
14
- super a.unpack('H*'), b.unpack('H*')
15
- end
16
-
17
- def test_xor_same
18
- assert_equal @zero, @x.dup.xor!(@x)
19
- assert_equal @one, @x.dup.xor!(@invx)
20
- assert_equal @x, @x.dup.xor!(@zero)
21
- assert_equal @invx, @x.dup.xor!(@one)
22
- end
23
-
24
- def test_xor2_same
25
- assert_equal @x, @x.dup.xor!(@x, @x)
26
- assert_equal @invx, @x.dup.xor!(@x, @invx)
27
- assert_equal @zero, @x.dup.xor!(@x, @zero)
28
- assert_equal @one, @x.dup.xor!(@x, @one)
29
-
30
- assert_equal @invx, @x.dup.xor!(@invx, @x)
31
- assert_equal @x, @x.dup.xor!(@invx, @invx)
32
- assert_equal @one, @x.dup.xor!(@invx, @zero)
33
- assert_equal @zero, @x.dup.xor!(@invx, @one)
34
-
35
- assert_equal @zero, @x.dup.xor!(@zero, @x)
36
- assert_equal @one, @x.dup.xor!(@zero, @invx)
37
- assert_equal @invx, @x.dup.xor!(@zero, @one)
38
- assert_equal @x, @x.dup.xor!(@zero, @zero)
39
-
40
- assert_equal @one, @x.dup.xor!(@one, @x)
41
- assert_equal @zero, @x.dup.xor!(@one, @invx)
42
- assert_equal @invx, @x.dup.xor!(@one, @zero)
43
- assert_equal @x, @x.dup.xor!(@one, @one)
44
- end
45
- end