Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/URIs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -768,16 +768,25 @@ function normpath(p::AbstractString)
else
next_slash = findnext(isequal('/'), input, nextind(input, 1))
if next_slash === nothing
append!(output, codeunits(input))
_append_codeunits!(output, input)
break
end
append!(output, codeunits(SubString(input, 1, prevind(input, next_slash))))
_append_codeunits!(output, SubString(input, 1, prevind(input, next_slash)))
SubString(input, next_slash)
end
end
return String(output)
end

# `append!(out, codeunits(s))` checks `out` and `s` for aliasing through `objectid`, which
# hashes all of `s`'s parent string, so appending segment by segment that way is quadratic.
function _append_codeunits!(out::Vector{UInt8}, s::SubString{String})
for i in 1:ncodeunits(s)
push!(out, codeunit(s, i))
end
return out
end

absuri(u, context) = absuri(URI(u), URI(context))

"""
Expand Down
6 changes: 6 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,10 @@ allocated_normalization(p) = @allocated URIs.normpath(p)
large_bytes = allocated_normalization(large)
@test large_bytes <= 6small_bytes
@test large_bytes <= 32ncodeunits(large) + 4096

# Each kept segment is copied in time proportional to the segment, not to the whole
# path: 500 KB of segments and dot segments take milliseconds, not tens of seconds.
dotted = "/" * "a/"^100_000 * "../"^100_000
@test URIs.normpath(dotted) == "/"
@test @elapsed(URIs.normpath(dotted)) < 1.0
end
Loading