Skip to content

Commit 92decdc

Browse files
jub0bsthepudds
authored andcommitted
net/url: further speed up escape and unescape
This change is a follow-up to CL 712200. It further simplifies and speeds up functions escape and unescape. Here are some benchmark results (no change to allocations): goos: darwin goarch: amd64 pkg: net/url cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ go/src/old │ go/src/new │ │ sec/op │ sec/op vs base │ QueryEscape/#00-8 34.58n ± 1% 31.97n ± 1% -7.55% (p=0.000 n=20) QueryEscape/#1-8 92.92n ± 0% 94.63n ± 0% +1.84% (p=0.000 n=20) QueryEscape/#2-8 75.44n ± 0% 73.32n ± 0% -2.80% (p=0.000 n=20) QueryEscape/#3-8 143.4n ± 0% 136.6n ± 0% -4.71% (p=0.000 n=20) QueryEscape/golang#4-8 918.8n ± 1% 838.3n ± 0% -8.76% (p=0.000 n=20) PathEscape/#00-8 43.93n ± 0% 42.86n ± 0% -2.44% (p=0.000 n=20) PathEscape/#1-8 94.99n ± 0% 95.86n ± 0% +0.91% (p=0.000 n=20) PathEscape/#2-8 75.40n ± 1% 71.50n ± 1% -5.18% (p=0.000 n=20) PathEscape/#3-8 143.4n ± 0% 136.2n ± 0% -4.99% (p=0.000 n=20) PathEscape/golang#4-8 871.8n ± 0% 822.7n ± 0% -5.63% (p=0.000 n=20) QueryUnescape/#00-8 52.64n ± 1% 51.19n ± 0% -2.75% (p=0.000 n=20) QueryUnescape/#1-8 137.4n ± 1% 137.9n ± 1% ~ (p=0.297 n=20) QueryUnescape/#2-8 114.0n ± 0% 122.3n ± 1% +7.24% (p=0.000 n=20) QueryUnescape/#3-8 271.8n ± 0% 260.7n ± 1% -4.08% (p=0.000 n=20) QueryUnescape/golang#4-8 1.390µ ± 1% 1.355µ ± 0% -2.52% (p=0.000 n=20) PathUnescape/#00-8 52.45n ± 1% 53.03n ± 1% +1.10% (p=0.008 n=20) PathUnescape/#1-8 138.5n ± 1% 141.3n ± 0% +2.06% (p=0.000 n=20) PathUnescape/#2-8 114.0n ± 0% 121.5n ± 0% +6.62% (p=0.000 n=20) PathUnescape/#3-8 273.1n ± 1% 260.1n ± 0% -4.76% (p=0.000 n=20) PathUnescape/golang#4-8 1.431µ ± 1% 1.359µ ± 0% -5.07% (p=0.000 n=20) geomean 160.4n 156.9n -2.14% Updates golang#17860 Change-Id: If64ac3e9c62c41f672db06cfd7eab7357e934e6d GitHub-Last-Rev: 1da047a GitHub-Pull-Request: golang#76048 Reviewed-on: https://go-review.googlesource.com/c/go/+/714900 Reviewed-by: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
1 parent 5f4ec35 commit 92decdc

File tree

1 file changed

+16
-20
lines changed

1 file changed

+16
-20
lines changed

src/net/url/url.go

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,9 @@ func ishex(c byte) bool {
5656
return table[c]&hexChar != 0
5757
}
5858

59+
// Precondition: ishex(c) is true.
5960
func unhex(c byte) byte {
60-
switch {
61-
case '0' <= c && c <= '9':
62-
return c - '0'
63-
case 'a' <= c && c <= 'f':
64-
return c - 'a' + 10
65-
case 'A' <= c && c <= 'F':
66-
return c - 'A' + 10
67-
default:
68-
panic("invalid hex character")
69-
}
61+
return 9*(c>>6) + (c & 15)
7062
}
7163

7264
type EscapeError string
@@ -161,19 +153,24 @@ func unescape(s string, mode encoding) (string, error) {
161153
return s, nil
162154
}
163155

156+
var unescapedPlusSign byte
157+
switch mode {
158+
case encodeQueryComponent:
159+
unescapedPlusSign = ' '
160+
default:
161+
unescapedPlusSign = '+'
162+
}
164163
var t strings.Builder
165164
t.Grow(len(s) - 2*n)
166165
for i := 0; i < len(s); i++ {
167166
switch s[i] {
168167
case '%':
168+
// In the loop above, we established that unhex's precondition is
169+
// fulfilled for both s[i+1] and s[i+2].
169170
t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2]))
170171
i += 2
171172
case '+':
172-
if mode == encodeQueryComponent {
173-
t.WriteByte(' ')
174-
} else {
175-
t.WriteByte('+')
176-
}
173+
t.WriteByte(unescapedPlusSign)
177174
default:
178175
t.WriteByte(s[i])
179176
}
@@ -195,8 +192,7 @@ func PathEscape(s string) string {
195192

196193
func escape(s string, mode encoding) string {
197194
spaceCount, hexCount := 0, 0
198-
for i := 0; i < len(s); i++ {
199-
c := s[i]
195+
for _, c := range []byte(s) {
200196
if shouldEscape(c, mode) {
201197
if c == ' ' && mode == encodeQueryComponent {
202198
spaceCount++
@@ -231,8 +227,8 @@ func escape(s string, mode encoding) string {
231227
}
232228

233229
j := 0
234-
for i := 0; i < len(s); i++ {
235-
switch c := s[i]; {
230+
for _, c := range []byte(s) {
231+
switch {
236232
case c == ' ' && mode == encodeQueryComponent:
237233
t[j] = '+'
238234
j++
@@ -242,7 +238,7 @@ func escape(s string, mode encoding) string {
242238
t[j+2] = upperhex[c&15]
243239
j += 3
244240
default:
245-
t[j] = s[i]
241+
t[j] = c
246242
j++
247243
}
248244
}

0 commit comments

Comments
 (0)