fast_xor 1.0.1

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/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006-2009 Steve Sloan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.rdoc ADDED
@@ -0,0 +1,33 @@
1
+ = String XOR Ruby Extension
2
+
3
+ +fast_xor+ is a simple extension which provides fast in-place String XOR functions (suitable for cryptography).
4
+
5
+ == How do you use it?
6
+
7
+ require 'xor'
8
+
9
+ # two-argument version
10
+ a, b = 'a string', 'another string'
11
+ a.xor!(b)
12
+ a == "\000N\034\000\032\f\034G"
13
+
14
+ # three-argument version
15
+ a, b, c = 'a string', 'another string', 'yet another string'
16
+ a.xor!(b, c)
17
+ a == "y+h {bs3"
18
+
19
+ == How fast is "Fast"?
20
+
21
+ On my computer, about 1,000x faster than pure Ruby (your mileage my vary):
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)
27
+
28
+
29
+ Author:: Steve Sloan (mailto:steve@finagle.org)
30
+ Website:: http://github.com/CodeMonkeySteve/fast_xor
31
+ Copyright:: Copyright (c) 2009 Steve Sloan
32
+ License:: MIT
33
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
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
data/ext/xor.c ADDED
@@ -0,0 +1,55 @@
1
+ #include <stdio.h>
2
+ #include <ruby.h>
3
+
4
+ VALUE string_xor( int argc, VALUE *argv, VALUE self ) {
5
+ const char *src = 0;
6
+ char *dest = 0 ;
7
+ size_t length = 0;
8
+
9
+ if ( (argc < 1) || (argc > 2) ) {
10
+ rb_raise( rb_eArgError, "wrong # of arguments(%d for 1 or 2)", argc );
11
+ return Qnil;
12
+ }
13
+
14
+ dest = STR2CSTR(self);
15
+ length = RSTRING(self)->len;
16
+
17
+ if ( TYPE(argv[0]) == T_STRING ) {
18
+ src = STR2CSTR(argv[0]);
19
+ size_t l = RSTRING(argv[0])->len;
20
+ if ( l < length )
21
+ length = l;
22
+ } else {
23
+ rb_raise( rb_eTypeError, "in method '" "xor" "', argument " "1"" of type '" "String""'" );
24
+ return Qnil;
25
+ }
26
+
27
+ if ( argc == 1 ) {
28
+ for ( ; length--; ++dest, ++src )
29
+ *dest ^= *src;
30
+
31
+ } else {
32
+ const char *src2 = 0;
33
+
34
+ if ( TYPE(argv[1]) == T_STRING ) {
35
+ src2 = STR2CSTR(argv[1]);
36
+ size_t l = RSTRING(argv[1])->len;
37
+ if ( l < length )
38
+ length = l;
39
+ } else {
40
+ rb_raise( rb_eTypeError, "in method '" "xor" "', argument " "2"" of type '" "String""'" );
41
+ return Qnil;
42
+ }
43
+
44
+ for ( ; length--; ++dest, ++src, ++src2 )
45
+ *dest ^= *src ^ *src2;
46
+ }
47
+
48
+ return self;
49
+ }
50
+
51
+
52
+ void Init_xor( void )
53
+ {
54
+ rb_define_method( rb_cString, "xor!", ((VALUE (*)(ANYARGS)) string_xor), -1 );
55
+ }
@@ -0,0 +1,191 @@
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 ADDED
@@ -0,0 +1,23 @@
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 ADDED
@@ -0,0 +1,45 @@
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
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fast_xor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Steve Sloan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-26 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Provides a C-optimized method for in-place XORing of two (or three) strings
17
+ email: steve@finagle.org
18
+ executables: []
19
+
20
+ extensions:
21
+ - Rakefile
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - MIT-LICENSE
26
+ - README.rdoc
27
+ - ext/xor.c
28
+ - rake/extensiontask.rb
29
+ - test/benchmark.rb
30
+ - test/test_xor.rb
31
+ has_rdoc: true
32
+ homepage: http://github.com/CodeMonkeySteve/fast_xor
33
+ licenses: []
34
+
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --charset=UTF-8
38
+ require_paths:
39
+ - ext
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project:
55
+ rubygems_version: 1.3.5
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Fast String XOR operator
59
+ test_files:
60
+ - test/benchmark.rb
61
+ - test/test_xor.rb