]> Cypherpunks.ru repositories - gostls13.git/commitdiff
all: use bytes.Cut, strings.Cut
authorRuss Cox <rsc@golang.org>
Wed, 22 Sep 2021 14:46:32 +0000 (10:46 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 6 Oct 2021 15:53:04 +0000 (15:53 +0000)
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 <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
78 files changed:
misc/cgo/errors/errors_test.go
misc/cgo/testcshared/cshared_test.go
misc/cgo/testsanitizers/cc_test.go
misc/ios/go_ios_exec.go
misc/linkcheck/linkcheck.go
src/archive/tar/strconv.go
src/archive/tar/writer_test.go
src/archive/zip/writer_test.go
src/cmd/doc/dirs.go
src/cmd/doc/pkg.go
src/cmd/fix/typecheck.go
src/cmd/vet/vet_test.go
src/crypto/ecdsa/ecdsa_test.go
src/crypto/tls/handshake_client_test.go
src/crypto/tls/handshake_test.go
src/crypto/x509/pem_decrypt.go
src/encoding/asn1/common.go
src/encoding/json/tags.go
src/encoding/pem/pem.go
src/encoding/xml/typeinfo.go
src/encoding/xml/xml.go
src/go/build/build.go
src/go/build/build_test.go
src/go/build/read.go
src/go/build/read_test.go
src/go/constant/value_test.go
src/go/doc/comment.go
src/go/doc/headscan.go
src/go/importer/importer_test.go
src/go/printer/nodes.go
src/go/printer/printer.go
src/go/types/eval_test.go
src/html/template/attr.go
src/html/template/js.go
src/html/template/url.go
src/internal/profile/legacy_profile.go
src/mime/encodedword.go
src/mime/mediatype.go
src/net/http/cgi/child.go
src/net/http/cgi/host.go
src/net/http/cgi/host_test.go
src/net/http/client_test.go
src/net/http/cookie.go
src/net/http/fs.go
src/net/http/internal/chunked.go
src/net/http/main_test.go
src/net/http/request.go
src/net/http/response.go
src/net/http/server.go
src/net/http/transport.go
src/net/mail/message.go
src/net/main_posix_test.go
src/net/main_test.go
src/net/platform_test.go
src/net/smtp/smtp.go
src/net/textproto/reader.go
src/net/url/url.go
src/net/url/url_test.go
src/os/exec/exec.go
src/os/exec/exec_test.go
src/os/os_test.go
src/os/user/cgo_lookup_unix.go
src/os/user/lookup_unix.go
src/regexp/exec_test.go
src/regexp/regexp.go
src/regexp/syntax/parse.go
src/runtime/debug/mod.go
src/runtime/pprof/pprof_test.go
src/runtime/pprof/proto.go
src/runtime/pprof/proto_test.go
src/runtime/runtime-gdb_test.go
src/runtime/testdata/testprog/numcpu_freebsd.go
src/runtime/testdata/testprog/traceback_ancestors.go
src/strconv/fp_test.go
src/syscall/exec_linux_test.go
src/text/template/option.go
test/run.go
test/zerodivide.go

index 68a30a44fe427d434df9dc634f702fc38552aa5e..e90ed1e058d83d7318b3ebaadf2c81f5dfaef7ce 100644 (file)
@@ -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)
index 19ad8c76a838b54bad64c35635216088ff40db80..84b92d502fdb5e6b17448e1f015833af7f10e555 100644 (file)
@@ -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
                }
@@ -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":
index 384b6250e1ef168ae130f6d77a5e302341d1cd99..7af30ab5571f4934ab168cc179f620fdc0ad1674 100644 (file)
@@ -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)
        }
 
index 9e63717d9214d6eb98726bb21d9f2c993fded2ac..34a734cda780e3112fd4a15c4befca692a3ec0a2 100644 (file)
@@ -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 {
@@ -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
index 570b430da4f1cbc76f14250822406e5449978757..efe400965b2e06c7bdb9a02b5fd7d38d72cf07e6 100644 (file)
@@ -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)
index f0b61e6dba69a4fb393c8c92c694713c9defd4d6..275db6f0263f2ce8f165c265bba65a272f951bad 100644 (file)
@@ -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.
@@ -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)
@@ -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
@@ -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 {
index 43f2f5976c96514cd81394e3fa9b9ebf4b10ceed..95ce99a3ed7d1276a6093f7d6a4ee26ab77310e2 100644 (file)
@@ -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)
                }
index 97c6c5297994684ca7fcfc5ccc492025709d795c..2b73eca814f621a9a0289f24cf0b6bbe8df35c6c 100644 (file)
@@ -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")
        }
 }
index 661624cfe4c168c793d582203de163f3169634e6..f27af1d27befbe10f4fcf61fc21eed960f6e9867 100644 (file)
@@ -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})
                }
index 587f0bdc1468f2fd23a2f15d8a097a89137f4fef..822c9e16f8c51c2d032c9ede7bde54fca1bac3bc 100644 (file)
@@ -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:
index 39a53785b724d4105ccfd6d7bdd320a7f3428005..8c4beb4b6528f5717e37569f13a02b12476b5475 100644 (file)
@@ -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
                                }
                        }
 
@@ -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
@@ -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] == "" {
@@ -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
index 50dd0735fa9e7ceed0345794463e92e7a3daea4a..714ee320aee603f72975e4fd3e9d703f5825d4e8 100644 (file)
@@ -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
index 556818acf4d14ac411cfc3393746e8bb075dca56..c8390b2cc9ffc4516b79114a5d40178ba6a0c22a 100644 (file)
@@ -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":
@@ -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":
index b6eb488a4d7899bc19ad2c6e330ff8c60bf4beb4..2158f3247b941dba3890756dd2e946b2e8dc9e61 100644 (file)
@@ -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
index 9bfb1177f27d04402ae687e2e1365154bbc8a818..90ac9bd11ee2ae31d1ec654f1f9776cf5c7ed834 100644 (file)
@@ -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 {
index 781cb3de834d94c02eaad1abe3ce362e1ca7af73..682923ac531fdaca2bbcef78d2598ffcdb1dbe8e 100644 (file)
@@ -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")
index 1c712e1eff4f05bffa72da895b698a58e3cd3f92..40115df8b4b6aae141b603a360e1af6fb1761179 100644 (file)
@@ -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
index c38fd5102f6302deb1e10639dbe4552ee255837e..b490328f4c46e70aa85413ac5a4ee5a0190592e9 100644 (file)
@@ -15,10 +15,8 @@ type tagOptions string
 // parseTag splits a struct field's json tag into its name and
 // comma-separated options.
 func parseTag(tag string) (string, tagOptions) {
-       if idx := strings.Index(tag, ","); idx != -1 {
-               return tag[:idx], tagOptions(tag[idx+1:])
-       }
-       return tag, tagOptions("")
+       tag, opt, _ := strings.Cut(tag, ",")
+       return tag, tagOptions(opt)
 }
 
 // Contains reports whether a comma-separated list of options
@@ -30,15 +28,11 @@ func (o tagOptions) Contains(optionName string) bool {
        }
        s := string(o)
        for s != "" {
-               var next string
-               i := strings.Index(s, ",")
-               if i >= 0 {
-                       s, next = s[:i], s[i+1:]
-               }
-               if s == optionName {
+               var name string
+               name, s, _ = strings.Cut(s, ",")
+               if name == optionName {
                        return true
                }
-               s = next
        }
        return false
 }
index a7272da5ad3a81575c3930fd405aafb824375004..e7adf88382320d4de57851430f0ea2211f139c5a 100644 (file)
@@ -78,6 +78,7 @@ func removeSpacesAndTabs(data []byte) []byte {
 var pemStart = []byte("\n-----BEGIN ")
 var pemEnd = []byte("\n-----END ")
 var pemEndOfLine = []byte("-----")
+var colon = []byte(":")
 
 // Decode will find the next PEM formatted block (certificate, private key
 // etc) in the input. It returns that block and the remainder of the input. If
@@ -89,8 +90,8 @@ func Decode(data []byte) (p *Block, rest []byte) {
        rest = data
        if bytes.HasPrefix(data, pemStart[1:]) {
                rest = rest[len(pemStart)-1 : len(data)]
-       } else if i := bytes.Index(data, pemStart); i >= 0 {
-               rest = rest[i+len(pemStart) : len(data)]
+       } else if _, after, ok := bytes.Cut(data, pemStart); ok {
+               rest = after
        } else {
                return nil, data
        }
@@ -114,13 +115,12 @@ func Decode(data []byte) (p *Block, rest []byte) {
                }
                line, next := getLine(rest)
 
-               i := bytes.IndexByte(line, ':')
-               if i == -1 {
+               key, val, ok := bytes.Cut(line, colon)
+               if !ok {
                        break
                }
 
                // TODO(agl): need to cope with values that spread across lines.
-               key, val := line[:i], line[i+1:]
                key = bytes.TrimSpace(key)
                val = bytes.TrimSpace(val)
                p.Headers[string(key)] = string(val)
index 162724ef1a58b02d452a7783a11f523c65c3d6bf..51e976cf01900168c2add439479ce7fd18a6640b 100644 (file)
@@ -115,8 +115,8 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
 
        // Split the tag from the xml namespace if necessary.
        tag := f.Tag.Get("xml")
-       if i := strings.Index(tag, " "); i >= 0 {
-               finfo.xmlns, tag = tag[:i], tag[i+1:]
+       if ns, t, ok := strings.Cut(tag, " "); ok {
+               finfo.xmlns, tag = ns, t
        }
 
        // Parse flags.
index c14954df155a64a0ff3ef1126f22376538f4f78a..33d0b417b91e11f619bdedc9de2a15bd64b9e71f 100644 (file)
@@ -1164,11 +1164,11 @@ func (d *Decoder) nsname() (name Name, ok bool) {
        }
        if strings.Count(s, ":") > 1 {
                name.Local = s
-       } else if i := strings.Index(s, ":"); i < 1 || i > len(s)-2 {
+       } else if space, local, ok := strings.Cut(s, ":"); !ok || space == "" || local == "" {
                name.Local = s
        } else {
-               name.Space = s[0:i]
-               name.Local = s[i+1:]
+               name.Space = space
+               name.Local = local
        }
        return name, true
 }
@@ -2012,25 +2012,26 @@ func emitCDATA(w io.Writer, s []byte) error {
        if _, err := w.Write(cdataStart); err != nil {
                return err
        }
+
        for {
-               i := bytes.Index(s, cdataEnd)
-               if i >= 0 && i+len(cdataEnd) <= len(s) {
-                       // Found a nested CDATA directive end.
-                       if _, err := w.Write(s[:i]); err != nil {
-                               return err
-                       }
-                       if _, err := w.Write(cdataEscape); err != nil {
-                               return err
-                       }
-                       i += len(cdataEnd)
-               } else {
-                       if _, err := w.Write(s); err != nil {
-                               return err
-                       }
+               before, after, ok := bytes.Cut(s, cdataEnd)
+               if !ok {
                        break
                }
-               s = s[i:]
+               // Found a nested CDATA directive end.
+               if _, err := w.Write(before); err != nil {
+                       return err
+               }
+               if _, err := w.Write(cdataEscape); err != nil {
+                       return err
+               }
+               s = after
+       }
+
+       if _, err := w.Write(s); err != nil {
+               return err
        }
+
        _, err := w.Write(cdataEnd)
        return err
 }
@@ -2041,20 +2042,16 @@ func procInst(param, s string) string {
        // TODO: this parsing is somewhat lame and not exact.
        // It works for all actual cases, though.
        param = param + "="
-       idx := strings.Index(s, param)
-       if idx == -1 {
-               return ""
-       }
-       v := s[idx+len(param):]
+       _, v, _ := strings.Cut(s, param)
        if v == "" {
                return ""
        }
        if v[0] != '\'' && v[0] != '"' {
                return ""
        }
-       idx = strings.IndexRune(v[1:], rune(v[0]))
-       if idx == -1 {
+       unquote, _, ok := strings.Cut(v[1:], v[:1])
+       if !ok {
                return ""
        }
-       return v[1 : idx+1]
+       return unquote
 }
index 8afa9d5240408a6d36df874ca9d5a8fe43bb708f..eb47ffe2859c4fa84a905cdfe6afb70c93e473fc 100644 (file)
@@ -1258,19 +1258,14 @@ func findImportComment(data []byte) (s string, line int) {
        var comment []byte
        switch {
        case bytes.HasPrefix(data, slashSlash):
-               i := bytes.Index(data, newline)
-               if i < 0 {
-                       i = len(data)
-               }
-               comment = data[2:i]
+               comment, _, _ = bytes.Cut(data[2:], newline)
        case bytes.HasPrefix(data, slashStar):
-               data = data[2:]
-               i := bytes.Index(data, starSlash)
-               if i < 0 {
+               var ok bool
+               comment, _, ok = bytes.Cut(data[2:], starSlash)
+               if !ok {
                        // malformed comment
                        return "", 0
                }
-               comment = data[:i]
                if bytes.Contains(comment, newline) {
                        return "", 0
                }
@@ -1654,12 +1649,10 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                }
 
                // Split at colon.
-               line = strings.TrimSpace(line[4:])
-               i := strings.Index(line, ":")
-               if i < 0 {
+               line, argstr, ok := strings.Cut(strings.TrimSpace(line[4:]), ":")
+               if !ok {
                        return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
                }
-               line, argstr := line[:i], line[i+1:]
 
                // Parse GOOS/GOARCH stuff.
                f := strings.Fields(line)
@@ -1685,7 +1678,6 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                if err != nil {
                        return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
                }
-               var ok bool
                for i, arg := range args {
                        if arg, ok = expandSrcDir(arg, di.Dir); !ok {
                                return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
@@ -1944,9 +1936,7 @@ func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
 // if GOOS=illumos, then files with GOOS=solaris are also matched.
 // if GOOS=ios, then files with GOOS=darwin are also matched.
 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
-       if dot := strings.Index(name, "."); dot != -1 {
-               name = name[:dot]
-       }
+       name, _, _ = strings.Cut(name, ".")
 
        // Before Go 1.4, a file called "linux.go" would be equivalent to having a
        // build tag "linux" in that file. For Go 1.4 and beyond, we require this
index 80f930f3c23bef47516580717c8cb729273d93d1..cfe9c5e4bb286b82a944e41929adb72c080bfd2a 100644 (file)
@@ -712,7 +712,7 @@ func TestMissingImportErrorRepetition(t *testing.T) {
        // Also don't count instances in suggested "go get" or similar commands
        // (see https://golang.org/issue/41576). The suggested command typically
        // follows a semicolon.
-       errStr = strings.SplitN(errStr, ";", 2)[0]
+       errStr, _, _ = strings.Cut(errStr, ";")
 
        if n := strings.Count(errStr, pkgPath); n != 1 {
                t.Fatalf("package path %q appears in error %d times; should appear once\nerror: %v", pkgPath, n, err)
index b98c7938a855993454b5e374ff99d9b9ebd04b95..6115ef810c786713bdc8c6696eaeccf9448c1436 100644 (file)
@@ -516,12 +516,12 @@ func parseGoEmbed(args string, pos token.Position) ([]fileEmbed, error) {
                        trimBytes(i)
 
                case '`':
-                       i := strings.Index(args[1:], "`")
-                       if i < 0 {
+                       var ok bool
+                       path, _, ok = strings.Cut(args[1:], "`")
+                       if !ok {
                                return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
                        }
-                       path = args[1 : 1+i]
-                       trimBytes(1 + i + 1)
+                       trimBytes(1 + len(path) + 1)
 
                case '"':
                        i := 1
index 1e5e1c2de2e6d110b539058fe64711c97547ee89..6851e6b6d6003eec431616fdf20ddf2968d6bf18 100644 (file)
@@ -119,20 +119,15 @@ var readCommentsTests = []readTest{
 
 func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
        for i, tt := range tests {
-               var in, testOut string
-               j := strings.Index(tt.in, "ℙ")
-               if j < 0 {
-                       in = tt.in
-                       testOut = tt.in
-               } else {
-                       in = tt.in[:j] + tt.in[j+len("ℙ"):]
-                       testOut = tt.in[:j]
-               }
-               d := strings.Index(tt.in, "𝔻")
-               if d >= 0 {
-                       in = in[:d] + in[d+len("𝔻"):]
-                       testOut = testOut[d+len("𝔻"):]
+               beforeP, afterP, _ := strings.Cut(tt.in, "ℙ")
+               in := beforeP + afterP
+               testOut := beforeP
+
+               if beforeD, afterD, ok := strings.Cut(beforeP, "𝔻"); ok {
+                       in = beforeD + afterD + afterP
+                       testOut = afterD
                }
+
                r := strings.NewReader(in)
                buf, err := read(r)
                if err != nil {
index 91ad0b0c2b9d998a2a28feb2827d8b118cb56124..ac179b3d8c21028bb726bac4ba8cc8c4b53bafc5 100644 (file)
@@ -143,9 +143,9 @@ func testNumbers(t *testing.T, kind token.Token, tests []string) {
                if a[1] == "?" {
                        y = MakeUnknown()
                } else {
-                       if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
-                               n := MakeFromLiteral(a[1][:i], token.INT, 0)
-                               d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
+                       if ns, ds, ok := strings.Cut(a[1], "/"); ok && kind == token.FLOAT {
+                               n := MakeFromLiteral(ns, token.INT, 0)
+                               d := MakeFromLiteral(ds, token.INT, 0)
                                y = BinaryOp(n, token.QUO, d)
                        } else {
                                y = MakeFromLiteral(a[1], kind, 0)
@@ -454,10 +454,10 @@ func val(lit string) Value {
                return MakeBool(false)
        }
 
-       if i := strings.IndexByte(lit, '/'); i >= 0 {
+       if as, bs, ok := strings.Cut(lit, "/"); ok {
                // assume fraction
-               a := MakeFromLiteral(lit[:i], token.INT, 0)
-               b := MakeFromLiteral(lit[i+1:], token.INT, 0)
+               a := MakeFromLiteral(as, token.INT, 0)
+               b := MakeFromLiteral(bs, token.INT, 0)
                return BinaryOp(a, token.QUO, b)
        }
 
index 92131a3b83f02700cb4b48d21d2ed3947056c082..a93c05fbb7e315494f229b7014bd270fd9e1b4b2 100644 (file)
@@ -236,26 +236,24 @@ func heading(line string) string {
 
        // allow "'" for possessive "'s" only
        for b := line; ; {
-               i := strings.IndexRune(b, '\'')
-               if i < 0 {
+               var ok bool
+               if _, b, ok = strings.Cut(b, "'"); !ok {
                        break
                }
-               if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') {
-                       return "" // not followed by "s "
+               if b != "s" && !strings.HasPrefix(b, "s ") {
+                       return "" // ' not followed by s and then end-of-word
                }
-               b = b[i+2:]
        }
 
        // allow "." when followed by non-space
        for b := line; ; {
-               i := strings.IndexRune(b, '.')
-               if i < 0 {
+               var ok bool
+               if _, b, ok = strings.Cut(b, "."); !ok {
                        break
                }
-               if i+1 >= len(b) || b[i+1] == ' ' {
+               if b == "" || strings.HasPrefix(b, " ") {
                        return "" // not followed by non-space
                }
-               b = b[i+1:]
        }
 
        return line
index 28cb84f91da8f0436684072703ad84c5ce231210..df54b4bd61fb469ba83d9cc42328cdd8e1110667 100644 (file)
@@ -23,10 +23,10 @@ import (
        "go/doc"
        "go/parser"
        "go/token"
-       "internal/lazyregexp"
        "io/fs"
        "os"
        "path/filepath"
+       "regexp"
        "runtime"
        "strings"
 )
@@ -37,7 +37,7 @@ var (
 )
 
 // ToHTML in comment.go assigns a (possibly blank) ID to each heading
-var html_h = lazyregexp.New(`<h3 id="[^"]*">`)
+var html_h = regexp.MustCompile(`<h3 id="[^"]*">`)
 
 const html_endh = "</h3>\n"
 
@@ -49,19 +49,14 @@ func isGoFile(fi fs.FileInfo) bool {
 func appendHeadings(list []string, comment string) []string {
        var buf bytes.Buffer
        doc.ToHTML(&buf, comment, nil)
-       for s := buf.String(); ; {
+       for s := buf.String(); s != ""; {
                loc := html_h.FindStringIndex(s)
                if len(loc) == 0 {
                        break
                }
-               i := loc[1]
-               j := strings.Index(s, html_endh)
-               if j < 0 {
-                       list = append(list, s[i:]) // incorrect HTML
-                       break
-               }
-               list = append(list, s[i:j])
-               s = s[j+len(html_endh):]
+               var inner string
+               inner, s, _ = strings.Cut(s[loc[1]:], html_endh)
+               list = append(list, inner)
        }
        return list
 }
index 0f5121d80212bd57e9f18ad94f995a69a1cf733d..27c4aa787173d82e2027a812493a70a06d02e32c 100644 (file)
@@ -24,8 +24,7 @@ func TestForCompiler(t *testing.T) {
                t.Fatalf("go list %s: %v\n%s", thePackage, err, out)
        }
        target := strings.TrimSpace(string(out))
-       i := strings.Index(target, ":")
-       compiler, target := target[:i], target[i+1:]
+       compiler, target, _ := strings.Cut(target, ":")
        if !strings.HasSuffix(target, ".a") {
                t.Fatalf("unexpected package %s target %q (not *.a)", thePackage, target)
        }
index 053a8ef174a9c8e2f99724f19f98fd131733d005..567b2339b435a0ad3037c2242c833b25bf75fdbd 100644 (file)
@@ -1049,7 +1049,7 @@ func normalizedNumber(lit *ast.BasicLit) *ast.BasicLit {
                        break
                }
                // remove leading 0's from integer (but not floating-point) imaginary literals
-               if x[len(x)-1] == 'i' && strings.IndexByte(x, '.') < 0 && strings.IndexByte(x, 'e') < 0 {
+               if x[len(x)-1] == 'i' && !strings.ContainsAny(x, ".e") {
                        x = strings.TrimLeft(x, "0_")
                        if x == "i" {
                                x = "0i"
index ba61f782267ad8ed27ab5b2252f06bdf70cc5252..2f41e7bf72f6b97b8f53eac68b9a304e490f25e6 100644 (file)
@@ -559,12 +559,9 @@ func stripCommonPrefix(lines []string) {
         * Check for vertical "line of stars" and correct prefix accordingly.
         */
        lineOfStars := false
-       if i := strings.Index(prefix, "*"); i >= 0 {
-               // Line of stars present.
-               if i > 0 && prefix[i-1] == ' ' {
-                       i-- // remove trailing blank from prefix so stars remain aligned
-               }
-               prefix = prefix[0:i]
+       if p, _, ok := strings.Cut(prefix, "*"); ok {
+               // remove trailing blank from prefix so stars remain aligned
+               prefix = strings.TrimSuffix(p, " ")
                lineOfStars = true
        } else {
                // No line of stars present.
@@ -616,8 +613,8 @@ func stripCommonPrefix(lines []string) {
        // lines.
        last := lines[len(lines)-1]
        closing := "*/"
-       i := strings.Index(last, closing) // i >= 0 (closing is always present)
-       if isBlank(last[0:i]) {
+       before, _, _ := strings.Cut(last, closing) // closing always present
+       if isBlank(before) {
                // last line only contains closing */
                if lineOfStars {
                        closing = " */" // add blank to align final star
index 41d3a61b89528ed7e8c4445585982f8efc593bd0..345bd143059350e16ddf8ab3da995500acdddf12 100644 (file)
@@ -195,10 +195,10 @@ func TestEvalPos(t *testing.T) {
        }
 }
 
-// split splits string s at the first occurrence of s.
+// split splits string s at the first occurrence of s, trimming spaces.
 func split(s, sep string) (string, string) {
-       i := strings.Index(s, sep)
-       return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+       before, after, _ := strings.Cut(s, sep)
+       return strings.TrimSpace(before), strings.TrimSpace(after)
 }
 
 func TestCheckExpr(t *testing.T) {
index 22922e6038b651196896976cfaccd56fe33fe34f..6c52211fede1d096f955a6bae656297bd5db8694 100644 (file)
@@ -143,12 +143,12 @@ func attrType(name string) contentType {
                // widely applied.
                // Treat data-action as URL below.
                name = name[5:]
-       } else if colon := strings.IndexRune(name, ':'); colon != -1 {
-               if name[:colon] == "xmlns" {
+       } else if prefix, short, ok := strings.Cut(name, ":"); ok {
+               if prefix == "xmlns" {
                        return contentTypeURL
                }
                // Treat svg:href and xlink:href as href below.
-               name = name[colon+1:]
+               name = short
        }
        if t, ok := attrTypeMap[name]; ok {
                return t
index ea9c18346ba2632b6e04db61e565492b96975156..32a4fbd30acc23b451876151d387e2126bf51f8b 100644 (file)
@@ -398,9 +398,7 @@ func isJSType(mimeType string) bool {
        //   https://tools.ietf.org/html/rfc4329#section-3
        //   https://www.ietf.org/rfc/rfc4627.txt
        // discard parameters
-       if i := strings.Index(mimeType, ";"); i >= 0 {
-               mimeType = mimeType[:i]
-       }
+       mimeType, _, _ = strings.Cut(mimeType, ";")
        mimeType = strings.ToLower(mimeType)
        mimeType = strings.TrimSpace(mimeType)
        switch mimeType {
index 6f8185a4e90e69a0833c31b8aa4bffdc6ef5bc30..4b39fddf07df41e805ca0059c71c575d6a48a6bb 100644 (file)
@@ -46,9 +46,7 @@ func urlFilter(args ...interface{}) string {
 // isSafeURL is true if s is a relative URL or if URL has a protocol in
 // (http, https, mailto).
 func isSafeURL(s string) bool {
-       if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
-
-               protocol := s[:i]
+       if protocol, _, ok := strings.Cut(s, ":"); ok && !strings.Contains(protocol, "/") {
                if !strings.EqualFold(protocol, "http") && !strings.EqualFold(protocol, "https") && !strings.EqualFold(protocol, "mailto") {
                        return false
                }
index d69f8deee7cb6aa677fdd36cdd8d0412419ca400..377a43d5858f08e066e59947d979a4994bc4e2d0 100644 (file)
@@ -750,11 +750,11 @@ func parseCppContention(r *bytes.Buffer) (*Profile, error) {
                        break
                }
 
-               attr := strings.SplitN(l, delimiter, 2)
-               if len(attr) != 2 {
+               key, val, ok := strings.Cut(l, delimiter)
+               if !ok {
                        break
                }
-               key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
+               key, val = strings.TrimSpace(key), strings.TrimSpace(val)
                var err error
                switch key {
                case "cycles/second":
@@ -1050,8 +1050,8 @@ func (p *Profile) ParseMemoryMap(rd io.Reader) error {
                        if err == errUnrecognized {
                                // Recognize assignments of the form: attr=value, and replace
                                // $attr with value on subsequent mappings.
-                               if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
-                                       attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
+                               if attr, value, ok := strings.Cut(l, delimiter); ok {
+                                       attrs = append(attrs, "$"+strings.TrimSpace(attr), strings.TrimSpace(value))
                                        r = strings.NewReplacer(attrs...)
                                }
                                // Ignore any unrecognized entries
index 58f60daec4312c673bf4b627a869273caf1033df..e6b470b1fb0ef83548656fc06f13d8e14cc6be02 100644 (file)
@@ -203,35 +203,25 @@ func (d *WordDecoder) Decode(word string) (string, error) {
        }
        word = word[2 : len(word)-2]
 
-       // split delimits the first 2 fields
-       split := strings.IndexByte(word, '?')
-
-       // split word "UTF-8?q?ascii" into "UTF-8", 'q', and "ascii"
-       charset := word[:split]
-       if len(charset) == 0 {
-               return "", errInvalidWord
-       }
-       if len(word) < split+3 {
+       // split word "UTF-8?q?text" into "UTF-8", 'q', and "text"
+       charset, text, _ := strings.Cut(word, "?")
+       if charset == "" {
                return "", errInvalidWord
        }
-       encoding := word[split+1]
-       // the field after split must only be one byte
-       if word[split+2] != '?' {
+       encoding, text, _ := strings.Cut(text, "?")
+       if len(encoding) != 1 {
                return "", errInvalidWord
        }
-       text := word[split+3:]
 
-       content, err := decode(encoding, text)
+       content, err := decode(encoding[0], text)
        if err != nil {
                return "", err
        }
 
        var buf strings.Builder
-
        if err := d.convert(&buf, charset, content); err != nil {
                return "", err
        }
-
        return buf.String(), nil
 }
 
index 56ceb488533fc9b94063b68c6250c2e4e0f4fea6..9456570cf1f35b4807cc1aafe68187ee1a8db1a5 100644 (file)
@@ -19,13 +19,12 @@ import (
 // FormatMediaType returns the empty string.
 func FormatMediaType(t string, param map[string]string) string {
        var b strings.Builder
-       if slash := strings.IndexByte(t, '/'); slash == -1 {
+       if major, sub, ok := strings.Cut(t, "/"); !ok {
                if !isToken(t) {
                        return ""
                }
                b.WriteString(strings.ToLower(t))
        } else {
-               major, sub := t[:slash], t[slash+1:]
                if !isToken(major) || !isToken(sub) {
                        return ""
                }
@@ -138,11 +137,8 @@ var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter")
 // The returned map, params, maps from the lowercase
 // attribute to the attribute value with its case preserved.
 func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
-       i := strings.Index(v, ";")
-       if i == -1 {
-               i = len(v)
-       }
-       mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+       base, _, _ := strings.Cut(v, ";")
+       mediatype = strings.TrimSpace(strings.ToLower(base))
 
        err = checkMediaTypeDisposition(mediatype)
        if err != nil {
@@ -156,7 +152,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
        // Lazily initialized.
        var continuation map[string]map[string]string
 
-       v = v[i:]
+       v = v[len(base):]
        for len(v) > 0 {
                v = strings.TrimLeftFunc(v, unicode.IsSpace)
                if len(v) == 0 {
@@ -174,8 +170,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
                }
 
                pmap := params
-               if idx := strings.Index(key, "*"); idx != -1 {
-                       baseName := key[:idx]
+               if baseName, _, ok := strings.Cut(key, "*"); ok {
                        if continuation == nil {
                                continuation = make(map[string]map[string]string)
                        }
index 0114da377b564725f7d33d804625cb4aacc2994c..bdb35a64e50b97ec0e542458621141cc6f85cb2a 100644 (file)
@@ -39,8 +39,8 @@ func Request() (*http.Request, error) {
 func envMap(env []string) map[string]string {
        m := make(map[string]string)
        for _, kv := range env {
-               if idx := strings.Index(kv, "="); idx != -1 {
-                       m[kv[:idx]] = kv[idx+1:]
+               if k, v, ok := strings.Cut(kv, "="); ok {
+                       m[k] = v
                }
        }
        return m
index eff67caf4e6efbe242129f768898acbd1f95741b..e7124a2ab058a4386b5fc86d3a289e517b512588 100644 (file)
@@ -273,12 +273,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
                        break
                }
                headerLines++
-               parts := strings.SplitN(string(line), ":", 2)
-               if len(parts) < 2 {
+               header, val, ok := strings.Cut(string(line), ":")
+               if !ok {
                        h.printf("cgi: bogus header line: %s", string(line))
                        continue
                }
-               header, val := parts[0], parts[1]
                if !httpguts.ValidHeaderFieldName(header) {
                        h.printf("cgi: invalid header name: %q", header)
                        continue
index fb869a67282d60df9abd4626accfe737a9f995a3..f8abc88c8973775397063bb28468b9c1c57763c8 100644 (file)
@@ -62,12 +62,12 @@ readlines:
                }
                linesRead++
                trimmedLine := strings.TrimRight(line, "\r\n")
-               split := strings.SplitN(trimmedLine, "=", 2)
-               if len(split) != 2 {
-                       t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v",
-                               len(split), linesRead, line, m)
+               k, v, ok := strings.Cut(trimmedLine, "=")
+               if !ok {
+                       t.Fatalf("Unexpected response from invalid line number %v: %q; existing map=%v",
+                               linesRead, line, m)
                }
-               m[split[0]] = split[1]
+               m[k] = v
        }
 
        for key, expected := range expectedMap {
index 05ed2268b59ff24fe95b5c40c23724628c794ddd..e741c3746f36f8a08d85c9e9cda13d8b213ff786 100644 (file)
@@ -431,11 +431,10 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
                if v := urlQuery.Get("code"); v != "" {
                        location := ts.URL
                        if final := urlQuery.Get("next"); final != "" {
-                               splits := strings.Split(final, ",")
-                               first, rest := splits[0], splits[1:]
+                               first, rest, _ := strings.Cut(final, ",")
                                location = fmt.Sprintf("%s?code=%s", location, first)
-                               if len(rest) > 0 {
-                                       location = fmt.Sprintf("%s&next=%s", location, strings.Join(rest, ","))
+                               if rest != "" {
+                                       location = fmt.Sprintf("%s&next=%s", location, rest)
                                }
                        }
                        code, _ := strconv.Atoi(v)
index ca2c1c2506694cc7c636c09af3b7cf9921352287..02b40315deb9fac197bdafd2144f5a4247a74bdb 100644 (file)
@@ -67,15 +67,14 @@ func readSetCookies(h Header) []*Cookie {
                        continue
                }
                parts[0] = textproto.TrimString(parts[0])
-               j := strings.Index(parts[0], "=")
-               if j < 0 {
+               name, value, ok := strings.Cut(parts[0], "=")
+               if !ok {
                        continue
                }
-               name, value := parts[0][:j], parts[0][j+1:]
                if !isCookieNameValid(name) {
                        continue
                }
-               value, ok := parseCookieValue(value, true)
+               value, ok = parseCookieValue(value, true)
                if !ok {
                        continue
                }
@@ -90,10 +89,7 @@ func readSetCookies(h Header) []*Cookie {
                                continue
                        }
 
-                       attr, val := parts[i], ""
-                       if j := strings.Index(attr, "="); j >= 0 {
-                               attr, val = attr[:j], attr[j+1:]
-                       }
+                       attr, val, _ := strings.Cut(parts[i], "=")
                        lowerAttr, isASCII := ascii.ToLower(attr)
                        if !isASCII {
                                continue
@@ -256,19 +252,12 @@ func readCookies(h Header, filter string) []*Cookie {
 
                var part string
                for len(line) > 0 { // continue since we have rest
-                       if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
-                               part, line = line[:splitIndex], line[splitIndex+1:]
-                       } else {
-                               part, line = line, ""
-                       }
+                       part, line, _ = strings.Cut(line, ";")
                        part = textproto.TrimString(part)
-                       if len(part) == 0 {
+                       if part == "" {
                                continue
                        }
-                       name, val := part, ""
-                       if j := strings.Index(part, "="); j >= 0 {
-                               name, val = name[:j], name[j+1:]
-                       }
+                       name, val, _ := strings.Cut(part, "=")
                        if !isCookieNameValid(name) {
                                continue
                        }
@@ -379,7 +368,7 @@ func sanitizeCookieValue(v string) string {
        if len(v) == 0 {
                return v
        }
-       if strings.IndexByte(v, ' ') >= 0 || strings.IndexByte(v, ',') >= 0 {
+       if strings.ContainsAny(v, " ,") {
                return `"` + v + `"`
        }
        return v
index 57e731e481ad49830b67a907dee59f554130579b..19b2894bf2ff388cbc0de14c38e26c4b342d2b4c 100644 (file)
@@ -881,11 +881,11 @@ func parseRange(s string, size int64) ([]httpRange, error) {
                if ra == "" {
                        continue
                }
-               i := strings.Index(ra, "-")
-               if i < 0 {
+               start, end, ok := strings.Cut(ra, "-")
+               if !ok {
                        return nil, errors.New("invalid range")
                }
-               start, end := textproto.TrimString(ra[:i]), textproto.TrimString(ra[i+1:])
+               start, end = textproto.TrimString(start), textproto.TrimString(end)
                var r httpRange
                if start == "" {
                        // If no start is specified, end specifies the
index f06e5725f3477988281ef10ae078cd945083a428..923e6a6d2cb0c621d87e4674a19bda642756ffde 100644 (file)
@@ -152,6 +152,8 @@ func isASCIISpace(b byte) bool {
        return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 }
 
+var semi = []byte(";")
+
 // removeChunkExtension removes any chunk-extension from p.
 // For example,
 //     "0" => "0"
@@ -159,14 +161,11 @@ func isASCIISpace(b byte) bool {
 //     "0;token=val" => "0"
 //     `0;token="quoted string"` => "0"
 func removeChunkExtension(p []byte) ([]byte, error) {
-       semi := bytes.IndexByte(p, ';')
-       if semi == -1 {
-               return p, nil
-       }
+       p, _, _ = bytes.Cut(p, semi)
        // TODO: care about exact syntax of chunk extensions? We're
        // ignoring and stripping them anyway. For now just never
        // return an error.
-       return p[:semi], nil
+       return p, nil
 }
 
 // NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
index 6564627998f53eb988cead8f72cbfbfc4202e54f..632a308a5ce2eb0da306356e80d026e77689d054 100644 (file)
@@ -31,11 +31,8 @@ func interestingGoroutines() (gs []string) {
        buf := make([]byte, 2<<20)
        buf = buf[:runtime.Stack(buf, true)]
        for _, g := range strings.Split(string(buf), "\n\n") {
-               sl := strings.SplitN(g, "\n", 2)
-               if len(sl) != 2 {
-                       continue
-               }
-               stack := strings.TrimSpace(sl[1])
+               _, stack, _ := strings.Cut(g, "\n")
+               stack = strings.TrimSpace(stack)
                if stack == "" ||
                        strings.Contains(stack, "testing.(*M).before.func1") ||
                        strings.Contains(stack, "os/signal.signal_recv") ||
index 0eb7042d7b6b510f6fc092d2a88ebb3da17bad46..76c2317d28256dfbbce67752b0951290bbea5656 100644 (file)
@@ -940,7 +940,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, body io.Read
 func (r *Request) BasicAuth() (username, password string, ok bool) {
        auth := r.Header.Get("Authorization")
        if auth == "" {
-               return
+               return "", "", false
        }
        return parseBasicAuth(auth)
 }
@@ -951,18 +951,18 @@ func parseBasicAuth(auth string) (username, password string, ok bool) {
        const prefix = "Basic "
        // Case insensitive prefix match. See Issue 22736.
        if len(auth) < len(prefix) || !ascii.EqualFold(auth[:len(prefix)], prefix) {
-               return
+               return "", "", false
        }
        c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
        if err != nil {
-               return
+               return "", "", false
        }
        cs := string(c)
-       s := strings.IndexByte(cs, ':')
-       if s < 0 {
-               return
+       username, password, ok = strings.Cut(cs, ":")
+       if !ok {
+               return "", "", false
        }
-       return cs[:s], cs[s+1:], true
+       return username, password, true
 }
 
 // SetBasicAuth sets the request's Authorization header to use HTTP
@@ -980,13 +980,12 @@ func (r *Request) SetBasicAuth(username, password string) {
 
 // parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
 func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
-       s1 := strings.Index(line, " ")
-       s2 := strings.Index(line[s1+1:], " ")
-       if s1 < 0 || s2 < 0 {
-               return
+       method, rest, ok1 := strings.Cut(line, " ")
+       requestURI, proto, ok2 := strings.Cut(rest, " ")
+       if !ok1 || !ok2 {
+               return "", "", "", false
        }
-       s2 += s1 + 1
-       return line[:s1], line[s1+1 : s2], line[s2+1:], true
+       return method, requestURI, proto, true
 }
 
 var textprotoReaderPool sync.Pool
index b8985da3c80fc413ef30f640bbd8fd282e65465e..297394eabebed53dc1853d4547c5e19e73256e4b 100644 (file)
@@ -165,16 +165,14 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
                }
                return nil, err
        }
-       if i := strings.IndexByte(line, ' '); i == -1 {
+       proto, status, ok := strings.Cut(line, " ")
+       if !ok {
                return nil, badStringError("malformed HTTP response", line)
-       } else {
-               resp.Proto = line[:i]
-               resp.Status = strings.TrimLeft(line[i+1:], " ")
-       }
-       statusCode := resp.Status
-       if i := strings.IndexByte(resp.Status, ' '); i != -1 {
-               statusCode = resp.Status[:i]
        }
+       resp.Proto = proto
+       resp.Status = strings.TrimLeft(status, " ")
+
+       statusCode, _, _ := strings.Cut(resp.Status, " ")
        if len(statusCode) != 3 {
                return nil, badStringError("malformed HTTP status code", statusCode)
        }
@@ -182,7 +180,6 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
        if err != nil || resp.StatusCode < 0 {
                return nil, badStringError("malformed HTTP status code", statusCode)
        }
-       var ok bool
        if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
                return nil, badStringError("malformed HTTP version", resp.Proto)
        }
index 4d0ce5619fe1d6b8e5dc0632de2146a4656ffbf6..55fd4ae22f90013e593206791a7a80ba1da36327 100644 (file)
@@ -2282,7 +2282,7 @@ func cleanPath(p string) string {
 // stripHostPort returns h without any trailing ":<port>".
 func stripHostPort(h string) string {
        // If no port on host, return unchanged
-       if strings.IndexByte(h, ':') == -1 {
+       if !strings.Contains(h, ":") {
                return h
        }
        host, _, err := net.SplitHostPort(h)
index 309194e8e52c86f8ef17109464f8b28a1f244bfa..17f0047b59982b48f910edcd2fe38111862d8e4f 100644 (file)
@@ -1715,12 +1715,12 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
                        return nil, err
                }
                if resp.StatusCode != 200 {
-                       f := strings.SplitN(resp.Status, " ", 2)
+                       _, text, ok := strings.Cut(resp.Status, " ")
                        conn.Close()
-                       if len(f) < 2 {
+                       if !ok {
                                return nil, errors.New("unknown status code")
                        }
-                       return nil, errors.New(f[1])
+                       return nil, errors.New(text)
                }
        }
 
index 47bbf6ca9771bdcf23f3cd37357d21f721816ef3..c120316730c55a4ab127fa2017267fea041be126 100644 (file)
@@ -100,7 +100,7 @@ func ParseDate(date string) (time.Time, error) {
        dateLayoutsBuildOnce.Do(buildDateLayouts)
        // CR and LF must match and are tolerated anywhere in the date field.
        date = strings.ReplaceAll(date, "\r\n", "")
-       if strings.Index(date, "\r") != -1 {
+       if strings.Contains(date, "\r") {
                return time.Time{}, errors.New("mail: header has a CR without LF")
        }
        // Re-using some addrParser methods which support obsolete text, i.e. non-printable ASCII
index c9ab25a4ad572ebb8e663fbf6bfe1d2c18999802..c804c4e7556a4d54d33afe9a988116f4f7395ce5 100644 (file)
@@ -18,9 +18,9 @@ func enableSocketConnect() {
 }
 
 func disableSocketConnect(network string) {
-       ss := strings.Split(network, ":")
+       net, _, _ := strings.Cut(network, ":")
        sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
-               switch ss[0] {
+               switch net {
                case "tcp4":
                        if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_STREAM {
                                return nil, syscall.EHOSTUNREACH
index dc17d3fbb84d1547879afa575352561299aa510e..4f004071f09decf1168c64faf3e76dd68693d7f0 100644 (file)
@@ -174,11 +174,8 @@ func runningGoroutines() []string {
        b := make([]byte, 2<<20)
        b = b[:runtime.Stack(b, true)]
        for _, s := range strings.Split(string(b), "\n\n") {
-               ss := strings.SplitN(s, "\n", 2)
-               if len(ss) != 2 {
-                       continue
-               }
-               stack := strings.TrimSpace(ss[1])
+               _, stack, _ := strings.Cut(s, "\n")
+               stack = strings.TrimSpace(stack)
                if !strings.Contains(stack, "created by net") {
                        continue
                }
index 2da23dedcea6749a74997c3804e376dc7b9b3801..7d92a0de5de7f675eb335b0b87dbed2d3ab3935e 100644 (file)
@@ -34,8 +34,8 @@ func init() {
 // testableNetwork reports whether network is testable on the current
 // platform configuration.
 func testableNetwork(network string) bool {
-       ss := strings.Split(network, ":")
-       switch ss[0] {
+       net, _, _ := strings.Cut(network, ":")
+       switch net {
        case "ip+nopriv":
        case "ip", "ip4", "ip6":
                switch runtime.GOOS {
@@ -68,7 +68,7 @@ func testableNetwork(network string) bool {
                        }
                }
        }
-       switch ss[0] {
+       switch net {
        case "tcp4", "udp4", "ip4":
                if !supportsIPv4() {
                        return false
@@ -88,7 +88,7 @@ func iOS() bool {
 // testableAddress reports whether address of network is testable on
 // the current platform configuration.
 func testableAddress(network, address string) bool {
-       switch ss := strings.Split(network, ":"); ss[0] {
+       switch net, _, _ := strings.Cut(network, ":"); net {
        case "unix", "unixgram", "unixpacket":
                // Abstract unix domain sockets, a Linux-ism.
                if address[0] == '@' && runtime.GOOS != "linux" {
@@ -107,7 +107,7 @@ func testableListenArgs(network, address, client string) bool {
 
        var err error
        var addr Addr
-       switch ss := strings.Split(network, ":"); ss[0] {
+       switch net, _, _ := strings.Cut(network, ":"); net {
        case "tcp", "tcp4", "tcp6":
                addr, err = ResolveTCPAddr("tcp", address)
        case "udp", "udp4", "udp6":
index 1a6864a0f2436caf5ad74a5aa05350d1f99c2f48..bcccaa25979599fb18b714bd0115e86f70669d29 100644 (file)
@@ -136,12 +136,8 @@ func (c *Client) ehlo() error {
        if len(extList) > 1 {
                extList = extList[1:]
                for _, line := range extList {
-                       args := strings.SplitN(line, " ", 2)
-                       if len(args) > 1 {
-                               ext[args[0]] = args[1]
-                       } else {
-                               ext[args[0]] = ""
-                       }
+                       k, v, _ := strings.Cut(line, " ")
+                       ext[k] = v
                }
        }
        if mechs, ok := ext["AUTH"]; ok {
index 5c3084f8a7c9fd8be8eb93af87cb9e758bca1fa2..157c59b17accfb2a48ca5ace16bf1d214ebe388c 100644 (file)
@@ -460,6 +460,8 @@ func (r *Reader) ReadDotLines() ([]string, error) {
        return v, err
 }
 
+var colon = []byte(":")
+
 // ReadMIMEHeader reads a MIME-style header from r.
 // The header is a sequence of possibly continued Key: Value lines
 // ending in a blank line.
@@ -508,11 +510,11 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
                }
 
                // Key ends at first colon.
-               i := bytes.IndexByte(kv, ':')
-               if i < 0 {
+               k, v, ok := bytes.Cut(kv, colon)
+               if !ok {
                        return m, ProtocolError("malformed MIME header line: " + string(kv))
                }
-               key := canonicalMIMEHeaderKey(kv[:i])
+               key := canonicalMIMEHeaderKey(k)
 
                // As per RFC 7230 field-name is a token, tokens consist of one or more chars.
                // We could return a ProtocolError here, but better to be liberal in what we
@@ -522,11 +524,7 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
                }
 
                // Skip initial spaces in value.
-               i++ // skip colon
-               for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
-                       i++
-               }
-               value := string(kv[i:])
+               value := strings.TrimLeft(string(v), " \t")
 
                vv := m[key]
                if vv == nil && len(strs) > 0 {
@@ -561,6 +559,8 @@ func mustHaveFieldNameColon(line []byte) error {
        return nil
 }
 
+var nl = []byte("\n")
+
 // upcomingHeaderNewlines returns an approximation of the number of newlines
 // that will be in this header. If it gets confused, it returns 0.
 func (r *Reader) upcomingHeaderNewlines() (n int) {
@@ -571,17 +571,7 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
                return
        }
        peek, _ := r.R.Peek(s)
-       for len(peek) > 0 {
-               i := bytes.IndexByte(peek, '\n')
-               if i < 3 {
-                       // Not present (-1) or found within the next few bytes,
-                       // implying we're at the end ("\r\n\r\n" or "\n\n")
-                       return
-               }
-               n++
-               peek = peek[i+1:]
-       }
-       return
+       return bytes.Count(peek, nl)
 }
 
 // CanonicalMIMEHeaderKey returns the canonical format of the
index 20de0f6f5178a1e9f4cb39ab7352973d44732bdf..d571ab2fc4df0d7b266ccf519954574ba4f47383 100644 (file)
@@ -452,20 +452,6 @@ func getScheme(rawURL string) (scheme, path string, err error) {
        return "", rawURL, nil
 }
 
-// split slices s into two substrings separated by the first occurrence of
-// sep. If cutc is true then sep is excluded from the second substring.
-// If sep does not occur in s then s and the empty string is returned.
-func split(s string, sep byte, cutc bool) (string, string) {
-       i := strings.IndexByte(s, sep)
-       if i < 0 {
-               return s, ""
-       }
-       if cutc {
-               return s[:i], s[i+1:]
-       }
-       return s[:i], s[i:]
-}
-
 // Parse parses a raw url into a URL structure.
 //
 // The url may be relative (a path, without a host) or absolute
@@ -474,7 +460,7 @@ func split(s string, sep byte, cutc bool) (string, string) {
 // error, due to parsing ambiguities.
 func Parse(rawURL string) (*URL, error) {
        // Cut off #frag
-       u, frag := split(rawURL, '#', true)
+       u, frag, _ := strings.Cut(rawURL, "#")
        url, err := parse(u, false)
        if err != nil {
                return nil, &Error{"parse", u, err}
@@ -534,7 +520,7 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
                url.ForceQuery = true
                rest = rest[:len(rest)-1]
        } else {
-               rest, url.RawQuery = split(rest, '?', true)
+               rest, url.RawQuery, _ = strings.Cut(rest, "?")
        }
 
        if !strings.HasPrefix(rest, "/") {
@@ -553,9 +539,7 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
                // RFC 3986, §3.3:
                // In addition, a URI reference (Section 4.1) may be a relative-path reference,
                // in which case the first path segment cannot contain a colon (":") character.
-               colon := strings.Index(rest, ":")
-               slash := strings.Index(rest, "/")
-               if colon >= 0 && (slash < 0 || colon < slash) {
+               if segment, _, _ := strings.Cut(rest, "/"); strings.Contains(segment, ":") {
                        // First path segment has colon. Not allowed in relative URL.
                        return nil, errors.New("first path segment in URL cannot contain colon")
                }
@@ -563,7 +547,10 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
 
        if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
                var authority string
-               authority, rest = split(rest[2:], '/', false)
+               authority, rest = rest[2:], ""
+               if i := strings.Index(authority, "/"); i >= 0 {
+                       authority, rest = authority[:i], authority[i:]
+               }
                url.User, url.Host, err = parseAuthority(authority)
                if err != nil {
                        return nil, err
@@ -602,7 +589,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
                }
                user = User(userinfo)
        } else {
-               username, password := split(userinfo, ':', true)
+               username, password, _ := strings.Cut(userinfo, ":")
                if username, err = unescape(username, encodeUserPassword); err != nil {
                        return nil, "", err
                }
@@ -840,7 +827,7 @@ func (u *URL) String() string {
                        // it would be mistaken for a scheme name. Such a segment must be
                        // preceded by a dot-segment (e.g., "./this:that") to make a relative-
                        // path reference.
-                       if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
+                       if segment, _, _ := strings.Cut(path, "/"); strings.Contains(segment, ":") {
                                buf.WriteString("./")
                        }
                }
@@ -933,12 +920,8 @@ func ParseQuery(query string) (Values, error) {
 
 func parseQuery(m Values, query string) (err error) {
        for query != "" {
-               key := query
-               if i := strings.IndexAny(key, "&"); i >= 0 {
-                       key, query = key[:i], key[i+1:]
-               } else {
-                       query = ""
-               }
+               var key string
+               key, query, _ = strings.Cut(query, "&")
                if strings.Contains(key, ";") {
                        err = fmt.Errorf("invalid semicolon separator in query")
                        continue
@@ -946,10 +929,7 @@ func parseQuery(m Values, query string) (err error) {
                if key == "" {
                        continue
                }
-               value := ""
-               if i := strings.Index(key, "="); i >= 0 {
-                       key, value = key[:i], key[i+1:]
-               }
+               key, value, _ := strings.Cut(key, "=")
                key, err1 := QueryUnescape(key)
                if err1 != nil {
                        if err == nil {
@@ -1013,22 +993,16 @@ func resolvePath(base, ref string) string {
        }
 
        var (
-               last string
                elem string
-               i    int
                dst  strings.Builder
        )
        first := true
        remaining := full
        // We want to return a leading '/', so write it now.
        dst.WriteByte('/')
-       for i >= 0 {
-               i = strings.IndexByte(remaining, '/')
-               if i < 0 {
-                       last, elem, remaining = remaining, remaining, ""
-               } else {
-                       elem, remaining = remaining[:i], remaining[i+1:]
-               }
+       found := true
+       for found {
+               elem, remaining, found = strings.Cut(remaining, "/")
                if elem == "." {
                        first = false
                        // drop
@@ -1056,7 +1030,7 @@ func resolvePath(base, ref string) string {
                }
        }
 
-       if last == "." || last == ".." {
+       if elem == "." || elem == ".." {
                dst.WriteByte('/')
        }
 
index 63c8e695af765050f5bfa0c1db616d0cf905a7f9..5059d34bf13cae65db7ed1c819a297500239ffb3 100644 (file)
@@ -2059,12 +2059,3 @@ func BenchmarkPathUnescape(b *testing.B) {
                })
        }
 }
-
-var sink string
-
-func BenchmarkSplit(b *testing.B) {
-       url := "http://www.google.com/?q=go+language#foo%26bar"
-       for i := 0; i < b.N; i++ {
-               sink, sink = split(url, '#', true)
-       }
-}
index 0c495755116f5254030d45284ea31515cadb8487..9551c22d6e468e9a569cdb2e08776a912ef2cbc7 100644 (file)
@@ -748,12 +748,11 @@ func dedupEnvCase(caseInsensitive bool, env []string) []string {
        out := make([]string, 0, len(env))
        saw := make(map[string]int, len(env)) // key => index into out
        for _, kv := range env {
-               eq := strings.Index(kv, "=")
-               if eq < 0 {
+               k, _, ok := strings.Cut(kv, "=")
+               if !ok {
                        out = append(out, kv)
                        continue
                }
-               k := kv[:eq]
                if caseInsensitive {
                        k = strings.ToLower(k)
                }
@@ -775,11 +774,10 @@ func addCriticalEnv(env []string) []string {
                return env
        }
        for _, kv := range env {
-               eq := strings.Index(kv, "=")
-               if eq < 0 {
+               k, _, ok := strings.Cut(kv, "=")
+               if !ok {
                        continue
                }
-               k := kv[:eq]
                if strings.EqualFold(k, "SYSTEMROOT") {
                        // We already have it.
                        return env
index d854e0de843d69eff3da155b0710812c412d068b..459ba39dff8f50a48b00d496289555f4a0e35ad6 100644 (file)
@@ -166,12 +166,10 @@ func TestCatGoodAndBadFile(t *testing.T) {
        if _, ok := err.(*exec.ExitError); !ok {
                t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err)
        }
-       s := string(bs)
-       sp := strings.SplitN(s, "\n", 2)
-       if len(sp) != 2 {
-               t.Fatalf("expected two lines from cat; got %q", s)
+       errLine, body, ok := strings.Cut(string(bs), "\n")
+       if !ok {
+               t.Fatalf("expected two lines from cat; got %q", bs)
        }
-       errLine, body := sp[0], sp[1]
        if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") {
                t.Errorf("expected stderr to complain about file; got %q", errLine)
        }
index 506f1fb0ee6071e513d96a6a9f21702e8f8afdfd..62173d9bf4499ecc55ef3d90bc41cef2a0ae8a7e 100644 (file)
@@ -1761,8 +1761,8 @@ func TestHostname(t *testing.T) {
        // and the /bin/hostname only returns the first component
        want := runBinHostname(t)
        if hostname != want {
-               i := strings.Index(hostname, ".")
-               if i < 0 || hostname[0:i] != want {
+               host, _, ok := strings.Cut(hostname, ".")
+               if !ok || host != want {
                        t.Errorf("Hostname() = %q, want %q", hostname, want)
                }
        }
index abc9e9ce6d617d8c79e58b20c4774424eccde2a2..5c972e77cfbd9de4fcfb4521751d4af669f12109 100644 (file)
@@ -125,9 +125,7 @@ func buildUser(pwd *C.struct_passwd) *User {
        // say: "It is expected to be a comma separated list of
        // personal data where the first item is the full name of the
        // user."
-       if i := strings.Index(u.Name, ","); i >= 0 {
-               u.Name = u.Name[:i]
-       }
+       u.Name, _, _ = strings.Cut(u.Name, ",")
        return u
 }
 
index ac4f1502af8f1793427545233d9bf39d7b06ff63..1cabdb5b711ee87f23c6e495e5538f5f828c8469 100644 (file)
@@ -174,9 +174,7 @@ func matchUserIndexValue(value string, idx int) lineFunc {
                // say: "It is expected to be a comma separated list of
                // personal data where the first item is the full name of the
                // user."
-               if i := strings.Index(u.Name, ","); i >= 0 {
-                       u.Name = u.Name[:i]
-               }
+               u.Name, _, _ = strings.Cut(u.Name, ",")
                return u, nil
        }
 }
index 1f9a7a96e0c67d5eeb9b479b973dc0698f17f86e..5f8442668ca3c65dcc1f4be54bec12e693cb45b9 100644 (file)
@@ -294,12 +294,9 @@ func parseResult(t *testing.T, file string, lineno int, res string) []int {
                                out[n] = -1
                                out[n+1] = -1
                        } else {
-                               k := strings.Index(pair, "-")
-                               if k < 0 {
-                                       t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
-                               }
-                               lo, err1 := strconv.Atoi(pair[:k])
-                               hi, err2 := strconv.Atoi(pair[k+1:])
+                               loStr, hiStr, _ := strings.Cut(pair, "-")
+                               lo, err1 := strconv.Atoi(loStr)
+                               hi, err2 := strconv.Atoi(hiStr)
                                if err1 != nil || err2 != nil || lo > hi {
                                        t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
                                }
@@ -457,12 +454,11 @@ Reading:
                                continue Reading
                        }
                case ':':
-                       i := strings.Index(flag[1:], ":")
-                       if i < 0 {
+                       var ok bool
+                       if _, flag, ok = strings.Cut(flag[1:], ":"); !ok {
                                t.Logf("skip: %s", line)
                                continue Reading
                        }
-                       flag = flag[1+i+1:]
                case 'C', 'N', 'T', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
                        t.Logf("skip: %s", line)
                        continue Reading
index b547a2ab97d71a8e26f427942d307d39ddfb28b6..bfcf7910cf38041ed50c73ca79492a752c0801a5 100644 (file)
@@ -922,23 +922,22 @@ func (re *Regexp) ExpandString(dst []byte, template string, src string, match []
 
 func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, match []int) []byte {
        for len(template) > 0 {
-               i := strings.Index(template, "$")
-               if i < 0 {
+               before, after, ok := strings.Cut(template, "$")
+               if !ok {
                        break
                }
-               dst = append(dst, template[:i]...)
-               template = template[i:]
-               if len(template) > 1 && template[1] == '$' {
+               dst = append(dst, before...)
+               template = after
+               if template != "" && template[0] == '$' {
                        // Treat $$ as $.
                        dst = append(dst, '$')
-                       template = template[2:]
+                       template = template[1:]
                        continue
                }
                name, num, rest, ok := extract(template)
                if !ok {
                        // Malformed; treat $ as raw text.
                        dst = append(dst, '$')
-                       template = template[1:]
                        continue
                }
                template = rest
@@ -967,17 +966,16 @@ func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, m
        return dst
 }
 
-// extract returns the name from a leading "$name" or "${name}" in str.
+// extract returns the name from a leading "name" or "{name}" in str.
+// (The $ has already been removed by the caller.)
 // If it is a number, extract returns num set to that number; otherwise num = -1.
 func extract(str string) (name string, num int, rest string, ok bool) {
-       if len(str) < 2 || str[0] != '$' {
+       if str == "" {
                return
        }
        brace := false
-       if str[1] == '{' {
+       if str[0] == '{' {
                brace = true
-               str = str[2:]
-       } else {
                str = str[1:]
        }
        i := 0
index 7b4030935a7bb5056163af5794786cd6c6b727ec..06a92fb3d75322a89987d410b2f794c4039df242 100644 (file)
@@ -824,13 +824,7 @@ func Parse(s string, flags Flags) (*Regexp, error) {
                                case 'Q':
                                        // \Q ... \E: the ... is always literals
                                        var lit string
-                                       if i := strings.Index(t, `\E`); i < 0 {
-                                               lit = t[2:]
-                                               t = ""
-                                       } else {
-                                               lit = t[2:i]
-                                               t = t[i+2:]
-                                       }
+                                       lit, t, _ = strings.Cut(t[2:], `\E`)
                                        for lit != "" {
                                                c, rest, err := nextRune(lit)
                                                if err != nil {
index 0381bdcc53951c64b6277277467ca896c8863941..05cad61155cf0859ba4cac235bbf7874c211386b 100644 (file)
@@ -70,11 +70,10 @@ func readBuildInfo(data string) (*BuildInfo, bool) {
        )
        // Reverse of cmd/go/internal/modload.PackageBuildInfo
        for len(data) > 0 {
-               i := strings.IndexByte(data, '\n')
-               if i < 0 {
+               line, data, ok = strings.Cut(data, "\n")
+               if !ok {
                        break
                }
-               line, data = data[:i], data[i+1:]
                switch {
                case strings.HasPrefix(line, pathLine):
                        elem := line[len(pathLine):]
index f39d65c0b5effafddb7f551e20bef0cf1b39b967..03ff55b541594da0f9e51d99d6de4283253bd0ca 100644 (file)
@@ -1234,11 +1234,10 @@ func TestGoroutineCounts(t *testing.T) {
 
 func containsInOrder(s string, all ...string) bool {
        for _, t := range all {
-               i := strings.Index(s, t)
-               if i < 0 {
+               var ok bool
+               if _, s, ok = strings.Cut(s, t); !ok {
                        return false
                }
-               s = s[i+len(t):]
        }
        return true
 }
@@ -1318,18 +1317,18 @@ func TestEmptyCallStack(t *testing.T) {
 // stackContainsLabeled takes a spec like funcname;key=value and matches if the stack has that key
 // and value and has funcname somewhere in the stack.
 func stackContainsLabeled(spec string, count uintptr, stk []*profile.Location, labels map[string][]string) bool {
-       semi := strings.Index(spec, ";")
-       if semi == -1 {
+       base, kv, ok := strings.Cut(spec, ";")
+       if !ok {
                panic("no semicolon in key/value spec")
        }
-       kv := strings.SplitN(spec[semi+1:], "=", 2)
-       if len(kv) != 2 {
+       k, v, ok := strings.Cut(kv, "=")
+       if !ok {
                panic("missing = in key/value spec")
        }
-       if !contains(labels[kv[0]], kv[1]) {
+       if !contains(labels[k], v) {
                return false
        }
-       return stackContains(spec[:semi], count, stk, labels)
+       return stackContains(base, count, stk, labels)
 }
 
 func TestCPUProfileLabel(t *testing.T) {
index 686251395663f32358e39bc283513c13effedb34..54e7a80183e072be1e6061943965ae14c8b002c0 100644 (file)
@@ -13,6 +13,7 @@ import (
        "os"
        "runtime"
        "strconv"
+       "strings"
        "time"
        "unsafe"
 )
@@ -581,6 +582,9 @@ func (b *profileBuilder) readMapping() {
        }
 }
 
+var space = []byte(" ")
+var newline = []byte("\n")
+
 func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, buildID string)) {
        // $ cat /proc/self/maps
        // 00400000-0040b000 r-xp 00000000 fc:01 787766                             /bin/cat
@@ -607,37 +611,24 @@ func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file,
        // next removes and returns the next field in the line.
        // It also removes from line any spaces following the field.
        next := func() []byte {
-               j := bytes.IndexByte(line, ' ')
-               if j < 0 {
-                       f := line
-                       line = nil
-                       return f
-               }
-               f := line[:j]
-               line = line[j+1:]
-               for len(line) > 0 && line[0] == ' ' {
-                       line = line[1:]
-               }
+               var f []byte
+               f, line, _ = bytes.Cut(line, space)
+               line = bytes.TrimLeft(line, " ")
                return f
        }
 
        for len(data) > 0 {
-               i := bytes.IndexByte(data, '\n')
-               if i < 0 {
-                       line, data = data, nil
-               } else {
-                       line, data = data[:i], data[i+1:]
-               }
+               line, data, _ = bytes.Cut(data, newline)
                addr := next()
-               i = bytes.IndexByte(addr, '-')
-               if i < 0 {
+               loStr, hiStr, ok := strings.Cut(string(addr), "-")
+               if !ok {
                        continue
                }
-               lo, err := strconv.ParseUint(string(addr[:i]), 16, 64)
+               lo, err := strconv.ParseUint(loStr, 16, 64)
                if err != nil {
                        continue
                }
-               hi, err := strconv.ParseUint(string(addr[i+1:]), 16, 64)
+               hi, err := strconv.ParseUint(hiStr, 16, 64)
                if err != nil {
                        continue
                }
index d052b9fa421d699c660020b62a4764119e873e15..4a9749a83f2e85633adbd19dc6eff74b7cfaffce 100644 (file)
@@ -274,11 +274,10 @@ func TestProcSelfMaps(t *testing.T) {
 
        f := func(t *testing.T, input string) {
                for tx, tt := range strings.Split(input, "\n\n") {
-                       i := strings.Index(tt, "->\n")
-                       if i < 0 {
+                       in, out, ok := strings.Cut(tt, "->\n")
+                       if !ok {
                                t.Fatal("malformed test case")
                        }
-                       in, out := tt[:i], tt[i+len("->\n"):]
                        if len(out) > 0 && out[len(out)-1] != '\n' {
                                out += "\n"
                        }
index 8c76a9123c69ef7ec7f57fe9beebfa8cdbc8631b..4a0f489c2f8b04de0f172f8a8372feda5a9556f4 100644 (file)
@@ -267,7 +267,7 @@ func testGdbPython(t *testing.T, cgo bool) {
                t.Fatalf("gdb exited with error: %v", err)
        }
 
-       firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
+       firstLine, _, _ := bytes.Cut(got, []byte("\n"))
        if string(firstLine) != "Loading Go Runtime support." {
                // This can happen when using all.bash with
                // GOROOT_FINAL set, because the tests are run before
index aff36ec702b0660ce2b5d4597cea9c093f13fc50..7209f67959a0a293705c36a147bd1a8be900774d 100644 (file)
@@ -85,19 +85,18 @@ func getList() ([]string, error) {
        if err != nil {
                return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
        }
-       pos := bytes.IndexRune(output, '\n')
-       if pos == -1 {
+       output, _, ok := bytes.Cut(output, []byte("\n"))
+       if !ok {
                return nil, fmt.Errorf("invalid output from '%s', '\\n' not found: %s", cmdline, output)
        }
-       output = output[0:pos]
 
-       pos = bytes.IndexRune(output, ':')
-       if pos == -1 {
+       _, cpus, ok := bytes.Cut(output, []byte(":"))
+       if !ok {
                return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
        }
 
        var list []string
-       for _, val := range bytes.Split(output[pos+1:], []byte(",")) {
+       for _, val := range bytes.Split(cpus, []byte(",")) {
                index := string(bytes.TrimSpace(val))
                if len(index) == 0 {
                        continue
index 0ee402c4bdc60837db2f12d20c53d001f9a51f5c..1d0d00bab7d4ae48cc8fd81d7bd33e9e90e3debe 100644 (file)
@@ -33,30 +33,27 @@ func printStack() {
        for {
                n := runtime.Stack(buf, true)
                if n < len(buf) {
-                       tb := string(buf[:n])
+                       all := string(buf[:n])
+                       var saved string
 
                        // Delete any ignored goroutines, if present.
-                       pos := 0
-                       for pos < len(tb) {
-                               next := pos + strings.Index(tb[pos:], "\n\n")
-                               if next < pos {
-                                       next = len(tb)
-                               } else {
-                                       next += len("\n\n")
-                               }
+                       for all != "" {
+                               var g string
+                               g, all, _ = strings.Cut(all, "\n\n")
 
-                               if strings.HasPrefix(tb[pos:], "goroutine ") {
-                                       id := tb[pos+len("goroutine "):]
-                                       id = id[:strings.IndexByte(id, ' ')]
+                               if strings.HasPrefix(g, "goroutine ") {
+                                       id, _, _ := strings.Cut(strings.TrimPrefix(g, "goroutine "), " ")
                                        if ignoreGoroutines[id] {
-                                               tb = tb[:pos] + tb[next:]
-                                               next = pos
+                                               continue
                                        }
                                }
-                               pos = next
+                               if saved != "" {
+                                       saved += "\n\n"
+                               }
+                               saved += g
                        }
 
-                       fmt.Print(tb)
+                       fmt.Print(saved)
                        return
                }
                buf = make([]byte, 2*len(buf))
@@ -89,11 +86,10 @@ func recurseThenCallGo(w chan struct{}, frames int, goroutines int, main bool) {
 func goroutineID() string {
        buf := make([]byte, 128)
        runtime.Stack(buf, false)
-       const prefix = "goroutine "
-       if !bytes.HasPrefix(buf, []byte(prefix)) {
+       prefix := []byte("goroutine ")
+       if !bytes.HasPrefix(buf, prefix) {
                panic(fmt.Sprintf("expected %q at beginning of traceback:\n%s", prefix, buf))
        }
-       buf = buf[len(prefix):]
-       n := bytes.IndexByte(buf, ' ')
-       return string(buf[:n])
+       id, _, _ := bytes.Cut(bytes.TrimPrefix(buf, prefix), []byte(" "))
+       return string(id)
 }
index 39dd9c4a581539376c5421ce88728e690fa01955..fd73958c97d29eb174e19044c714ed0e31b75f1e 100644 (file)
@@ -28,15 +28,14 @@ func pow2(i int) float64 {
 // Wrapper around strconv.ParseFloat(x, 64).  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.ParseFloat.
 func myatof64(s string) (f float64, ok bool) {
-       a := strings.SplitN(s, "p", 2)
-       if len(a) == 2 {
-               n, err := strconv.ParseInt(a[0], 10, 64)
+       if mant, exp, ok := strings.Cut(s, "p"); ok {
+               n, err := strconv.ParseInt(mant, 10, 64)
                if err != nil {
                        return 0, false
                }
-               e, err1 := strconv.Atoi(a[1])
+               e, err1 := strconv.Atoi(exp)
                if err1 != nil {
-                       println("bad e", a[1])
+                       println("bad e", exp)
                        return 0, false
                }
                v := float64(n)
@@ -72,16 +71,15 @@ func myatof64(s string) (f float64, ok bool) {
 // Wrapper around strconv.ParseFloat(x, 32).  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.ParseFloat.
 func myatof32(s string) (f float32, ok bool) {
-       a := strings.SplitN(s, "p", 2)
-       if len(a) == 2 {
-               n, err := strconv.Atoi(a[0])
+       if mant, exp, ok := strings.Cut(s, "p"); ok {
+               n, err := strconv.Atoi(mant)
                if err != nil {
-                       println("bad n", a[0])
+                       println("bad n", mant)
                        return 0, false
                }
-               e, err1 := strconv.Atoi(a[1])
+               e, err1 := strconv.Atoi(exp)
                if err1 != nil {
-                       println("bad p", a[1])
+                       println("bad p", exp)
                        return 0, false
                }
                return float32(float64(n) * pow2(e)), true
index 1555318edae46715333873e39b61f15e8e02b8f9..79b2633aca079acca0e037d8a8d4373a82cf9868 100644 (file)
@@ -510,9 +510,7 @@ func mustSupportAmbientCaps(t *testing.T) {
                buf[i] = byte(b)
        }
        ver := string(buf[:])
-       if i := strings.Index(ver, "\x00"); i != -1 {
-               ver = ver[:i]
-       }
+       ver, _, _ = strings.Cut(ver, "\x00")
        if strings.HasPrefix(ver, "2.") ||
                strings.HasPrefix(ver, "3.") ||
                strings.HasPrefix(ver, "4.1.") ||
index addce2d890d6d842445dae44c8d140a90416c41a..1035afad72a93f4eaa2d0282c83a43e68bba5e0c 100644 (file)
@@ -51,13 +51,11 @@ func (t *Template) setOption(opt string) {
        if opt == "" {
                panic("empty option string")
        }
-       elems := strings.Split(opt, "=")
-       switch len(elems) {
-       case 2:
-               // key=value
-               switch elems[0] {
+       // key=value
+       if key, value, ok := strings.Cut(opt, "="); ok {
+               switch key {
                case "missingkey":
-                       switch elems[1] {
+                       switch value {
                        case "invalid", "default":
                                t.option.missingKey = mapInvalid
                                return
index 0c9c8c5cb89fc2de588f8dd3fa87aa0f882f4fbc..0c5da1af78c5d9044fd1f09b0db6022e51e78d35 100644 (file)
@@ -535,9 +535,9 @@ func (ctxt *context) match(name string) bool {
        if name == "" {
                return false
        }
-       if i := strings.Index(name, ","); i >= 0 {
+       if first, rest, ok := strings.Cut(name, ","); ok {
                // comma-separated list
-               return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+               return ctxt.match(first) && ctxt.match(rest)
        }
        if strings.HasPrefix(name, "!!") { // bad syntax, reject always
                return false
@@ -622,24 +622,23 @@ func (t *test) run() {
        }
 
        // Execution recipe stops at first blank line.
-       pos := strings.Index(t.src, "\n\n")
-       if pos == -1 {
+       action, _, ok := strings.Cut(t.src, "\n\n")
+       if !ok {
                t.err = fmt.Errorf("double newline ending execution recipe not found in %s", t.goFileName())
                return
        }
-       action := t.src[:pos]
-       if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
+       if firstLine, rest, ok := strings.Cut(action, "\n"); ok && strings.Contains(firstLine, "+build") {
                // skip first line
-               action = action[nl+1:]
+               action = rest
        }
        action = strings.TrimPrefix(action, "//")
 
        // Check for build constraints only up to the actual code.
-       pkgPos := strings.Index(t.src, "\npackage")
-       if pkgPos == -1 {
-               pkgPos = pos // some files are intentionally malformed
+       header, _, ok := strings.Cut(t.src, "\npackage")
+       if !ok {
+               header = action // some files are intentionally malformed
        }
-       if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
+       if ok, why := shouldTest(header, goos, goarch); !ok {
                if *showSkips {
                        fmt.Printf("%-20s %-20s: %s\n", "skip", t.goFileName(), why)
                }
@@ -1516,8 +1515,8 @@ func (t *test) errorCheck(outStr string, wantAuto bool, fullshort ...string) (er
                        // 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
@@ -1562,31 +1561,26 @@ func (t *test) updateErrors(out, file string) {
        }
        lines := strings.Split(string(src), "\n")
        // Remove old errors.
-       for i, ln := range lines {
-               pos := strings.Index(ln, " // ERROR ")
-               if pos >= 0 {
-                       lines[i] = ln[:pos]
-               }
+       for i := range lines {
+               lines[i], _, _ = strings.Cut(lines[i], " // ERROR ")
        }
        // Parse new errors.
        errors := make(map[int]map[string]bool)
        tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
        for _, errStr := range splitOutput(out, false) {
-               colon1 := strings.Index(errStr, ":")
-               if colon1 < 0 || errStr[:colon1] != file {
+               errFile, rest, ok := strings.Cut(errStr, ":")
+               if !ok || errFile != file {
                        continue
                }
-               colon2 := strings.Index(errStr[colon1+1:], ":")
-               if colon2 < 0 {
+               lineStr, msg, ok := strings.Cut(rest, ":")
+               if !ok {
                        continue
                }
-               colon2 += colon1 + 1
-               line, err := strconv.Atoi(errStr[colon1+1 : colon2])
+               line, err := strconv.Atoi(lineStr)
                line--
                if err != nil || line < 0 || line >= len(lines) {
                        continue
                }
-               msg := errStr[colon2+2:]
                msg = strings.Replace(msg, file, base, -1) // normalize file mentions in error itself
                msg = strings.TrimLeft(msg, " \t")
                for _, r := range []string{`\`, `*`, `+`, `?`, `[`, `]`, `(`, `)`} {
index 214d481164442aab25c7e5f9189933108a54c005..fd36d67d1ad6dc8b189473a7e45206edea866428 100644 (file)
@@ -218,7 +218,7 @@ func main() {
                        }
                        fmt.Printf("%s: expected no error; got %q\n", t.name, err)
                case t.err != "" && err != "":
-                       if strings.Index(err, t.err) < 0 {
+                       if !strings.Contains(err, t.err) {
                                if !bad {
                                        bad = true
                                        fmt.Printf("BUG\n")