From 7a178df0bcdfbb3a73ffa9ff2701577f3621a113 Mon Sep 17 00:00:00 2001 From: go101 Date: Wed, 22 Aug 2018 16:12:46 +0000 Subject: [PATCH] strings: use Builder in Repeat to avoid an allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: 4b2c73f3bfa0b3789268b9ea6e1ecdb984e8087c GitHub-Pull-Request: golang/go#25894 Reviewed-on: https://go-review.googlesource.com/118855 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/strings/strings.go | 24 +++++++++++++++++------- src/strings/strings_test.go | 11 +++++++++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/strings/strings.go b/src/strings/strings.go index 97d83cfde1..e0bebced63 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -523,23 +523,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. diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index bb46e136f2..d6197ed895 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -1660,8 +1660,15 @@ func BenchmarkSplitNMultiByteSeparator(b *testing.B) { } func BenchmarkRepeat(b *testing.B) { - for i := 0; i < b.N; i++ { - Repeat("-", 80) + s := "0123456789" + for _, n := range []int{5, 10} { + for _, c := range []int{1, 2, 6} { + b.Run(fmt.Sprintf("%dx%d", n, c), func(b *testing.B) { + for i := 0; i < b.N; i++ { + Repeat(s[:n], c) + } + }) + } } }