fast_xor 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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