diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 1871814c6e0..72ccdfc98eb 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -1330,6 +1330,12 @@ func Index(s, sep []byte) int { // // Cut returns slices of the original slice s, not copies. func Cut(s, sep []byte) (before, after []byte, found bool) { + if len(sep) == 1 { + if i := IndexByte(s, sep[0]); i >= 0 { + return s[:i], s[i+1:], true + } + return s, nil, false + } if i := Index(s, sep); i >= 0 { return s[:i], s[i+len(sep):], true } diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index 5e8cf85fd90..7026ad9c583 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -2263,3 +2263,31 @@ func TestClone(t *testing.T) { } } } + +func BenchmarkCut(b *testing.B) { + b.ReportAllocs() + + for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { + s := Repeat(append(append(Repeat([]byte(" "), skip), 'a', 'a'), Repeat([]byte(" "), skip)...), 1<<16/skip) + b.Run(fmt.Sprintf("Cut-One/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, []byte{'a'}) + } + }) + b.Run(fmt.Sprintf("Cut-Two/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, []byte{'a', 'a'}) + } + }) + b.Run(fmt.Sprintf("Cut-One-Nil/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, []byte{'c'}) + } + }) + b.Run(fmt.Sprintf("Cut-Two-Nil/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, []byte{'c', 'c'}) + } + }) + } +} diff --git a/src/internal/stringslite/strings.go b/src/internal/stringslite/strings.go index ce8a913297b..2b30808c528 100644 --- a/src/internal/stringslite/strings.go +++ b/src/internal/stringslite/strings.go @@ -103,6 +103,12 @@ func Index(s, substr string) int { } func Cut(s, sep string) (before, after string, found bool) { + if len(sep) == 1 { + if i := IndexByte(s, sep[0]); i >= 0 { + return s[:i], s[i+1:], true + } + return s, "", false + } if i := Index(s, sep); i >= 0 { return s[:i], s[i+len(sep):], true } diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index ac493c7dcd4..37db3cb3a27 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -2071,3 +2071,31 @@ func BenchmarkReplaceAll(b *testing.B) { stringSink = ReplaceAll("banana", "a", "<>") } } + +func BenchmarkCut(b *testing.B) { + b.ReportAllocs() + + for _, skip := range [...]int{2, 4, 8, 16, 32, 64} { + s := Repeat(Repeat(" ", skip)+"aa"+Repeat(" ", skip), 1<<16/skip) + b.Run(fmt.Sprintf("Cut-One/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, "a") + } + }) + b.Run(fmt.Sprintf("Cut-Two/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, "aa") + } + }) + b.Run(fmt.Sprintf("Cut-One-Nil/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, "c") + } + }) + b.Run(fmt.Sprintf("Cut-Two-Nil/%d", skip), func(b *testing.B) { + for range b.N { + _, _, _ = Cut(s, "cc") + } + }) + } +}