diff options
Diffstat (limited to 'src/strings/strings.go')
| -rw-r--r-- | src/strings/strings.go | 99 |
1 files changed, 47 insertions, 52 deletions
diff --git a/src/strings/strings.go b/src/strings/strings.go index adbbe742fc..df95715ec8 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -423,27 +423,20 @@ func Join(a []string, sep string) string { return "" case 1: return a[0] - case 2: - // Special case for common small values. - // Remove if golang.org/issue/6714 is fixed - return a[0] + sep + a[1] - case 3: - // Special case for common small values. - // Remove if golang.org/issue/6714 is fixed - return a[0] + sep + a[1] + sep + a[2] } n := len(sep) * (len(a) - 1) for i := 0; i < len(a); i++ { n += len(a[i]) } - b := make([]byte, n) - bp := copy(b, a[0]) + var b Builder + b.Grow(n) + b.WriteString(a[0]) for _, s := range a[1:] { - bp += copy(b[bp:], sep) - bp += copy(b[bp:], s) + b.WriteString(sep) + b.WriteString(s) } - return string(b) + return b.String() } // HasPrefix tests whether the string s begins with prefix. @@ -466,9 +459,7 @@ func Map(mapping func(rune) rune, s string) string { // The output buffer b is initialized on demand, the first // time a character differs. - var b []byte - // nbytes is the number of bytes encoded in b. - var nbytes int + var b Builder for i, c := range s { r := mapping(c) @@ -476,15 +467,10 @@ func Map(mapping func(rune) rune, s string) string { continue } - b = make([]byte, len(s)+utf8.UTFMax) - nbytes = copy(b, s[:i]) + b.Grow(len(s) + utf8.UTFMax) + b.WriteString(s[:i]) if r >= 0 { - if r < utf8.RuneSelf { - b[nbytes] = byte(r) - nbytes++ - } else { - nbytes += utf8.EncodeRune(b[nbytes:], r) - } + b.WriteRune(r) } if c == utf8.RuneError { @@ -501,33 +487,28 @@ func Map(mapping func(rune) rune, s string) string { break } - if b == nil { + // Fast path for unchanged input + if b.Cap() == 0 { // didn't call b.Grow above return s } for _, c := range s { r := mapping(c) - // common case - if (0 <= r && r < utf8.RuneSelf) && nbytes < len(b) { - b[nbytes] = byte(r) - nbytes++ - continue - } - - // b is not big enough or r is not a ASCII rune. if r >= 0 { - if nbytes+utf8.UTFMax >= len(b) { - // Grow the buffer. - nb := make([]byte, 2*len(b)) - copy(nb, b[:nbytes]) - b = nb + // common case + // Due to inlining, it is more performant to determine if WriteByte should be + // invoked rather than always call WriteRune + if r < utf8.RuneSelf { + b.WriteByte(byte(r)) + } else { + // r is not a ASCII rune. + b.WriteRune(r) } - nbytes += utf8.EncodeRune(b[nbytes:], r) } } - return string(b[:nbytes]) + return b.String() } // Repeat returns a new string consisting of count copies of the string s. @@ -535,23 +516,33 @@ func Map(mapping func(rune) rune, s string) string { // It panics if count is negative or if // the result of (len(s) * count) overflows. func Repeat(s string, count int) string { + if count == 0 { + return "" + } + // Since we cannot return an error on overflow, // we should panic if the repeat will generate // an overflow. // See Issue golang.org/issue/16237 if count < 0 { panic("strings: negative Repeat count") - } else if count > 0 && len(s)*count/count != len(s) { + } else if len(s)*count/count != len(s) { panic("strings: Repeat count causes overflow") } - b := make([]byte, len(s)*count) - bp := copy(b, s) - for bp < len(b) { - copy(b[bp:], b[:bp]) - bp *= 2 + n := len(s) * count + var b Builder + b.Grow(n) + b.WriteString(s) + for b.Len() < n { + if b.Len() <= n/2 { + b.WriteString(b.String()) + } else { + b.WriteString(b.String()[:n-b.Len()]) + break + } } - return string(b) + return b.String() } // ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case. @@ -616,21 +607,21 @@ func ToLower(s string) string { func ToTitle(s string) string { return Map(unicode.ToTitle, s) } // ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their -// upper case, giving priority to the special casing rules. +// upper case using the case mapping specified by c. func ToUpperSpecial(c unicode.SpecialCase, s string) string { - return Map(func(r rune) rune { return c.ToUpper(r) }, s) + return Map(c.ToUpper, s) } // ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their -// lower case, giving priority to the special casing rules. +// lower case using the case mapping specified by c. func ToLowerSpecial(c unicode.SpecialCase, s string) string { - return Map(func(r rune) rune { return c.ToLower(r) }, s) + return Map(c.ToLower, s) } // ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their // title case, giving priority to the special casing rules. func ToTitleSpecial(c unicode.SpecialCase, s string) string { - return Map(func(r rune) rune { return c.ToTitle(r) }, s) + return Map(c.ToTitle, s) } // isSeparator reports whether the rune could mark a word boundary. @@ -797,6 +788,8 @@ func Trim(s string, cutset string) string { // TrimLeft returns a slice of the string s with all leading // Unicode code points contained in cutset removed. +// +// To remove a prefix, use TrimPrefix instead. func TrimLeft(s string, cutset string) string { if s == "" || cutset == "" { return s @@ -806,6 +799,8 @@ func TrimLeft(s string, cutset string) string { // TrimRight returns a slice of the string s, with all trailing // Unicode code points contained in cutset removed. +// +// To remove a suffix, use TrimSuffix instead. func TrimRight(s string, cutset string) string { if s == "" || cutset == "" { return s |
