fast_blank_ocaml 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 29cf7f388a3afa1193ab25134c944804f479f1e8
4
+ data.tar.gz: 95cf3a37f89100e15619ae870cab6aa5ad796ec2
5
+ SHA512:
6
+ metadata.gz: a3e39f2097057b1c2dfa40c9895dd090c12875c9fe793813b8e2426ee7d2591252e1dcd7830e91f35f4b45cffab0b1ef3691e3a253eb01334ac2b9923480d9f0
7
+ data.tar.gz: 8694b96a5586521faad477dea7b617cccdcaa1551c65765cfbead4a7047b27d51d9bede5e0990bef439b2137b6ed346e74990c725a67dc5aaabffec8d2808028
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /*.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fast_blank_ocaml (0.0.0)
5
+ ffi
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ benchmark-ips (2.7.2)
11
+ fast_blank (1.0.0)
12
+ ffi (1.9.17)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ benchmark-ips
19
+ bundler (~> 1.15)
20
+ fast_blank
21
+ fast_blank_ocaml!
22
+
23
+ BUNDLED WITH
24
+ 1.15.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Alexander Komarov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # fast_blank_ocaml
2
+
3
+ *DISCLAIMER*: I am not an expert in OCaml, C, Ruby and native extensions.
4
+ This is just something I wanted to try out, and since I didn't find a lot of
5
+ info by googling, I decided to put this on GitHub and maybe someone will find
6
+ this useful.
7
+
8
+ ### Description
9
+
10
+ This is an example of how to write a Ruby native extension in OCaml.
11
+ The code for `blank?` itself is in `ocaml/blank.ml`.
12
+
13
+ There's also a C wrapper in `ocaml/blank.c` which is required to make a
14
+ connection via FFI.
15
+
16
+ ### Benchmark
17
+
18
+ To view the benchmark results (with comparison to
19
+ [fast_blank](https://github.com/SamSaffron/fast_blank)), see `benchmark.rb`.
20
+ Or, run it for yourself via `ruby benchmark.rb`.
21
+
22
+ ### Contributing
23
+
24
+ Despite the gem's "it's just a test" status, issues and PRs are very welcome.
data/benchmark.rb ADDED
@@ -0,0 +1,193 @@
1
+ require 'benchmark/ips'
2
+ require 'fast_blank'
3
+ require_relative 'lib/cowcaml.rb'
4
+
5
+ class String
6
+ def ocaml_blank?
7
+ Cowcaml::Base.blank self
8
+ end
9
+
10
+ # active support implementation
11
+ def slow_blank?
12
+ /\A[[:space:]]*\z/ === self
13
+ end
14
+
15
+ def new_slow_blank?
16
+ empty? || !(/[[:^space:]]/ === self)
17
+ end
18
+ end
19
+
20
+ test_strings = [
21
+ "",
22
+ "\r\n\r\n ",
23
+ "this is a test",
24
+ " this is a longer test",
25
+ " this is a longer test
26
+ this is a longer test
27
+ this is a longer test
28
+ this is a longer test
29
+ this is a longer test"
30
+ ]
31
+
32
+ test_strings.each do |s|
33
+ raise "failed on #{s.inspect}" if s.ocaml_blank? != s.slow_blank?
34
+ raise "failed on #{s.inspect}" if s.ocaml_blank? != s.new_slow_blank?
35
+ end
36
+
37
+ test_strings.each do |s|
38
+ puts "\n================== Test String Length: #{s.length} =================="
39
+ Benchmark.ips do |x|
40
+ x.report("Fast Blank") do |times|
41
+ i = 0
42
+ while i < times
43
+ s.blank?
44
+ i += 1
45
+ end
46
+ end
47
+
48
+ x.report("Fast ActiveSupport") do |times|
49
+ i = 0
50
+ while i < times
51
+ s.blank_as?
52
+ i += 1
53
+ end
54
+ end
55
+
56
+ x.report("Slow Blank") do |times|
57
+ i = 0
58
+ while i < times
59
+ s.slow_blank?
60
+ i += 1
61
+ end
62
+ end
63
+
64
+ x.report("New Slow Blank") do |times|
65
+ i = 0
66
+ while i < times
67
+ s.new_slow_blank?
68
+ i += 1
69
+ end
70
+ end
71
+
72
+ x.report("OCaml Fast Blank") do |times|
73
+ i = 0
74
+ while i < times
75
+ s.ocaml_blank?
76
+ i += 1
77
+ end
78
+ end
79
+
80
+ x.compare!
81
+ end
82
+ end
83
+
84
+ __END__
85
+
86
+ ================== Test String Length: 0 ==================
87
+ Warming up --------------------------------------
88
+ Fast Blank 259.226k i/100ms
89
+ Fast ActiveSupport 226.507k i/100ms
90
+ Slow Blank 67.603k i/100ms
91
+ New Slow Blank 259.002k i/100ms
92
+ OCaml Fast Blank 186.906k i/100ms
93
+ Calculating -------------------------------------
94
+ Fast Blank 20.637M (±15.6%) i/s - 99.284M in 5.013785s
95
+ Fast ActiveSupport 21.001M (±14.2%) i/s - 101.702M in 5.007715s
96
+ Slow Blank 802.420k (±20.7%) i/s - 3.718M in 5.001746s
97
+ New Slow Blank 18.710M (±23.3%) i/s - 84.694M in 4.998752s
98
+ OCaml Fast Blank 4.950M (±15.4%) i/s - 23.924M in 5.025812s
99
+
100
+ Comparison:
101
+ Fast ActiveSupport: 21001105.8 i/s
102
+ Fast Blank: 20637083.6 i/s - same-ish: difference falls within error
103
+ New Slow Blank: 18710072.3 i/s - same-ish: difference falls within error
104
+ OCaml Fast Blank: 4949668.0 i/s - 4.24x slower
105
+ Slow Blank: 802419.7 i/s - 26.17x slower
106
+
107
+
108
+ ================== Test String Length: 6 ==================
109
+ Warming up --------------------------------------
110
+ Fast Blank 187.458k i/100ms
111
+ Fast ActiveSupport 171.902k i/100ms
112
+ Slow Blank 61.453k i/100ms
113
+ New Slow Blank 102.474k i/100ms
114
+ OCaml Fast Blank 163.372k i/100ms
115
+ Calculating -------------------------------------
116
+ Fast Blank 9.151M (± 9.8%) i/s - 45.177M in 5.004625s
117
+ Fast ActiveSupport 10.112M (± 6.9%) i/s - 50.367M in 5.010209s
118
+ Slow Blank 922.222k (± 4.0%) i/s - 4.609M in 5.005885s
119
+ New Slow Blank 1.741M (± 6.3%) i/s - 8.710M in 5.026138s
120
+ OCaml Fast Blank 4.555M (±10.2%) i/s - 22.382M in 5.005977s
121
+
122
+ Comparison:
123
+ Fast ActiveSupport: 10112422.2 i/s
124
+ Fast Blank: 9150969.7 i/s - same-ish: difference falls within error
125
+ OCaml Fast Blank: 4554510.1 i/s - 2.22x slower
126
+ New Slow Blank: 1741425.3 i/s - 5.81x slower
127
+ Slow Blank: 922222.1 i/s - 10.97x slower
128
+
129
+
130
+ ================== Test String Length: 14 ==================
131
+ Warming up --------------------------------------
132
+ Fast Blank 249.490k i/100ms
133
+ Fast ActiveSupport 248.312k i/100ms
134
+ Slow Blank 125.931k i/100ms
135
+ New Slow Blank 69.459k i/100ms
136
+ OCaml Fast Blank 182.275k i/100ms
137
+ Calculating -------------------------------------
138
+ Fast Blank 18.106M (± 6.8%) i/s - 90.315M in 5.015731s
139
+ Fast ActiveSupport 16.674M (±19.7%) i/s - 77.225M in 5.006326s
140
+ Slow Blank 2.104M (±15.7%) i/s - 10.200M in 5.041044s
141
+ New Slow Blank 876.423k (±13.0%) i/s - 4.306M in 5.013083s
142
+ OCaml Fast Blank 5.026M (±12.4%) i/s - 24.607M in 5.011347s
143
+
144
+ Comparison:
145
+ Fast Blank: 18106150.8 i/s
146
+ Fast ActiveSupport: 16673555.8 i/s - same-ish: difference falls within error
147
+ OCaml Fast Blank: 5026177.7 i/s - 3.60x slower
148
+ Slow Blank: 2103665.1 i/s - 8.61x slower
149
+ New Slow Blank: 876422.6 i/s - 20.66x slower
150
+
151
+
152
+ ================== Test String Length: 24 ==================
153
+ Warming up --------------------------------------
154
+ Fast Blank 221.182k i/100ms
155
+ Fast ActiveSupport 222.870k i/100ms
156
+ Slow Blank 111.589k i/100ms
157
+ New Slow Blank 66.756k i/100ms
158
+ OCaml Fast Blank 171.531k i/100ms
159
+ Calculating -------------------------------------
160
+ Fast Blank 11.786M (± 5.3%) i/s - 58.834M in 5.007267s
161
+ Fast ActiveSupport 11.704M (±14.7%) i/s - 56.386M in 5.011782s
162
+ Slow Blank 1.984M (±10.0%) i/s - 9.820M in 5.049188s
163
+ New Slow Blank 874.532k (± 8.3%) i/s - 4.339M in 5.001362s
164
+ OCaml Fast Blank 4.967M (± 4.8%) i/s - 24.872M in 5.019823s
165
+
166
+ Comparison:
167
+ Fast Blank: 11785709.1 i/s
168
+ Fast ActiveSupport: 11704475.2 i/s - same-ish: difference falls within error
169
+ OCaml Fast Blank: 4966928.5 i/s - 2.37x slower
170
+ Slow Blank: 1983904.0 i/s - 5.94x slower
171
+ New Slow Blank: 874532.3 i/s - 13.48x slower
172
+
173
+
174
+ ================== Test String Length: 136 ==================
175
+ Warming up --------------------------------------
176
+ Fast Blank 210.768k i/100ms
177
+ Fast ActiveSupport 193.088k i/100ms
178
+ Slow Blank 77.595k i/100ms
179
+ New Slow Blank 44.558k i/100ms
180
+ OCaml Fast Blank 143.046k i/100ms
181
+ Calculating -------------------------------------
182
+ Fast Blank 10.256M (±20.4%) i/s - 47.844M in 5.002855s
183
+ Fast ActiveSupport 12.072M (±10.6%) i/s - 59.471M in 5.009553s
184
+ Slow Blank 1.851M (±18.1%) i/s - 8.613M in 5.087665s
185
+ New Slow Blank 849.400k (±14.3%) i/s - 4.144M in 5.036486s
186
+ OCaml Fast Blank 3.387M (±13.7%) i/s - 16.593M in 5.024423s
187
+
188
+ Comparison:
189
+ Fast ActiveSupport: 12071703.8 i/s
190
+ Fast Blank: 10255565.3 i/s - same-ish: difference falls within error
191
+ OCaml Fast Blank: 3387110.1 i/s - 3.56x slower
192
+ Slow Blank: 1850712.1 i/s - 6.52x slower
193
+ New Slow Blank: 849400.0 i/s - 14.21x slower
@@ -0,0 +1,4 @@
1
+ blank.cmi
2
+ blank.cmx
3
+ blank.o
4
+ blankcaml.o
@@ -0,0 +1,4 @@
1
+ libblank-so:
2
+ ocamlopt -output-obj -o blankcaml.o blank.ml
3
+ ocamlc -c blank.c
4
+ cc -o libblank.so blank.o blankcaml.o -L`ocamlc -where` -lunix -lasmrun
@@ -0,0 +1,14 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+
4
+ CLOBBER.include('libblank.so')
5
+
6
+ task :default => [:build]
7
+
8
+ desc 'Build the shared library'
9
+ task :build => %w[libblank.so]
10
+
11
+ file 'libblank.so' => %w[blank.ml blank.c] do
12
+ sh 'make'
13
+ sh 'mv libblank.so ../../lib'
14
+ end
@@ -0,0 +1,20 @@
1
+ #include <stdbool.h>
2
+ #include <string.h>
3
+ #include <caml/alloc.h>
4
+ #include <caml/mlvalues.h>
5
+ #include <caml/memory.h>
6
+ #include <caml/callback.h>
7
+
8
+ void startup (char** argv) {
9
+ caml_startup(argv);
10
+ }
11
+
12
+ bool blank (const char* string) {
13
+ CAMLparam0();
14
+ CAMLlocal1(ostring);
15
+ static value* closure = NULL;
16
+ if (closure == NULL)
17
+ closure = caml_named_value("blank");
18
+ ostring = caml_copy_string(string); // this is probably slowing things down
19
+ CAMLreturn(Bool_val(caml_callback(*closure, ostring)));
20
+ }
@@ -0,0 +1,47 @@
1
+ (* char codes taken from https://github.com/SamSaffron/fast_blank *)
2
+ let char_blank char =
3
+ match int_of_char char with
4
+ | 0x9 -> true (* tab *)
5
+ | 0xA -> true (* line feed *)
6
+ | 0xB -> true (* vertical tab *)
7
+ | 0xC -> true (* form feed *)
8
+ | 0xD -> true (* carriage return *)
9
+ | 0x20 -> true (* space *)
10
+ | 0x85 -> true
11
+ | 0xA0 -> true (* nbsp *)
12
+ | 0x1680 -> true
13
+ | 0x2000 -> true
14
+ | 0x2001 -> true
15
+ | 0x2002 -> true
16
+ | 0x2003 -> true
17
+ | 0x2004 -> true
18
+ | 0x2005 -> true
19
+ | 0x2006 -> true
20
+ | 0x2007 -> true
21
+ | 0x2008 -> true
22
+ | 0x2009 -> true
23
+ | 0x200a -> true
24
+ | 0x2028 -> true
25
+ | 0x2029 -> true
26
+ | 0x202f -> true
27
+ | 0x205f -> true
28
+ | 0x3000 -> true
29
+ | _ -> false
30
+
31
+ let blank_by_char string length =
32
+ let index = ref 0 in
33
+ let result = ref true in
34
+ while !index < length && !result do
35
+ if not (char_blank string.[!index]) then
36
+ result := false;
37
+ index := !index + 1
38
+ done;
39
+ !result
40
+
41
+ let blank string =
42
+ match String.length string with
43
+ | 0 -> true
44
+ | len -> blank_by_char string len
45
+
46
+ (* register callback for C *)
47
+ let _ = Callback.register "blank" blank
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fast_blank_ocaml'
8
+ spec.version = '0.0.0'
9
+ spec.authors = ['Alexander Komarov']
10
+ spec.email = ['ak@akxcv.com']
11
+
12
+ spec.summary = 'String#blank? in OCaml'
13
+ spec.description = 'A simple example of how to write a Ruby native extension in OCaml'
14
+ spec.homepage = 'https://github.com/akxcv/fast_blank_ocaml'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.require_paths = ['lib']
19
+ spec.required_ruby_version = '>= 2.2.0'
20
+
21
+ spec.extensions = ['ext/ocaml-blank/Rakefile']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.15'
24
+ spec.add_development_dependency 'benchmark-ips'
25
+ spec.add_development_dependency 'fast_blank'
26
+
27
+ spec.add_dependency 'ffi'
28
+ end
data/lib/.gitignore ADDED
@@ -0,0 +1 @@
1
+ libblank.so
data/lib/cowcaml.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module Cowcaml
6
+ module Base
7
+ extend FFI::Library
8
+ ffi_lib File.expand_path('../libblank.so', __FILE__)
9
+ attach_function :blank, [:string], :bool
10
+ attach_function :startup, [:string], :void
11
+ end
12
+ Base.startup ''
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'cowcaml.rb'
4
+
5
+ class String
6
+ def blank?
7
+ Cowcaml::Base.blank self
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fast_blank_ocaml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Komarov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: benchmark-ips
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fast_blank
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ffi
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A simple example of how to write a Ruby native extension in OCaml
70
+ email:
71
+ - ak@akxcv.com
72
+ executables: []
73
+ extensions:
74
+ - ext/ocaml-blank/Rakefile
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE
81
+ - README.md
82
+ - benchmark.rb
83
+ - ext/ocaml-blank/.gitignore
84
+ - ext/ocaml-blank/Makefile
85
+ - ext/ocaml-blank/Rakefile
86
+ - ext/ocaml-blank/blank.c
87
+ - ext/ocaml-blank/blank.ml
88
+ - fast_blank_ocaml.gemspec
89
+ - lib/.gitignore
90
+ - lib/cowcaml.rb
91
+ - lib/fast_blank_ocaml.rb
92
+ homepage: https://github.com/akxcv/fast_blank_ocaml
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 2.2.0
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.6.8
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: String#blank? in OCaml
116
+ test_files: []