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 (
// 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)]
}
......@@ -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.
......
......@@ -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.
......
......@@ -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.
......
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