Skip to content

Commit 7a178df

Browse files
TapirLiubradfitz
authored andcommitted
strings: use Builder in Repeat to avoid an allocation
name old time/op new time/op delta Repeat/5x1-4 95.9ns ± 2% 70.1ns ± 2% -26.93% (p=0.000 n=9+10) Repeat/5x2-4 146ns ± 3% 100ns ± 2% -31.99% (p=0.000 n=10+10) Repeat/5x6-4 203ns ± 3% 140ns ± 4% -30.77% (p=0.000 n=10+10) Repeat/10x1-4 139ns ± 3% 92ns ± 4% -34.08% (p=0.000 n=10+10) Repeat/10x2-4 188ns ± 4% 122ns ± 2% -35.34% (p=0.000 n=10+10) Repeat/10x6-4 264ns ± 5% 179ns ± 4% -32.15% (p=0.000 n=10+10) name old alloc/op new alloc/op delta Repeat/5x1-4 10.0B ± 0% 5.0B ± 0% -50.00% (p=0.000 n=10+10) Repeat/5x2-4 32.0B ± 0% 16.0B ± 0% -50.00% (p=0.000 n=10+10) Repeat/5x6-4 64.0B ± 0% 32.0B ± 0% -50.00% (p=0.000 n=10+10) Repeat/10x1-4 32.0B ± 0% 16.0B ± 0% -50.00% (p=0.000 n=10+10) Repeat/10x2-4 64.0B ± 0% 32.0B ± 0% -50.00% (p=0.000 n=10+10) Repeat/10x6-4 128B ± 0% 64B ± 0% -50.00% (p=0.000 n=10+10) Change-Id: I6619336da636df39c560f6cc481519f48c6e8176 GitHub-Last-Rev: 4b2c73f GitHub-Pull-Request: golang#25894 Reviewed-on: https://go-review.googlesource.com/118855 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 6a11e1e commit 7a178df

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

src/strings/strings.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -523,23 +523,33 @@ func Map(mapping func(rune) rune, s string) string {
523523
// It panics if count is negative or if
524524
// the result of (len(s) * count) overflows.
525525
func Repeat(s string, count int) string {
526+
if count == 0 {
527+
return ""
528+
}
529+
526530
// Since we cannot return an error on overflow,
527531
// we should panic if the repeat will generate
528532
// an overflow.
529533
// See Issue golang.org/issue/16237
530534
if count < 0 {
531535
panic("strings: negative Repeat count")
532-
} else if count > 0 && len(s)*count/count != len(s) {
536+
} else if len(s)*count/count != len(s) {
533537
panic("strings: Repeat count causes overflow")
534538
}
535539

536-
b := make([]byte, len(s)*count)
537-
bp := copy(b, s)
538-
for bp < len(b) {
539-
copy(b[bp:], b[:bp])
540-
bp *= 2
540+
n := len(s) * count
541+
var b Builder
542+
b.Grow(n)
543+
b.WriteString(s)
544+
for b.Len() < n {
545+
if b.Len() <= n/2 {
546+
b.WriteString(b.String())
547+
} else {
548+
b.WriteString(b.String()[:n-b.Len()])
549+
break
550+
}
541551
}
542-
return string(b)
552+
return b.String()
543553
}
544554

545555
// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.

src/strings/strings_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,8 +1660,15 @@ func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
16601660
}
16611661

16621662
func BenchmarkRepeat(b *testing.B) {
1663-
for i := 0; i < b.N; i++ {
1664-
Repeat("-", 80)
1663+
s := "0123456789"
1664+
for _, n := range []int{5, 10} {
1665+
for _, c := range []int{1, 2, 6} {
1666+
b.Run(fmt.Sprintf("%dx%d", n, c), func(b *testing.B) {
1667+
for i := 0; i < b.N; i++ {
1668+
Repeat(s[:n], c)
1669+
}
1670+
})
1671+
}
16651672
}
16661673
}
16671674

0 commit comments

Comments
 (0)