Commit c644a4dd authored by Alex Brainman's avatar Alex Brainman

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
parent 33d2b495
...@@ -18,26 +18,28 @@ import ( ...@@ -18,26 +18,28 @@ import (
// and retrieving the final string. It does not allocate a buffer // and retrieving the final string. It does not allocate a buffer
// to hold the output until that output diverges from s. // to hold the output until that output diverges from s.
type lazybuf struct { type lazybuf struct {
s string path string
buf []byte buf []byte
w int w int
volAndPath string
volLen int
} }
func (b *lazybuf) index(i int) byte { func (b *lazybuf) index(i int) byte {
if b.buf != nil { if b.buf != nil {
return b.buf[i] return b.buf[i]
} }
return b.s[i] return b.path[i]
} }
func (b *lazybuf) append(c byte) { func (b *lazybuf) append(c byte) {
if b.buf == nil { 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++ b.w++
return return
} }
b.buf = make([]byte, len(b.s)) b.buf = make([]byte, len(b.path))
copy(b.buf, b.s[:b.w]) copy(b.buf, b.path[:b.w])
} }
b.buf[b.w] = c b.buf[b.w] = c
b.w++ b.w++
...@@ -45,9 +47,9 @@ func (b *lazybuf) append(c byte) { ...@@ -45,9 +47,9 @@ func (b *lazybuf) append(c byte) {
func (b *lazybuf) string() string { func (b *lazybuf) string() string {
if b.buf == nil { 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 ( const (
...@@ -77,14 +79,15 @@ const ( ...@@ -77,14 +79,15 @@ const (
// Getting Dot-Dot Right,'' // Getting Dot-Dot Right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html // http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string { func Clean(path string) string {
vol := VolumeName(path) originalPath := path
path = path[len(vol):] volLen := volumeNameLen(path)
path = path[volLen:]
if path == "" { if path == "" {
if len(vol) > 1 && vol[1] != ':' { if volLen > 1 && originalPath[1] != ':' {
// should be UNC // should be UNC
return FromSlash(vol) return FromSlash(originalPath)
} }
return vol + "." return originalPath + "."
} }
rooted := os.IsPathSeparator(path[0]) rooted := os.IsPathSeparator(path[0])
...@@ -94,7 +97,7 @@ func Clean(path string) string { ...@@ -94,7 +97,7 @@ func Clean(path string) string {
// dotdot is index in buf where .. must stop, either because // dotdot is index in buf where .. must stop, either because
// it is the leading slash or it is a leading ../../.. prefix. // it is the leading slash or it is a leading ../../.. prefix.
n := len(path) n := len(path)
out := lazybuf{s: path} out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
r, dotdot := 0, 0 r, dotdot := 0, 0
if rooted { if rooted {
out.append(Separator) out.append(Separator)
...@@ -146,7 +149,7 @@ func Clean(path string) string { ...@@ -146,7 +149,7 @@ func Clean(path string) string {
out.append('.') out.append('.')
} }
return FromSlash(vol + out.string()) return FromSlash(out.string())
} }
// ToSlash returns the result of replacing each separator character // ToSlash returns the result of replacing each separator character
...@@ -448,3 +451,11 @@ func Dir(path string) string { ...@@ -448,3 +451,11 @@ func Dir(path string) string {
} }
return vol + dir 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)]
}
...@@ -11,10 +11,10 @@ func IsAbs(path string) bool { ...@@ -11,10 +11,10 @@ func IsAbs(path string) bool {
return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
} }
// VolumeName returns the leading volume name on Windows. // volumeNameLen returns length of the leading volume name on Windows.
// It returns "" elsewhere. // It returns 0 elsewhere.
func VolumeName(path string) string { func volumeNameLen(path string) int {
return "" return 0
} }
// HasPrefix exists for historical compatibility and should not be used. // HasPrefix exists for historical compatibility and should not be used.
......
...@@ -13,10 +13,10 @@ func IsAbs(path string) bool { ...@@ -13,10 +13,10 @@ func IsAbs(path string) bool {
return strings.HasPrefix(path, "/") return strings.HasPrefix(path, "/")
} }
// VolumeName returns the leading volume name on Windows. // volumeNameLen returns length of the leading volume name on Windows.
// It returns "" elsewhere. // It returns 0 elsewhere.
func VolumeName(path string) string { func volumeNameLen(path string) int {
return "" return 0
} }
// HasPrefix exists for historical compatibility and should not be used. // HasPrefix exists for historical compatibility and should not be used.
......
...@@ -14,29 +14,27 @@ func isSlash(c uint8) bool { ...@@ -14,29 +14,27 @@ func isSlash(c uint8) bool {
// IsAbs returns true if the path is absolute. // IsAbs returns true if the path is absolute.
func IsAbs(path string) (b bool) { func IsAbs(path string) (b bool) {
v := VolumeName(path) l := volumeNameLen(path)
if v == "" { if l == 0 {
return false return false
} }
path = path[len(v):] path = path[l:]
if path == "" { if path == "" {
return false return false
} }
return isSlash(path[0]) return isSlash(path[0])
} }
// VolumeName returns leading volume name. // volumeNameLen returns length of the leading volume name on Windows.
// Given "C:\foo\bar" it returns "C:" under windows. // It returns 0 elsewhere.
// Given "\\host\share\foo" it returns "\\host\share". func volumeNameLen(path string) int {
// On other platforms it returns "".
func VolumeName(path string) (v string) {
if len(path) < 2 { if len(path) < 2 {
return "" return 0
} }
// with drive letter // with drive letter
c := path[0] c := path[0]
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
return path[:2] return 2
} }
// is it UNC // is it UNC
if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
...@@ -56,13 +54,13 @@ func VolumeName(path string) (v string) { ...@@ -56,13 +54,13 @@ func VolumeName(path string) (v string) {
break break
} }
} }
return path[:n] return n
} }
break break
} }
} }
} }
return "" return 0
} }
// HasPrefix exists for historical compatibility and should not be used. // HasPrefix exists for historical compatibility and should not be used.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment