From c1ad6e7474ffbce83189305e4c8a3b30fba2a98f Mon Sep 17 00:00:00 2001 From: Tapir Liu Date: Thu, 14 Jun 2018 11:43:30 -0400 Subject: [PATCH] Implement Repeat with Builder to avoid one unnecessary allocation. benchmark old ns/op new ns/op delta BenchmarkRepeat/length-1-4 290 225 -22.41% BenchmarkRepeat/length-5-4 621 391 -37.04% BenchmarkRepeat/length-10-4 900 556 -38.22% benchmark old allocs new allocs delta BenchmarkRepeat/length-1-4 2 1 -50.00% BenchmarkRepeat/length-5-4 2 1 -50.00% BenchmarkRepeat/length-10-4 2 1 -50.00% --- src/strings/strings.go | 23 ++++++++++++++++------- src/strings/strings_test.go | 16 +++++++++++++++- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/strings/strings.go b/src/strings/strings.go index adbbe742fc..a0a31f7c58 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -541,17 +541,26 @@ func Repeat(s string, count int) string { // 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 count == 0 { + return "" + } 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 + k, n := len(s), len(s)*count + var b Builder + b.Grow(n) + b.WriteString(s) + for k < n { + if k + k < n { + b.WriteString(b.String()) + k = k + k + } else { + b.WriteString(b.String()[:n-k]) + 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 78bc573e5f..ffc4ab0964 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -1648,7 +1648,21 @@ func BenchmarkSplitNMultiByteSeparator(b *testing.B) { func BenchmarkRepeat(b *testing.B) { for i := 0; i < b.N; i++ { - Repeat("-", 80) + b.Run("length-1", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Repeat("-", 80) + } + }) + b.Run("length-5", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Repeat("-!@#$", 80) + } + }) + b.Run("length-10", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Repeat("-!@#$abcde", 80) + } + }) } }