Skip to content

Commit

Permalink
all: use bytes.Cut, strings.Cut
Browse files Browse the repository at this point in the history
Many uses of Index/IndexByte/IndexRune/Split/SplitN
can be written more clearly using the new Cut functions.
Do that. Also rewrite to other functions if that's clearer.

For #46336.

Change-Id: I68d024716ace41a57a8bf74455c62279bde0f448
Reviewed-on: https://go-review.googlesource.com/c/go/+/351711
Trust: Russ Cox <[email protected]>
Run-TryBot: Russ Cox <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
rsc committed Oct 6, 2021
1 parent 8e36ab0 commit 4d8db00
Show file tree
Hide file tree
Showing 78 changed files with 356 additions and 577 deletions.
9 changes: 4 additions & 5 deletions misc/cgo/errors/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@ func check(t *testing.T, file string) {
continue
}

frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2)
if len(frags) == 1 {
_, frag, ok := bytes.Cut(line, []byte("ERROR HERE: "))
if !ok {
continue
}
frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1])
re, err := regexp.Compile(frag)
re, err := regexp.Compile(fmt.Sprintf(":%d:.*%s", i+1, frag))
if err != nil {
t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frag)
continue
}
errors = append(errors, re)
Expand Down
4 changes: 2 additions & 2 deletions misc/cgo/testcshared/cshared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
args := append(adbCmd(), "exec-out")
// Propagate LD_LIBRARY_PATH to the adb shell invocation.
for _, e := range env {
if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
if strings.Contains(e, "LD_LIBRARY_PATH=") {
adbargs = append([]string{e}, adbargs...)
break
}
Expand Down Expand Up @@ -326,7 +326,7 @@ func createHeaders() error {
base, name := filepath.Split(args[0])
args[0] = filepath.Join(base, "llvm-dlltool")
var machine string
switch strings.SplitN(name, "-", 2)[0] {
switch prefix, _, _ := strings.Cut(name, "-"); prefix {
case "i686":
machine = "i386"
case "x86_64":
Expand Down
2 changes: 1 addition & 1 deletion misc/cgo/testsanitizers/cc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func (c *config) checkCSanitizer() (skip bool, err error) {
if os.IsNotExist(err) {
return true, fmt.Errorf("%#q failed to produce executable: %v", strings.Join(cmd.Args, " "), err)
}
snippet := bytes.SplitN(out, []byte{'\n'}, 2)[0]
snippet, _, _ := bytes.Cut(out, []byte("\n"))
return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet)
}

Expand Down
10 changes: 4 additions & 6 deletions misc/ios/go_ios_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,8 @@ func runOnDevice(appdir string) error {
// Device IDs as listed with ios-deploy -c.
deviceID = os.Getenv("GOIOS_DEVICE_ID")

parts := strings.SplitN(appID, ".", 2)
if len(parts) == 2 {
bundleID = parts[1]
if _, id, ok := strings.Cut(appID, "."); ok {
bundleID = id
}

if err := signApp(appdir); err != nil {
Expand Down Expand Up @@ -291,11 +290,10 @@ func findDevImage() (string, error) {
var iosVer, buildVer string
lines := bytes.Split(out, []byte("\n"))
for _, line := range lines {
spl := bytes.SplitN(line, []byte(": "), 2)
if len(spl) != 2 {
key, val, ok := strings.Cut(string(line), ": ")
if !ok {
continue
}
key, val := string(spl[0]), string(spl[1])
switch key {
case "ProductVersion":
iosVer = val
Expand Down
6 changes: 2 additions & 4 deletions misc/linkcheck/linkcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,8 @@ func crawl(url string, sourceURL string) {
}
mu.Lock()
defer mu.Unlock()
var frag string
if i := strings.Index(url, "#"); i >= 0 {
frag = url[i+1:]
url = url[:i]
if u, frag, ok := strings.Cut(url, "#"); ok {
url = u
if frag != "" {
uf := urlFrag{url, frag}
neededFrags[uf] = append(neededFrags[uf], sourceURL)
Expand Down
43 changes: 12 additions & 31 deletions src/archive/tar/strconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

// hasNUL reports whether the NUL character exists within s.
func hasNUL(s string) bool {
return strings.IndexByte(s, 0) >= 0
return strings.Contains(s, "\x00")
}

// isASCII reports whether the input is an ASCII C-style string.
Expand Down Expand Up @@ -201,10 +201,7 @@ func parsePAXTime(s string) (time.Time, error) {
const maxNanoSecondDigits = 9

// Split string into seconds and sub-seconds parts.
ss, sn := s, ""
if pos := strings.IndexByte(s, '.'); pos >= 0 {
ss, sn = s[:pos], s[pos+1:]
}
ss, sn, _ := strings.Cut(s, ".")

// Parse the seconds.
secs, err := strconv.ParseInt(ss, 10, 64)
Expand Down Expand Up @@ -254,48 +251,32 @@ func formatPAXTime(ts time.Time) (s string) {
// return the remainder as r.
func parsePAXRecord(s string) (k, v, r string, err error) {
// The size field ends at the first space.
sp := strings.IndexByte(s, ' ')
if sp == -1 {
nStr, rest, ok := strings.Cut(s, " ")
if !ok {
return "", "", s, ErrHeader
}

// Parse the first token as a decimal integer.
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
if perr != nil || n < 5 || int64(len(s)) < n {
n, perr := strconv.ParseInt(nStr, 10, 0) // Intentionally parse as native int
if perr != nil || n < 5 || n > int64(len(s)) {
return "", "", s, ErrHeader
}

afterSpace := int64(sp + 1)
beforeLastNewLine := n - 1
// In some cases, "length" was perhaps padded/malformed, and
// trying to index past where the space supposedly is goes past
// the end of the actual record.
// For example:
// "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319"
// ^ ^
// | |
// | afterSpace=35
// |
// beforeLastNewLine=29
// yet indexOf(firstSpace) MUST BE before endOfRecord.
//
// See https://golang.org/issues/40196.
if afterSpace >= beforeLastNewLine {
n -= int64(len(nStr) + 1) // convert from index in s to index in rest
if n <= 0 {
return "", "", s, ErrHeader
}

// Extract everything between the space and the final newline.
rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
rec, nl, rem := rest[:n-1], rest[n-1:n], rest[n:]
if nl != "\n" {
return "", "", s, ErrHeader
}

// The first equals separates the key from the value.
eq := strings.IndexByte(rec, '=')
if eq == -1 {
k, v, ok = strings.Cut(rec, "=")
if !ok {
return "", "", s, ErrHeader
}
k, v = rec[:eq], rec[eq+1:]

if !validPAXRecord(k, v) {
return "", "", s, ErrHeader
Expand Down Expand Up @@ -333,7 +314,7 @@ func formatPAXRecord(k, v string) (string, error) {
// for the PAX version of the USTAR string fields.
// The key must not contain an '=' character.
func validPAXRecord(k, v string) bool {
if k == "" || strings.IndexByte(k, '=') >= 0 {
if k == "" || strings.Contains(k, "=") {
return false
}
switch k {
Expand Down
4 changes: 1 addition & 3 deletions src/archive/tar/writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -988,9 +988,7 @@ func TestIssue12594(t *testing.T) {
var blk block
copy(blk[:], b.Bytes())
prefix := string(blk.toUSTAR().prefix())
if i := strings.IndexByte(prefix, 0); i >= 0 {
prefix = prefix[:i] // Truncate at the NUL terminator
}
prefix, _, _ = strings.Cut(prefix, "\x00") // Truncate at the NUL terminator
if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
}
Expand Down
2 changes: 1 addition & 1 deletion src/archive/zip/writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ func TestWriterDirAttributes(t *testing.T) {
}

binary.LittleEndian.PutUint32(sig[:], uint32(dataDescriptorSignature))
if bytes.Index(b, sig[:]) != -1 {
if bytes.Contains(b, sig[:]) {
t.Error("there should be no data descriptor")
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/cmd/doc/dirs.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,7 @@ func findCodeRoots() []Dir {
cmd.Stderr = os.Stderr
out, _ := cmd.Output()
for _, line := range strings.Split(string(out), "\n") {
i := strings.Index(line, "\t")
if i < 0 {
continue
}
path, dir := line[:i], line[i+1:]
path, dir, _ := strings.Cut(line, "\t")
if dir != "" {
list = append(list, Dir{importPath: path, dir: dir, inModule: true})
}
Expand Down
4 changes: 1 addition & 3 deletions src/cmd/doc/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,7 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
recv = "(" + recv + ") "
}
fnc := pkg.oneLineNodeDepth(n.Type, depth)
if strings.Index(fnc, "func") == 0 {
fnc = fnc[4:]
}
fnc = strings.TrimPrefix(fnc, "func")
return fmt.Sprintf("func %s%s%s", recv, name, fnc)

case *ast.TypeSpec:
Expand Down
18 changes: 7 additions & 11 deletions src/cmd/fix/typecheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
// Lazy: assume there are no nested [] in the array
// length or map key type.
if i := strings.Index(t, "]"); i >= 0 {
typeof[n] = t[i+1:]
if _, elem, ok := strings.Cut(t, "]"); ok {
typeof[n] = elem
}
}

Expand Down Expand Up @@ -575,8 +575,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
t := expand(typeof[n])
if strings.HasPrefix(t, "[") { // array or slice
// Lazy: assume there are no nested [] in the array length.
if i := strings.Index(t, "]"); i >= 0 {
et := t[i+1:]
if _, et, ok := strings.Cut(t, "]"); ok {
for _, e := range n.Elts {
if kv, ok := e.(*ast.KeyValueExpr); ok {
e = kv.Value
Expand All @@ -589,8 +588,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
}
if strings.HasPrefix(t, "map[") { // map
// Lazy: assume there are no nested [] in the map key type.
if i := strings.Index(t, "]"); i >= 0 {
kt, vt := t[4:i], t[i+1:]
if kt, vt, ok := strings.Cut(t[len("map["):], "]"); ok {
for _, e := range n.Elts {
if kv, ok := e.(*ast.KeyValueExpr); ok {
if typeof[kv.Key] == "" {
Expand Down Expand Up @@ -629,12 +627,10 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
key, value = "int", "rune"
} else if strings.HasPrefix(t, "[") {
key = "int"
if i := strings.Index(t, "]"); i >= 0 {
value = t[i+1:]
}
_, value, _ = strings.Cut(t, "]")
} else if strings.HasPrefix(t, "map[") {
if i := strings.Index(t, "]"); i >= 0 {
key, value = t[4:i], t[i+1:]
if k, v, ok := strings.Cut(t[len("map["):], "]"); ok {
key, value = k, v
}
}
changed := false
Expand Down
4 changes: 2 additions & 2 deletions src/cmd/vet/vet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
// Assume errmsg says "file:line: foo".
// Cut leading "file:line: " to avoid accidental matching of file name instead of message.
text := errmsg
if i := strings.Index(text, " "); i >= 0 {
text = text[i+1:]
if _, suffix, ok := strings.Cut(text, " "); ok {
text = suffix
}
if we.re.MatchString(text) {
matched = true
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/ecdsa/ecdsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ func TestVectors(t *testing.T) {

if line[0] == '[' {
line = line[1 : len(line)-1]
parts := strings.SplitN(line, ",", 2)
curve, hash, _ := strings.Cut(line, ",")

switch parts[0] {
switch curve {
case "P-224":
pub.Curve = elliptic.P224()
case "P-256":
Expand All @@ -234,7 +234,7 @@ func TestVectors(t *testing.T) {
pub.Curve = nil
}

switch parts[1] {
switch hash {
case "SHA-1":
h = sha1.New()
case "SHA-224":
Expand Down
10 changes: 5 additions & 5 deletions src/crypto/tls/handshake_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,18 @@ func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
o.all = append(o.all, data...)

for {
i := bytes.IndexByte(o.line, '\n')
if i < 0 {
line, next, ok := bytes.Cut(o.line, []byte("\n"))
if !ok {
break
}

if bytes.Equal([]byte(opensslEndOfHandshake), o.line[:i]) {
if bytes.Equal([]byte(opensslEndOfHandshake), line) {
o.handshakeComplete <- struct{}{}
}
if bytes.Equal([]byte(opensslReadKeyUpdate), o.line[:i]) {
if bytes.Equal([]byte(opensslReadKeyUpdate), line) {
o.readKeyUpdate <- struct{}{}
}
o.line = o.line[i+1:]
o.line = next
}

return len(data), nil
Expand Down
13 changes: 6 additions & 7 deletions src/crypto/tls/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,17 @@ func parseTestData(r io.Reader) (flows [][]byte, err error) {
// Otherwise the line is a line of hex dump that looks like:
// 00000170 fc f5 06 bf (...) |.....X{&?......!|
// (Some bytes have been omitted from the middle section.)

if i := strings.IndexByte(line, ' '); i >= 0 {
line = line[i:]
} else {
_, after, ok := strings.Cut(line, " ")
if !ok {
return nil, errors.New("invalid test data")
}
line = after

if i := strings.IndexByte(line, '|'); i >= 0 {
line = line[:i]
} else {
before, _, ok := strings.Cut(line, "|")
if !ok {
return nil, errors.New("invalid test data")
}
line = before

hexBytes := strings.Fields(line)
for _, hexByte := range hexBytes {
Expand Down
5 changes: 2 additions & 3 deletions src/crypto/x509/pem_decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,11 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
return nil, errors.New("x509: no DEK-Info header in block")
}

idx := strings.Index(dek, ",")
if idx == -1 {
mode, hexIV, ok := strings.Cut(dek, ",")
if !ok {
return nil, errors.New("x509: malformed DEK-Info header")
}

mode, hexIV := dek[:idx], dek[idx+1:]
ciph := cipherByName(mode)
if ciph == nil {
return nil, errors.New("x509: unknown encryption mode")
Expand Down
9 changes: 1 addition & 8 deletions src/encoding/asn1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,7 @@ type fieldParameters struct {
func parseFieldParameters(str string) (ret fieldParameters) {
var part string
for len(str) > 0 {
// This loop uses IndexByte and explicit slicing
// instead of strings.Split(str, ",") to reduce allocations.
i := strings.IndexByte(str, ',')
if i < 0 {
part, str = str, ""
} else {
part, str = str[:i], str[i+1:]
}
part, str, _ = strings.Cut(str, ",")
switch {
case part == "optional":
ret.optional = true
Expand Down
Loading

0 comments on commit 4d8db00

Please sign in to comment.