From: imxyb Date: Wed, 28 Oct 2020 21:26:04 +0000 (+0000) Subject: net/url: improve performance for resolvePath X-Git-Tag: go1.16beta1~440 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=49a210eb87da6b7ac960cac990337ef4dc113b0d;p=gostls13.git net/url: improve performance for resolvePath benchmark compare results: benchmark old ns/op new ns/op delta BenchmarkResolvePath-12 297 141 -52.53% benchmark old allocs new allocs delta BenchmarkResolvePath-12 5 3 -40.00% benchmark old bytes new bytes delta BenchmarkResolvePath-12 181 24 -86.74% Change-Id: Ia69e9fb36abb5930ed49217b5219be62b57ec429 GitHub-Last-Rev: e16dd9f7415178120f67f472bf45a2b006e00a93 GitHub-Pull-Request: golang/go#42180 Reviewed-on: https://go-review.googlesource.com/c/go/+/264817 Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Trust: Emmanuel Odeke --- diff --git a/src/net/url/url.go b/src/net/url/url.go index c93def0bd7..d90f5f06b5 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -1000,25 +1000,52 @@ func resolvePath(base, ref string) string { if full == "" { return "" } - src := strings.Split(full, "/") - dst := make([]string, 0, len(src)) - for _, elem := range src { - switch elem { - case ".": + + var ( + last string + elem string + i int + dst strings.Builder + ) + first := true + remaining := full + for i >= 0 { + i = strings.IndexByte(remaining, '/') + if i < 0 { + last, elem, remaining = remaining, remaining, "" + } else { + elem, remaining = remaining[:i], remaining[i+1:] + } + if elem == "." { + first = false // drop - case "..": - if len(dst) > 0 { - dst = dst[:len(dst)-1] + continue + } + + if elem == ".." { + str := dst.String() + index := strings.LastIndexByte(str, '/') + + dst.Reset() + if index == -1 { + first = true + } else { + dst.WriteString(str[:index]) } - default: - dst = append(dst, elem) + } else { + if !first { + dst.WriteByte('/') + } + dst.WriteString(elem) + first = false } } - if last := src[len(src)-1]; last == "." || last == ".." { - // Add final slash to the joined path. - dst = append(dst, "") + + if last == "." || last == ".." { + dst.WriteByte('/') } - return "/" + strings.TrimPrefix(strings.Join(dst, "/"), "/") + + return "/" + strings.TrimPrefix(dst.String(), "/") } // IsAbs reports whether the URL is absolute. diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index 92b15afad4..f02e4650d8 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -1114,6 +1114,14 @@ func TestResolvePath(t *testing.T) { } } +func BenchmarkResolvePath(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + resolvePath("a/b/c", ".././d") + } +} + var resolveReferenceTests = []struct { base, rel, expected string }{