Skip to content

Commit 8222db1

Browse files
committed
path: use stack buffer in CleanPath to avoid allocs in common case
1 parent f53938f commit 8222db1

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

path.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,18 @@ package httprouter
1919
//
2020
// If the result of this process is an empty string, "/" is returned
2121
func CleanPath(p string) string {
22+
const stackBufSize = 128
23+
2224
// Turn empty string into "/"
2325
if p == "" {
2426
return "/"
2527
}
2628

29+
// Reasonably sized buffer on stack to avoid allocations in the common case.
30+
// If a larger buffer is required, it gets allocated dynamically.
31+
buf := make([]byte, 0, stackBufSize)
32+
2733
n := len(p)
28-
var buf []byte
2934

3035
// Invariants:
3136
// reading from path; r is index of next byte to process.
@@ -37,7 +42,12 @@ func CleanPath(p string) string {
3742

3843
if p[0] != '/' {
3944
r = 0
40-
buf = make([]byte, n+1)
45+
46+
if n+1 > stackBufSize {
47+
buf = make([]byte, n+1)
48+
} else {
49+
buf = buf[:n+1]
50+
}
4151
buf[0] = '/'
4252
}
4353

@@ -69,7 +79,7 @@ func CleanPath(p string) string {
6979
// can backtrack
7080
w--
7181

72-
if buf == nil {
82+
if len(buf) == 0 {
7383
for w > 1 && p[w] != '/' {
7484
w--
7585
}
@@ -103,20 +113,25 @@ func CleanPath(p string) string {
103113
w++
104114
}
105115

106-
if buf == nil {
116+
if len(buf) == 0 {
107117
return p[:w]
108118
}
109119
return string(buf[:w])
110120
}
111121

112122
// internal helper to lazily create a buffer if necessary
113123
func bufApp(buf *[]byte, s string, w int, c byte) {
114-
if *buf == nil {
124+
if len(*buf) == 0 {
115125
if s[w] == c {
116126
return
117127
}
118128

119-
*buf = make([]byte, len(s))
129+
if l := len(s); l > cap(*buf) {
130+
*buf = make([]byte, len(s))
131+
} else {
132+
*buf = (*buf)[:l]
133+
}
134+
120135
copy(*buf, s[:w])
121136
}
122137
(*buf)[w] = c

0 commit comments

Comments
 (0)