fast_blank_ocaml 0.0.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.
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: []