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/#01-8     92.92n ± 0%   94.63n ± 0%  +1.84% (p=0.000 n=20)
QueryEscape/#02-8     75.44n ± 0%   73.32n ± 0%  -2.80% (p=0.000 n=20)
QueryEscape/#03-8     143.4n ± 0%   136.6n ± 0%  -4.71% (p=0.000 n=20)
QueryEscape/#04-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/#01-8      94.99n ± 0%   95.86n ± 0%  +0.91% (p=0.000 n=20)
PathEscape/#02-8      75.40n ± 1%   71.50n ± 1%  -5.18% (p=0.000 n=20)
PathEscape/#03-8      143.4n ± 0%   136.2n ± 0%  -4.99% (p=0.000 n=20)
PathEscape/#04-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/#01-8   137.4n ± 1%   137.9n ± 1%       ~ (p=0.297 n=20)
QueryUnescape/#02-8   114.0n ± 0%   122.3n ± 1%  +7.24% (p=0.000 n=20)
QueryUnescape/#03-8   271.8n ± 0%   260.7n ± 1%  -4.08% (p=0.000 n=20)
QueryUnescape/#04-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/#01-8    138.5n ± 1%   141.3n ± 0%  +2.06% (p=0.000 n=20)
PathUnescape/#02-8    114.0n ± 0%   121.5n ± 0%  +6.62% (p=0.000 n=20)
PathUnescape/#03-8    273.1n ± 1%   260.1n ± 0%  -4.76% (p=0.000 n=20)
PathUnescape/#04-8    1.431µ ± 1%   1.359µ ± 0%  -5.07% (p=0.000 n=20)
geomean               160.4n        156.9n       -2.14%

Updates #17860

Change-Id: If64ac3e9c62c41f672db06cfd7eab7357e934e6d
GitHub-Last-Rev: 1da047ac75
GitHub-Pull-Request: golang/go#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>
This commit is contained in:
Julien Cretel
2025-10-27 12:40:37 +00:00
committed by t hepudds
parent 5f4ec3541f
commit 92decdcbaa

View File

@@ -56,17 +56,9 @@ func ishex(c byte) bool {
return table[c]&hexChar != 0
}
// Precondition: ishex(c) is true.
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
default:
panic("invalid hex character")
}
return 9*(c>>6) + (c & 15)
}
type EscapeError string
@@ -161,19 +153,24 @@ func unescape(s string, mode encoding) (string, error) {
return s, nil
}
var unescapedPlusSign byte
switch mode {
case encodeQueryComponent:
unescapedPlusSign = ' '
default:
unescapedPlusSign = '+'
}
var t strings.Builder
t.Grow(len(s) - 2*n)
for i := 0; i < len(s); i++ {
switch s[i] {
case '%':
// In the loop above, we established that unhex's precondition is
// fulfilled for both s[i+1] and s[i+2].
t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2]))
i += 2
case '+':
if mode == encodeQueryComponent {
t.WriteByte(' ')
} else {
t.WriteByte('+')
}
t.WriteByte(unescapedPlusSign)
default:
t.WriteByte(s[i])
}
@@ -195,8 +192,7 @@ func PathEscape(s string) string {
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
for _, c := range []byte(s) {
if shouldEscape(c, mode) {
if c == ' ' && mode == encodeQueryComponent {
spaceCount++
@@ -231,8 +227,8 @@ func escape(s string, mode encoding) string {
}
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
for _, c := range []byte(s) {
switch {
case c == ' ' && mode == encodeQueryComponent:
t[j] = '+'
j++
@@ -242,7 +238,7 @@ func escape(s string, mode encoding) string {
t[j+2] = upperhex[c&15]
j += 3
default:
t[j] = s[i]
t[j] = c
j++
}
}