Skip to content

Commit b8e4592

Browse files
committed
non-java normalize, more than 10x faster
1 parent cc9bbec commit b8e4592

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

+stdlib/canonical.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
else
4646
% for non-existing path, return normalized relative path
4747
% like C++ filesystem weakly_canonical()
48-
c = stdlib.normalize(c);
48+
c = stdlib.normalize(c, use_java);
4949
return
5050
end
5151
end

+stdlib/normalize.m

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function n = normalize(p)
1+
function n = normalize(p, use_java)
22
%% normalize(p)
33
% normalize(p) remove redundant elements of path p
44
% path need not exist, normalized path is returned
@@ -10,9 +10,53 @@
1010
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/Path.html#normalize()
1111
arguments
1212
p (1,1) string
13+
use_java (1,1) logical = false
1314
end
1415

15-
n = stdlib.posix(java.io.File(p).toPath().normalize());
16+
if use_java
17+
n = stdlib.posix(java.io.File(p).toPath().normalize());
18+
else
19+
20+
n = stdlib.posix(p);
21+
22+
% use split to remove /../ and /./ and duplicated /
23+
parts = split(n, "/");
24+
i0 = 1;
25+
if startsWith(n, "/")
26+
n = "/";
27+
elseif ispc && strlength(n) >= 2 && isletter(extractBetween(n, 1, 1)) && extractBetween(n, 2, 2) == ":"
28+
n = parts(1);
29+
i0 = 2;
30+
else
31+
n = "";
32+
end
33+
34+
for i = i0:length(parts)
35+
if parts(i) == ".."
36+
if n == ""
37+
n = parts(i);
38+
elseif endsWith(n, "..")
39+
n = n + "/" + parts(i);
40+
else
41+
j = strfind(n, "/");
42+
if isempty(j)
43+
n = "";
44+
else
45+
n = extractBefore(n, j(end));
46+
end
47+
end
48+
elseif all(parts(i) ~= [".", ""])
49+
if n == ""
50+
n = parts(i);
51+
elseif n == "/"
52+
n = n + parts(i);
53+
else
54+
n = n + "/" + parts(i);
55+
end
56+
end
57+
end
58+
59+
end
1660

1761
if(strlength(n) == 0), n = "."; end
1862

+stdlib/relative_to.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
end
66

77
% must remove trailing slashes
8-
base = stdlib.normalize(base);
9-
other = stdlib.normalize(other);
8+
base = stdlib.normalize(base, true);
9+
other = stdlib.normalize(other, true);
1010

1111
if base == other
1212
r = ".";

test/TestFilePure.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
in_suffix = {"", "/foo/bar/baz", "/foo/bar/baz/", "foo/bar/baz.txt", "foo/bar/baz.txt.gz", ".stat", ".stat.txt"}
2424
ref_suffix = {"", "", "", ".txt", ".gz", ".stat", ".txt"}
2525

26-
in_norm = {"", "a/b/", "a/../c", "a/b/../c", "a/b/../../c", "a/b/../../c/..", ...
26+
in_norm = {"", "//a/b/", "/a/b/", "a/b/", "a/../c", "a/b/../c", "a/b/../../c", "a/b/../../c/..", ...
2727
"a/b/../../c/../..", "a////b"}
28-
ref_norm = {".", "a/b", "c", "a/c", "c", ".", ...
28+
ref_norm = {".", "/a/b", "/a/b", "a/b", "c", "a/c", "c", ".", ...
2929
"..", "a/b"}
3030

3131
in_root

0 commit comments

Comments
 (0)