aboutsummaryrefslogtreecommitdiff
path: root/src/strings/strings.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/strings/strings.go')
-rw-r--r--src/strings/strings.go99
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