optimize this more

This commit is contained in:
Karl Seguin
2026-01-28 06:17:52 +08:00
parent fd21d952ac
commit 864ac08f16

View File

@@ -77,8 +77,9 @@ pub fn resolve(allocator: Allocator, base: [:0]const u8, path: anytype, comptime
}
// trailing space so that we always have space to append the null terminator
var out = try std.mem.join(allocator, "", &.{ normalized_base, "/", path, " " });
const end = out.len - 1;
// and so that we can compare the next two characters without needing to length check
var out = try std.mem.join(allocator, "", &.{ normalized_base, "/", path, " " });
const end = out.len - 2;
const path_marker = path_start + 1;
@@ -87,39 +88,42 @@ pub fn resolve(allocator: Allocator, base: [:0]const u8, path: anytype, comptime
// an allocator, which is ok, because we expect allocator to be an arena.
var in_i: usize = 0;
var out_i: usize = 0;
var separator = false;
while (in_i < end) {
if (separator and std.mem.startsWith(u8, out[in_i..], "./")) {
in_i += 2;
continue;
}
if (separator and std.mem.startsWith(u8, out[in_i..], "../")) {
lp.assert(out[out_i - 1] == '/', "URL.resolve", .{ .out = out });
if (out_i > path_marker) {
// go back before the /
out_i -= 2;
while (out_i > 1 and out[out_i - 1] != '/') {
out_i -= 1;
}
} else {
// if out_i == path_marker, than we've reached the start of
// the path. We can't ../ any more. E.g.:
// http://www.example.com/../hello.
// You might think that's an error, but, at least with
// new URL('../hello', 'http://www.example.com/')
// it just ignores the extra ../
if (out[in_i] == '.' and (out_i == 0 or out[out_i - 1] == '/')) {
if (out[in_i + 1] == '/') { // always safe, because we added a whitespace
// /./
in_i += 2;
continue;
}
if (out[in_i + 1] == '.' and out[in_i + 2] == '/') { // always safe, because we added two whitespaces
// /../
if (out_i > path_marker) {
// go back before the /
out_i -= 2;
while (out_i > 1 and out[out_i - 1] != '/') {
out_i -= 1;
}
} else {
// if out_i == path_marker, than we've reached the start of
// the path. We can't ../ any more. E.g.:
// http://www.example.com/../hello.
// You might think that's an error, but, at least with
// new URL('../hello', 'http://www.example.com/')
// it just ignores the extra ../
}
in_i += 3;
continue;
}
if (in_i == end - 1) {
// ignore trailing dot
break;
}
in_i += 3;
continue;
}
const c = out[in_i];
out[out_i] = c;
in_i += 1;
out_i += 1;
separator = c == '/';
}
// we always have an extra space
@@ -550,6 +554,16 @@ test "URL: resolve" {
.path = "abc../test",
.expected = "https://example/abc../test",
},
.{
.base = "https://example/dir",
.path = "abc.",
.expected = "https://example/abc.",
},
.{
.base = "https://example/dir",
.path = "abc/.",
.expected = "https://example/abc/",
},
.{
.base = "https://example/xyz/abc/123",
.path = "something.js",