From c644a4ddfe9afe8ab79a6d3c776117cdb11dd2b7 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sat, 30 Jun 2012 22:08:53 +1000 Subject: [PATCH] path/filepath: avoid allocation in Clean of cleaned path even on windows (fix build) R=golang-dev, rsc CC=golang-dev https://golang.org/cl/6344049 --- src/pkg/path/filepath/path.go | 43 +++++++++++++++++---------- src/pkg/path/filepath/path_plan9.go | 8 ++--- src/pkg/path/filepath/path_unix.go | 8 ++--- src/pkg/path/filepath/path_windows.go | 22 +++++++------- 4 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go index 7b6a9bd5d2..bb27f1c851 100644 --- a/src/pkg/path/filepath/path.go +++ b/src/pkg/path/filepath/path.go @@ -18,26 +18,28 @@ import ( // and retrieving the final string. It does not allocate a buffer // to hold the output until that output diverges from s. type lazybuf struct { - s string - buf []byte - w int + path string + buf []byte + w int + volAndPath string + volLen int } func (b *lazybuf) index(i int) byte { if b.buf != nil { return b.buf[i] } - return b.s[i] + return b.path[i] } func (b *lazybuf) append(c byte) { if b.buf == nil { - if b.w < len(b.s) && b.s[b.w] == c { + if b.w < len(b.path) && b.path[b.w] == c { b.w++ return } - b.buf = make([]byte, len(b.s)) - copy(b.buf, b.s[:b.w]) + b.buf = make([]byte, len(b.path)) + copy(b.buf, b.path[:b.w]) } b.buf[b.w] = c b.w++ @@ -45,9 +47,9 @@ func (b *lazybuf) append(c byte) { func (b *lazybuf) string() string { if b.buf == nil { - return b.s[:b.w] + return b.volAndPath[:b.volLen+b.w] } - return string(b.buf[:b.w]) + return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) } const ( @@ -77,14 +79,15 @@ const ( // Getting Dot-Dot Right,'' // http://plan9.bell-labs.com/sys/doc/lexnames.html func Clean(path string) string { - vol := VolumeName(path) - path = path[len(vol):] + originalPath := path + volLen := volumeNameLen(path) + path = path[volLen:] if path == "" { - if len(vol) > 1 && vol[1] != ':' { + if volLen > 1 && originalPath[1] != ':' { // should be UNC - return FromSlash(vol) + return FromSlash(originalPath) } - return vol + "." + return originalPath + "." } rooted := os.IsPathSeparator(path[0]) @@ -94,7 +97,7 @@ func Clean(path string) string { // dotdot is index in buf where .. must stop, either because // it is the leading slash or it is a leading ../../.. prefix. n := len(path) - out := lazybuf{s: path} + out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} r, dotdot := 0, 0 if rooted { out.append(Separator) @@ -146,7 +149,7 @@ func Clean(path string) string { out.append('.') } - return FromSlash(vol + out.string()) + return FromSlash(out.string()) } // ToSlash returns the result of replacing each separator character @@ -448,3 +451,11 @@ func Dir(path string) string { } return vol + dir } + +// VolumeName returns leading volume name. +// Given "C:\foo\bar" it returns "C:" under windows. +// Given "\\host\share\foo" it returns "\\host\share". +// On other platforms it returns "". +func VolumeName(path string) (v string) { + return path[:volumeNameLen(path)] +} diff --git a/src/pkg/path/filepath/path_plan9.go b/src/pkg/path/filepath/path_plan9.go index 59a5812dd0..0c938d89da 100644 --- a/src/pkg/path/filepath/path_plan9.go +++ b/src/pkg/path/filepath/path_plan9.go @@ -11,10 +11,10 @@ func IsAbs(path string) bool { return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") } -// VolumeName returns the leading volume name on Windows. -// It returns "" elsewhere. -func VolumeName(path string) string { - return "" +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 } // HasPrefix exists for historical compatibility and should not be used. diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go index 305e307272..3b48d14e08 100644 --- a/src/pkg/path/filepath/path_unix.go +++ b/src/pkg/path/filepath/path_unix.go @@ -13,10 +13,10 @@ func IsAbs(path string) bool { return strings.HasPrefix(path, "/") } -// VolumeName returns the leading volume name on Windows. -// It returns "" elsewhere. -func VolumeName(path string) string { - return "" +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 } // HasPrefix exists for historical compatibility and should not be used. diff --git a/src/pkg/path/filepath/path_windows.go b/src/pkg/path/filepath/path_windows.go index 3dcd030219..db2b57ec00 100644 --- a/src/pkg/path/filepath/path_windows.go +++ b/src/pkg/path/filepath/path_windows.go @@ -14,29 +14,27 @@ func isSlash(c uint8) bool { // IsAbs returns true if the path is absolute. func IsAbs(path string) (b bool) { - v := VolumeName(path) - if v == "" { + l := volumeNameLen(path) + if l == 0 { return false } - path = path[len(v):] + path = path[l:] if path == "" { return false } return isSlash(path[0]) } -// VolumeName returns leading volume name. -// Given "C:\foo\bar" it returns "C:" under windows. -// Given "\\host\share\foo" it returns "\\host\share". -// On other platforms it returns "". -func VolumeName(path string) (v string) { +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { if len(path) < 2 { - return "" + return 0 } // with drive letter c := path[0] if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { - return path[:2] + return 2 } // is it UNC if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && @@ -56,13 +54,13 @@ func VolumeName(path string) (v string) { break } } - return path[:n] + return n } break } } } - return "" + return 0 } // HasPrefix exists for historical compatibility and should not be used. -- 2.48.1