faster_path 0.0.6 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 145d0ead52899b0287c3854351371ed572753abf
4
- data.tar.gz: 26a96e5e5120c5697f44d1dd2aae6d0780f361c0
3
+ metadata.gz: f92e6ae04b2843b4ebbe35489a57a3761e549c5a
4
+ data.tar.gz: cf6a2778380a40beae6bd75f399c8e3ba3945c57
5
5
  SHA512:
6
- metadata.gz: d05a6334782f4994a0ff6d25f4b9e3851c08fc26dec8e32e8533ea459f602fe9df0ec2ac8a8d557ad4d278b713d7073db0ec641754f0537416e9bfa1ee3decf6
7
- data.tar.gz: 98e70ecc789fbdb19d945f07a0f3c2ab2844c719ef7d41794aace5e659a3b9fa0353d4ca409bea0a28f1549d0db698f494a1d819d7de2cf2158a5fa6def61dd9
6
+ metadata.gz: 0924b343e18fbe1444b5e1ebe8def4f7856dfe99298bd24b3ba1e5d1b2367900d6464063ba9c0b6508ea75799cee37085531d63627937e0a1b620e7002496742
7
+ data.tar.gz: 834d364fd05f66a698964e9fd9c9f71717a8026f114f04f0349fe5e6c700572e1f39d86b1083cc1b475c659605d13b708f116c2f4baf9075be3976d18b466c47
data/README.md CHANGED
@@ -86,7 +86,7 @@ Current methods implemented:
86
86
  |FasterPath Rust Implementation|Ruby 2.3.1 Implementation|Performance Improvement|
87
87
  |---|---|:---:|
88
88
  | `FasterPath.absolute?` | `Pathname#absolute?` | 1234.6% |
89
- | `FasterPath.chop_basename` | `Pathname#chop_basename` | 27.5% |
89
+ | `FasterPath.chop_basename` | `Pathname#chop_basename` | 46.7% |
90
90
  | `FasterPath.relative?` | `Pathname#relative?` | 1262.3% |
91
91
  | `FasterPath.blank?` | | |
92
92
 
@@ -115,8 +115,9 @@ FasterPath.sledgehammer_everything!
115
115
 
116
116
  The primary methods to target are mostly listed in the **Why** section above. You may find the Ruby
117
117
  source code useful for Pathname's [Ruby source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/lib/pathname.rb),
118
- [C source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/pathname.c), and
119
- [tests](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/test/pathname/test_pathname.rb).
118
+ [C source](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/ext/pathname/pathname.c),
119
+ [tests](https://github.com/ruby/ruby/blob/32674b167bddc0d737c38f84722986b0f228b44b/test/pathname/test_pathname.rb),
120
+ and checkout the [documentation](http://ruby-doc.org/stdlib-2.3.1/libdoc/pathname/rdoc/Pathname.html).
120
121
 
121
122
  Methods will be written as exclusively in Rust as possible. Even just writing a **not** in Ruby with a
122
123
  Rust method like `!absolute?` _(not absolute)_ drops 39% of the performance already gained in Rust.
@@ -16,4 +16,4 @@ Dir.chdir('../../') do
16
16
  system("rake clean_src")
17
17
  end
18
18
 
19
- create_makefile('faster_path/dummy')
19
+ create_makefile('faster_path/dummy')
data/faster_path.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/danielpclark/faster_path"
14
14
  spec.license = "MIT OR Apache-2.0"
15
15
 
16
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets|benches)/}) }
17
17
  spec.bindir = "exe"
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.extensions << "ext/faster_path/extconf.rb"
data/lib/faster_path.rb CHANGED
@@ -18,17 +18,18 @@ module FasterPath
18
18
  # to handle non-path strings.
19
19
  def self.chop_basename(pth)
20
20
  d,b = [Rust.dirname(pth), Rust.basename(pth)]
21
- if blank?(d) && blank?(b)
22
- nil
23
- else
24
- [d,b]
25
- end
21
+ [d,b] unless Rust.both_are_blank(d,b)
26
22
  end
27
23
 
28
24
  def self.blank?(str)
29
25
  Rust.is_blank(str)
30
26
  end
31
27
 
28
+ # EXAMPLE
29
+ #def self.one_and_two
30
+ # Rust.one_and_two.to_a
31
+ #end
32
+
32
33
  private
33
34
  module Rust
34
35
  extend FFI::Library
@@ -36,11 +37,25 @@ module FasterPath
36
37
  prefix = Gem.win_platform? ? "" : "lib"
37
38
  "#{File.expand_path("../target/release/", File.dirname(__FILE__))}/#{prefix}faster_path.#{FFI::Platform::LIBSUFFIX}"
38
39
  end
40
+
41
+ class FromRustArray < FFI::Struct
42
+ layout :len, :size_t, # dynamic array layout
43
+ :data, :pointer #
44
+
45
+ def to_a
46
+ self[:data].get_array_of_string(0, self[:len]).compact
47
+ end
48
+ end
49
+
39
50
  attach_function :is_absolute, [ :string ], :bool
40
51
  attach_function :is_relative, [ :string ], :bool
41
52
  attach_function :is_blank, [ :string ], :bool
53
+ attach_function :both_are_blank, [ :string, :string ], :bool
42
54
  attach_function :basename, [ :string ], :string
43
55
  attach_function :dirname, [ :string ], :string
56
+
57
+ # EXAMPLE
58
+ #attach_function :one_and_two, [], FromRustArray.by_value
44
59
  end
45
60
  private_constant :Rust
46
61
  end
@@ -1,3 +1,3 @@
1
1
  module FasterPath
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.8"
3
3
  end
data/src/basename.rs ADDED
@@ -0,0 +1,15 @@
1
+ #[no_mangle]
2
+ pub extern fn basename(string: *const c_char) -> *const c_char {
3
+ let c_str = unsafe {
4
+ assert!(!string.is_null());
5
+
6
+ CStr::from_ptr(string)
7
+ };
8
+
9
+ let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
10
+
11
+ let part = Path::new(r_str).file_name().unwrap_or(OsStr::new("")).to_str();
12
+
13
+ let output = CString::new(format!("{}", part.unwrap())).unwrap();
14
+ output.into_raw()
15
+ }
@@ -0,0 +1,14 @@
1
+ #[no_mangle]
2
+ pub extern fn both_are_blank(s1: *const c_char, s2: *const c_char) -> bool {
3
+ let c_str1 = unsafe {
4
+ assert!(!s1.is_null());
5
+ CStr::from_ptr(s1)
6
+ };
7
+ let c_str2 = unsafe {
8
+ assert!(!s2.is_null());
9
+ CStr::from_ptr(s2)
10
+ };
11
+
12
+ str::from_utf8(c_str1.to_bytes()).unwrap().trim().is_empty() &&
13
+ str::from_utf8(c_str2.to_bytes()).unwrap().trim().is_empty()
14
+ }
data/src/dirname.rs ADDED
@@ -0,0 +1,25 @@
1
+ #[no_mangle]
2
+ pub extern fn dirname(string: *const c_char) -> *const c_char {
3
+ let c_str = unsafe {
4
+ assert!(!string.is_null());
5
+
6
+ CStr::from_ptr(string)
7
+ };
8
+
9
+ let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
10
+
11
+ if r_str.is_empty() {
12
+ return string
13
+ }
14
+
15
+ let path = Path::new(r_str).parent().unwrap_or(Path::new(""));
16
+
17
+ let out_str = if !path.to_str().unwrap().is_empty() {
18
+ format!("{}{}", path.to_str().unwrap(), MAIN_SEPARATOR)
19
+ } else {
20
+ format!("{}", path.to_str().unwrap())
21
+ };
22
+
23
+ let output = CString::new(out_str).unwrap();
24
+ output.into_raw()
25
+ }
@@ -0,0 +1,12 @@
1
+ #[no_mangle]
2
+ pub extern fn is_absolute(string: *const c_char) -> bool {
3
+ let c_str = unsafe {
4
+ assert!(!string.is_null());
5
+
6
+ CStr::from_ptr(string)
7
+ };
8
+
9
+ let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
10
+
11
+ r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) == MAIN_SEPARATOR
12
+ }
data/src/is_blank.rs ADDED
@@ -0,0 +1,10 @@
1
+ #[no_mangle]
2
+ pub extern fn is_blank(string: *const c_char) -> bool {
3
+ let c_str = unsafe {
4
+ assert!(!string.is_null());
5
+
6
+ CStr::from_ptr(string)
7
+ };
8
+
9
+ str::from_utf8(c_str.to_bytes()).unwrap().trim().is_empty()
10
+ }
@@ -0,0 +1,12 @@
1
+ #[no_mangle]
2
+ pub extern fn is_relative(string: *const c_char) -> bool {
3
+ let c_str = unsafe {
4
+ assert!(!string.is_null());
5
+
6
+ CStr::from_ptr(string)
7
+ };
8
+
9
+ let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
10
+
11
+ r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) != MAIN_SEPARATOR
12
+ }
data/src/lib.rs CHANGED
@@ -10,82 +10,23 @@ use std::path::{Path,MAIN_SEPARATOR};
10
10
  use libc::c_char;
11
11
  use std::ffi::{CStr,CString,OsStr};
12
12
  use std::str;
13
-
14
- #[no_mangle]
15
- pub extern fn is_absolute(string: *const c_char) -> bool {
16
- let c_str = unsafe {
17
- assert!(!string.is_null());
18
-
19
- CStr::from_ptr(string)
20
- };
21
-
22
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
23
-
24
- r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) == MAIN_SEPARATOR
25
- }
26
-
27
- #[no_mangle]
28
- pub extern fn is_relative(string: *const c_char) -> bool {
29
- let c_str = unsafe {
30
- assert!(!string.is_null());
31
-
32
- CStr::from_ptr(string)
33
- };
34
-
35
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap_or("");
36
-
37
- r_str.chars().next().unwrap_or("muffins".chars().next().unwrap()) != MAIN_SEPARATOR
38
- }
39
-
40
- #[no_mangle]
41
- pub extern fn is_blank(string: *const c_char) -> bool {
42
- let c_str = unsafe {
43
- assert!(!string.is_null());
44
-
45
- CStr::from_ptr(string)
46
- };
47
-
48
- str::from_utf8(c_str.to_bytes()).unwrap().trim().is_empty()
49
- }
50
-
51
- #[no_mangle]
52
- pub extern fn basename(string: *const c_char) -> *const c_char {
53
- let c_str = unsafe {
54
- assert!(!string.is_null());
55
-
56
- CStr::from_ptr(string)
57
- };
58
-
59
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
60
-
61
- let part = Path::new(r_str).file_name().unwrap_or(OsStr::new("")).to_str();
62
-
63
- let output = CString::new(format!("{}", part.unwrap())).unwrap();
64
- output.into_raw()
65
- }
66
-
67
- #[no_mangle]
68
- pub extern fn dirname(string: *const c_char) -> *const c_char {
69
- let c_str = unsafe {
70
- assert!(!string.is_null());
71
-
72
- CStr::from_ptr(string)
73
- };
74
-
75
- let r_str = str::from_utf8(c_str.to_bytes()).unwrap();
76
-
77
- if r_str.is_empty() {
78
- return string
79
- }
80
-
81
- let path = Path::new(r_str).parent().unwrap_or(Path::new(""));
82
-
83
- let out_str = if !path.to_str().unwrap().is_empty() {
84
- format!("{}{}", path.to_str().unwrap(), MAIN_SEPARATOR)
85
- } else {
86
- format!("{}", path.to_str().unwrap())
87
- };
88
-
89
- let output = CString::new(out_str).unwrap();
90
- output.into_raw()
91
- }
13
+ use std::mem;
14
+
15
+ include!("ruby_string.rs");
16
+ include!("ruby_array.rs");
17
+ include!("is_absolute.rs");
18
+ include!("is_relative.rs");
19
+ include!("is_blank.rs");
20
+ include!("both_are_blank.rs");
21
+ include!("basename.rs");
22
+ include!("dirname.rs");
23
+
24
+ // EXAMPLE
25
+ //
26
+ //#[no_mangle]
27
+ //pub extern fn one_and_two() -> RubyArray {
28
+ // let mut words = vec![];
29
+ // words.push(RubyString::to_ruby(&"one".to_string()));
30
+ // words.push(RubyString::to_ruby(&"two".to_string()));
31
+ // RubyArray::from_vec(words)
32
+ //}
data/src/ruby_array.rs ADDED
@@ -0,0 +1,17 @@
1
+ #[repr(C)]
2
+ pub struct RubyArray {
3
+ len: libc::size_t,
4
+ data: *const libc::c_void,
5
+ }
6
+
7
+ impl RubyArray {
8
+ #[allow(dead_code)]
9
+ fn from_vec<T>(vec: Vec<T>) -> RubyArray {
10
+ let array = RubyArray {
11
+ data: vec.as_ptr() as *const libc::c_void,
12
+ len: vec.len() as libc::size_t
13
+ };
14
+ mem::forget(vec);
15
+ array
16
+ }
17
+ }
@@ -0,0 +1,30 @@
1
+ pub struct RubyString;
2
+
3
+ // Coercing strs into Strings has some loss of performance
4
+ // You may use these methods temporarily but it would be much better
5
+ // to write all of this code out in each method using just str.
6
+ //
7
+ // Using these methods you will still get you 10X (= 900%) performance
8
+ // gain regardless. But really consider not using String. If you do
9
+ // as I've intstructed the performance gains will go from 900% to 1250%.
10
+ impl RubyString {
11
+ #[allow(dead_code)]
12
+ // FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
13
+ // SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
14
+ fn from_ruby(s: *const c_char) -> String {
15
+ let c_str = unsafe {
16
+ assert!(!s.is_null());
17
+ CStr::from_ptr(s)
18
+ };
19
+ (*str::from_utf8(c_str.to_bytes()).unwrap_or("")).to_string()
20
+ }
21
+
22
+ #[allow(dead_code)]
23
+ // FOR QUICK IMPLEMENTATION. NOT FOR PRODUCTION.
24
+ // SEE BENCHMARKS FOR SANCTIONED IMPLEMENTATION.
25
+ fn to_ruby<S: Into<String>>(s: S) -> *const c_char {
26
+ let r_str = s.into();
27
+ let s_slice: &str = &r_str[..];
28
+ CString::new(s_slice).unwrap().into_raw()
29
+ }
30
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faster_path
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel P. Clark
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-11 00:00:00.000000000 Z
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -90,7 +90,15 @@ files:
90
90
  - lib/faster_path/optional/monkeypatches.rb
91
91
  - lib/faster_path/optional/refinements.rb
92
92
  - lib/faster_path/version.rb
93
+ - src/basename.rs
94
+ - src/both_are_blank.rs
95
+ - src/dirname.rs
96
+ - src/is_absolute.rs
97
+ - src/is_blank.rs
98
+ - src/is_relative.rs
93
99
  - src/lib.rs
100
+ - src/ruby_array.rs
101
+ - src/ruby_string.rs
94
102
  homepage: https://github.com/danielpclark/faster_path
95
103
  licenses:
96
104
  - MIT OR Apache-2.0