]> Cypherpunks repositories - gostls13.git/commitdiff
net/url: use bytes.Buffer in (*URL).String
authorAndrew Gerrand <adg@golang.org>
Wed, 23 Jan 2013 01:17:11 +0000 (12:17 +1100)
committerAndrew Gerrand <adg@golang.org>
Wed, 23 Jan 2013 01:17:11 +0000 (12:17 +1100)
BenchmarkString before:

        11990 ns/op            1621 B/op         73 allocs/op

Using bytes.Buffer:

        8774 ns/op            1994 B/op         40 allocs/op

I also tried making a version of escape() that writes directly to the
bytes.Buffer, but it only saved 1 alloc/op and increased CPU time by
about 10%. Didn't seem worth the extra code path.

R=bradfitz
CC=golang-dev
https://golang.org/cl/7182050

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

index 22425b33681f39ebbc0259932b0af6b4d8affe20..68f2c2f6e7e176d19f4671dffb7ed5b7be534f2d 100644 (file)
@@ -434,32 +434,35 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 
 // String reassembles the URL into a valid URL string.
 func (u *URL) String() string {
-       // TODO: Rewrite to use bytes.Buffer
-       result := ""
+       var buf bytes.Buffer
        if u.Scheme != "" {
-               result += u.Scheme + ":"
+               buf.WriteString(u.Scheme)
+               buf.WriteByte(':')
        }
        if u.Opaque != "" {
-               result += u.Opaque
+               buf.WriteString(u.Opaque)
        } else {
                if u.Scheme != "" || u.Host != "" || u.User != nil {
-                       result += "//"
+                       buf.WriteString("//")
                        if u := u.User; u != nil {
-                               result += u.String() + "@"
+                               buf.WriteString(u.String())
+                               buf.WriteByte('@')
                        }
                        if h := u.Host; h != "" {
-                               result += u.Host
+                               buf.WriteString(h)
                        }
                }
-               result += escape(u.Path, encodePath)
+               buf.WriteString(escape(u.Path, encodePath))
        }
        if u.RawQuery != "" {
-               result += "?" + u.RawQuery
+               buf.WriteByte('?')
+               buf.WriteString(u.RawQuery)
        }
        if u.Fragment != "" {
-               result += "#" + escape(u.Fragment, encodeFragment)
+               buf.WriteByte('#')
+               buf.WriteString(escape(u.Fragment, encodeFragment))
        }
-       return result
+       return buf.String()
 }
 
 // Values maps a string key to a list of values.
index 9eddf730e09e242c770f0d5bc3b16d6cd1df51cf..cd3b0b9e8c7a734200dc941687bcc38b68b20020 100644 (file)
@@ -280,6 +280,30 @@ func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests [
        }
 }
 
+func BenchmarkString(b *testing.B) {
+       b.StopTimer()
+       b.ReportAllocs()
+       for _, tt := range urltests {
+               u, err := Parse(tt.in)
+               if err != nil {
+                       b.Errorf("Parse(%q) returned error %s", tt.in, err)
+                       continue
+               }
+               if tt.roundtrip == "" {
+                       continue
+               }
+               b.StartTimer()
+               var g string
+               for i := 0; i < b.N; i++ {
+                       g = u.String()
+               }
+               b.StopTimer()
+               if w := tt.roundtrip; g != w {
+                       b.Errorf("Parse(%q).String() == %q, want %q", tt.in, g, w)
+               }
+       }
+}
+
 func TestParse(t *testing.T) {
        DoTest(t, Parse, "Parse", urltests)
 }