1
0
mirror of https://github.com/golang/go synced 2024-11-25 01:08:02 -07:00

bytes, strings: add CutByte

CutByte optimizes slicing operations for single-byte
separators, offering a more efficient alternative when only a single byte
is involved.

There is more discussion on https://golang.org/issue/67101.

Fixes #67101.
This commit is contained in:
aimuz 2024-04-29 15:49:57 +08:00
parent db5f2b4153
commit ed17861607
4 changed files with 64 additions and 0 deletions

View File

@ -1336,6 +1336,19 @@ func Cut(s, sep []byte) (before, after []byte, found bool) {
return s, nil, false return s, nil, false
} }
// CutByte slices s around the first instance of sep,
// returning the text before and after sep.
// The found result reports whether sep appears in s.
// If sep does not appear in s, cut returns s, nil, false.
//
// CutByte returns slices of the original slice s, not copies.
func CutByte(s []byte, sep byte) (before, after []byte, found bool) {
if i := IndexByte(s, sep); i >= 0 {
return s[:i], s[i+1:], true
}
return s, nil, false
}
// Clone returns a copy of b[:len(b)]. // Clone returns a copy of b[:len(b)].
// The result may have additional unused capacity. // The result may have additional unused capacity.
// Clone(nil) returns nil. // Clone(nil) returns nil.

View File

@ -1742,6 +1742,26 @@ func TestCut(t *testing.T) {
} }
} }
var cutByteTests = []struct {
s string
sep byte
before, after string
found bool
}{
{"abc", 'b', "a", "c", true},
{"abc", 'a', "", "bc", true},
{"abc", 'c', "ab", "", true},
{"", 'd', "", "", false},
}
func TestCutByte(t *testing.T) {
for _, tt := range cutByteTests {
if before, after, found := CutByte([]byte(tt.s), tt.sep); string(before) != tt.before || string(after) != tt.after || found != tt.found {
t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
}
}
}
var cutPrefixTests = []struct { var cutPrefixTests = []struct {
s, sep string s, sep string
after string after string

View File

@ -1315,6 +1315,17 @@ func Cut(s, sep string) (before, after string, found bool) {
return s, "", false return s, "", false
} }
// CutByte slices s around the first instance of sep,
// returning the text before and after sep.
// The found result reports whether sep appears in s.
// If sep does not appear in s, cut returns s, "", false.
func CutByte(s string, sep byte) (before, after string, found bool) {
if i := IndexByte(s, sep); i >= 0 {
return s[:i], s[i+1:], true
}
return s, "", false
}
// CutPrefix returns s without the provided leading prefix string // CutPrefix returns s without the provided leading prefix string
// and reports whether it found the prefix. // and reports whether it found the prefix.
// If s doesn't start with prefix, CutPrefix returns s, false. // If s doesn't start with prefix, CutPrefix returns s, false.

View File

@ -1669,6 +1669,26 @@ func TestCut(t *testing.T) {
} }
} }
var cutByteTests = []struct {
s string
sep byte
before, after string
found bool
}{
{"abc", 'b', "a", "c", true},
{"abc", 'a', "", "bc", true},
{"abc", 'c', "ab", "", true},
{"", 'd', "", "", false},
}
func TestCutByte(t *testing.T) {
for _, tt := range cutByteTests {
if before, after, found := CutByte(tt.s, tt.sep); before != tt.before || after != tt.after || found != tt.found {
t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
}
}
}
var cutPrefixTests = []struct { var cutPrefixTests = []struct {
s, sep string s, sep string
after string after string