diff --git a/path.go b/path.go index 88669141..fb6c520d 100644 --- a/path.go +++ b/path.go @@ -54,8 +54,9 @@ func CleanPath(p string) string { trailing := n > 1 && p[n-1] == '/' // A bit more clunky without a 'lazybuf' like the path package, but the loop - // gets completely inlined (bufApp). So in contrast to the path package this - // loop has no expensive function calls (except 1x make) + // gets completely inlined (bufApp calls). + // So in contrast to the path package this loop has no expensive function + // calls (except make, if needed). for r < n { switch { @@ -91,14 +92,14 @@ func CleanPath(p string) string { } default: - // real path element. - // add slash if needed + // Real path element. + // Add slash if needed if w > 1 { bufApp(&buf, p, w, '/') w++ } - // copy element + // Copy element for r < n && p[r] != '/' { bufApp(&buf, p, w, p[r]) w++ @@ -107,26 +108,35 @@ func CleanPath(p string) string { } } - // re-append trailing slash + // Re-append trailing slash if trailing && w > 1 { bufApp(&buf, p, w, '/') w++ } + // If the original string was not modified (or only shortened at the end), + // return the respective substring of the original string. + // Otherwise return a new string from the buffer. if len(buf) == 0 { return p[:w] } return string(buf[:w]) } -// internal helper to lazily create a buffer if necessary +// Internal helper to lazily create a buffer if necessary. +// Calls to this function get inlined. func bufApp(buf *[]byte, s string, w int, c byte) { b := *buf if len(b) == 0 { + // No modification of the original string so far. + // If the next character is the same as in the original string, we do + // not yet have to allocate a buffer. if s[w] == c { return } + // Otherwise use either the stack buffer, if it is large enough, or + // allocate a new buffer on the heap, and copy all previous characters. if l := len(s); l > cap(b) { *buf = make([]byte, len(s)) } else {