authorgravatar for fancl20@gmail.comfancl20 <fancl20@gmail.com> 2021-03-01 19:38:56+11:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-03-01 10:38:56+02:00
logbaab1b2f3135a10ed0adb56e653fc300d4add661
tree327a9440c50c4e226cf7413c8148cf2062d6e9fa
parent45d220cac6e9dbb130b48554915233672c240b7b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std: Add std.fs.path.joinZ (#7974)

* std: Add std.fs.path.joinZ * Merge std.fs.path.join and std.fs.path.joinZZ tests

1 files changed, 53 insertions(+), 37 deletions(-)

lib/std/fs/path.zig+53-37
......@@ -39,8 +39,8 @@ pub fn isSep(byte: u8) bool {
3939
4040/// This is different from mem.join in that the separator will not be repeated if
4141/// it is found at the end or beginning of a pair of consecutive paths.
42fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8) ![]u8 {
43 if (paths.len == 0) return &[0]u8{};
42fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {
43 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
4444
4545 const total_len = blk: {
4646 var sum: usize = paths[0].len;
......@@ -53,6 +53,7 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
5353 sum += @boolToInt(!prev_sep and !this_sep);
5454 sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
5555 }
56 if (zero) sum += 1;
5657 break :blk sum;
5758 };
5859
......@@ -76,6 +77,8 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
7677 buf_index += adjusted_path.len;
7778 }
7879
80 if (zero) buf[buf.len - 1] = 0;
81
7982 // No need for shrink since buf is exactly the correct size.
8083 return buf;
8184}
......@@ -83,60 +86,73 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
8386/// Naively combines a series of paths with the native path seperator.
8487/// Allocates memory for the result, which must be freed by the caller.
8588pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 {
86 return joinSep(allocator, sep, isSep, paths);
89 return joinSepMaybeZ(allocator, sep, isSep, paths, false);
90}
91
92/// Naively combines a series of paths with the native path seperator and null terminator.
93/// Allocates memory for the result, which must be freed by the caller.
94pub fn joinZ(allocator: *Allocator, paths: []const []const u8) ![:0]u8 {
95 const out = joinSepMaybeZ(allocator, sep, isSep, paths, true);
96 return out[0 .. out.len - 1 :0];
8797}
8898
89fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
99fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) void {
90100 const windowsIsSep = struct {
91101 fn isSep(byte: u8) bool {
92102 return byte == '/' or byte == '\\';
93103 }
94104 }.isSep;
95 const actual = joinSep(testing.allocator, sep_windows, windowsIsSep, paths) catch @panic("fail");
105 const actual = joinSepMaybeZ(testing.allocator, sep_windows, windowsIsSep, paths, zero) catch @panic("fail");
96106 defer testing.allocator.free(actual);
97 testing.expectEqualSlices(u8, expected, actual);
107 testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
98108}
99109
100fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
110fn testJoinMaybeZPosix(paths: []const []const u8, expected: []const u8, zero: bool) void {
101111 const posixIsSep = struct {
102112 fn isSep(byte: u8) bool {
103113 return byte == '/';
104114 }
105115 }.isSep;
106 const actual = joinSep(testing.allocator, sep_posix, posixIsSep, paths) catch @panic("fail");
116 const actual = joinSepMaybeZ(testing.allocator, sep_posix, posixIsSep, paths, zero) catch @panic("fail");
107117 defer testing.allocator.free(actual);
108 testing.expectEqualSlices(u8, expected, actual);
118 testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
109119}
110120
111121test "join" {
112 testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
113 testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
114 testJoinWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
115
116 testJoinWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
117 testJoinWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
118
119 testJoinWindows(
120 &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
121 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
122 );
123
124 testJoinWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c");
125 testJoinWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c");
126
127 testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c");
128 testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c");
129
130 testJoinPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
131 testJoinPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
132
133 testJoinPosix(
134 &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
135 "/home/andy/dev/zig/build/lib/zig/std/io.zig",
136 );
137
138 testJoinPosix(&[_][]const u8{ "a", "/c" }, "a/c");
139 testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c");
122 for (&[_]bool{ false, true }) |zero| {
123 testJoinMaybeZWindows(&[_][]const u8{}, "", zero);
124 testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero);
125 testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero);
126 testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c", zero);
127
128 testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c", zero);
129 testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c", zero);
130
131 testJoinMaybeZWindows(
132 &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
133 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
134 zero,
135 );
136
137 testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero);
138 testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero);
139
140 testJoinMaybeZPosix(&[_][]const u8{}, "", zero);
141 testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero);
142 testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero);
143
144 testJoinMaybeZPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c", zero);
145 testJoinMaybeZPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c", zero);
146
147 testJoinMaybeZPosix(
148 &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
149 "/home/andy/dev/zig/build/lib/zig/std/io.zig",
150 zero,
151 );
152
153 testJoinMaybeZPosix(&[_][]const u8{ "a", "/c" }, "a/c", zero);
154 testJoinMaybeZPosix(&[_][]const u8{ "a/", "/c" }, "a/c", zero);
155 }
140156}
141157
142158pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ");