Skip to content

Commit 961c8d0

Browse files
committed
mex: parent 10x faster
1 parent 6d6b137 commit 961c8d0

File tree

11 files changed

+117
-14
lines changed

11 files changed

+117
-14
lines changed

+stdlib/parent.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
%% PARENT parent directory of path
2+
% optional: mex
23
%
4+
%% Examples:
5+
% parent("a/b/c") == "a/b"
6+
% parent("a/b/c/") == "a/b"
7+
%
8+
% MEX is about 10x faster than plain Matlab for this function
39

410
function p = parent(pth)
511
arguments

buildfile.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ function publishTask(context)
9797
srcs = {
9898
["src/is_admin.cpp", "src/admin_fs.cpp"] ...
9999
"src/is_char_device.cpp", ...
100+
["src/parent.cpp", "src/parent_fs.cpp", normal], ...
100101
"src/relative_to.cpp", ...
101102
"src/proximate_to.cpp", ...
102103
["src/is_wsl.cpp", linux], ...

example/bench_parent.m

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
f = mfilename("fullpath") + ".m";
2-
%f = tempname;
32

4-
fno = @() stdlib.parent(f, false);
5-
fjava = @() stdlib.parent(f, true);
3+
fno = @() stdlib.parent(f);
64

75
t_no = timeit(fno);
8-
t_java = timeit(fjava);
96

107
disp("No Java: " + t_no + " s")
11-
disp("Java: " + t_java + " s")
12-
13-
disp("Java is " + t_no/t_java + " times faster")

octave_build.m

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ function octave_build(overwrite)
1515
fullfile(d, "is_wsl.cpp"), ...
1616
fullfile(d, "is_rosetta.cpp"), ...
1717
fullfile(d, "is_admin.cpp"), ...
18+
fullfile(d, "parent.cpp"), ...
1819
fullfile(d, "proximate_to.cpp"), ...
1920
fullfile(d, "relative_to.cpp"), ...
2021
};
@@ -24,11 +25,13 @@ function octave_build(overwrite)
2425
for s = srcs
2526
src = s{1};
2627
[~, n] = fileparts(src);
28+
bin = fullfile(t, [n, ".oct"]);
2729

28-
if ~overwrite && isfile(fullfile(t, [n, ".oct"]))
30+
if ~overwrite && stdlib.get_modtime(src) < stdlib.get_modtime(bin)
2931
continue
3032
end
3133

32-
disp(["mkoctfile: ", src, " => ", n, ".oct"])
33-
mkoctfile(src, ["-I", inc], "--output", fullfile(t, n))
34+
disp(["mkoctfile: ", src, " => ", bin])
35+
delete(bin)
36+
mkoctfile(src, ["-I", inc], "--output", bin)
3437
end

src/ffilesystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,8 @@ bool fs_is_symlink(std::string_view);
1616
bool fs_create_symlink(std::string_view, std::string_view);
1717
std::string fs_read_symlink(std::string_view);
1818

19+
std::string fs_parent(std::string_view);
20+
std::string fs_root_name(std::string_view);
21+
1922
bool fs_win32_is_symlink(std::string_view);
2023
std::string fs_shortname(std::string_view);

src/normalize.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
std::string fs_drop_slash(std::string_view in)
1111
{
1212
// drop all trailing "/" and duplicated internal "/"
13-
if (fs_is_url(in))
14-
return {};
1513

1614
std::filesystem::path p(in);
1715

src/octave/parent.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <octave/oct.h>
2+
3+
#include <string>
4+
#include <filesystem>
5+
6+
#include "pure.cpp"
7+
#include "normalize.cpp"
8+
9+
10+
DEFUN_DLD (parent, args, nargout,
11+
"get parent directory")
12+
{
13+
if (args.length() != 1){
14+
octave_stdout << "Oct: One input required\n";
15+
return octave_value("");
16+
}
17+
18+
std::string out = std::filesystem::path(fs_drop_slash(args(0).string_value())).parent_path().generic_string();
19+
20+
return octave_value(out);
21+
}

src/parent.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include "mex.hpp"
2+
#include "mexAdapter.hpp"
3+
4+
#include <string>
5+
6+
#include <vector>
7+
#include <memory>
8+
9+
#include <filesystem>
10+
11+
#include "ffilesystem.h"
12+
13+
14+
class MexFunction : public matlab::mex::Function {
15+
public:
16+
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
17+
// boilerplate engine & ArrayFactory setup
18+
std::shared_ptr<matlab::engine::MATLABEngine> matlabEng = getEngine();
19+
20+
matlab::data::ArrayFactory factory;
21+
// wrangle inputs
22+
std::string in;
23+
24+
if (inputs.size() != 1) {
25+
matlabEng->feval(u"error", 0,
26+
std::vector<matlab::data::Array>({ factory.createScalar("Mex: One input required") }));
27+
}
28+
if ((inputs[0].getType() == matlab::data::ArrayType::MATLAB_STRING && inputs[0].getNumberOfElements() == 1)){
29+
matlab::data::TypedArray<matlab::data::MATLABString> stringArr = inputs[0];
30+
in = stringArr[0];
31+
} else if (inputs[0].getType() == matlab::data::ArrayType::CHAR){
32+
matlab::data::CharArray charArr = inputs[0];
33+
in.assign(charArr.begin(), charArr.end());
34+
} else {
35+
matlabEng->feval(u"error", 0,
36+
std::vector<matlab::data::Array>({ factory.createScalar("Mex: First input must be a scalar string or char vector") }));
37+
}
38+
39+
// actual function algorithm / computation
40+
std::string out = fs_parent(in);
41+
42+
outputs[0] = factory.createScalar(out);
43+
}
44+
};

src/parent_fs.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <string>
2+
#include <string_view>
3+
4+
#include <filesystem>
5+
6+
#include "ffilesystem.h"
7+
8+
std::string fs_parent(std::string_view in)
9+
{
10+
std::string out;
11+
if(in.empty())
12+
out = ".";
13+
else
14+
out = std::filesystem::path(fs_drop_slash(in)).parent_path().generic_string();
15+
16+
// handle "/" and other no parent cases
17+
if (out.empty()){
18+
if (!in.empty() && in.front() == '/')
19+
out = "/";
20+
else
21+
out = ".";
22+
}
23+
24+
// make x: x:/
25+
if (fs_is_windows() && out.length() == 2 && !fs_root_name(out).empty())
26+
out.push_back('/');
27+
28+
return out;
29+
}

src/pure.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ std::string fs_as_posix(std::string_view path)
4646
return p.generic_string();
4747
}
4848

49+
std::string fs_root_name(std::string_view path)
50+
{
51+
return std::filesystem::path(path).root_name().generic_string();
52+
}
53+
4954

5055
bool fs_is_url(std::string_view path)
5156
{

0 commit comments

Comments
 (0)