]> Cypherpunks repositories - gostls13.git/commitdiff
net/url: improve performance for resolvePath
authorimxyb <xyb4638@gmail.com>
Wed, 28 Oct 2020 21:26:04 +0000 (21:26 +0000)
committerEmmanuel Odeke <emmanuel@orijtech.com>
Wed, 28 Oct 2020 21:40:08 +0000 (21:40 +0000)
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 <emmanuel@orijtech.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>

src/net/url/url.go
src/net/url/url_test.go

index c93def0bd77487c8cc74748e6ca5e0b876a6aff8..d90f5f06b548b03baccd81256ec614817a728a24 100644 (file)
@@ -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.
index 92b15afad4d9bea66b394fda96fdead8348644e1..f02e4650d87ecf3c216684646c5066ced1ef8503 100644 (file)
@@ -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
 }{