]> Cypherpunks repositories - gostls13.git/commitdiff
strings, internal/stringslite: lite version of strings package
authorDamien Neil <dneil@google.com>
Wed, 24 Apr 2024 16:52:52 +0000 (09:52 -0700)
committerDamien Neil <dneil@google.com>
Fri, 26 Apr 2024 23:07:25 +0000 (23:07 +0000)
To be used by internal/filepathlite, which is to be used by os.
There are probably other places where it would be convenient
to have strings functions accessible to RUNTIME level packages.

Change-Id: Icda59e7a9e26d9e8f3692db0ea4fb7b3dbf570d7
Reviewed-on: https://go-review.googlesource.com/c/go/+/581516
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/go/build/deps_test.go
src/internal/stringslite/strings.go [new file with mode: 0644]
src/strings/strings.go

index 0ea34b1bd7abfd88445e7c38028b17ecded00b83..a3ba8092be65732cc101a768511c6cbd2cbb841d 100644 (file)
@@ -66,6 +66,7 @@ var depsRules = `
        internal/goexperiment,
        internal/goos
        < internal/bytealg
+       < internal/stringslite
        < internal/itoa
        < internal/unsafeheader
        < runtime/internal/sys
diff --git a/src/internal/stringslite/strings.go b/src/internal/stringslite/strings.go
new file mode 100644 (file)
index 0000000..ce8a913
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package stringslite implements a subset of strings,
+// only using packages that may be imported by "os".
+//
+// Tests for these functions are in the strings package.
+package stringslite
+
+import "internal/bytealg"
+
+func HasPrefix(s, prefix string) bool {
+       return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+func HasSuffix(s, suffix string) bool {
+       return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+func IndexByte(s string, c byte) int {
+       return bytealg.IndexByteString(s, c)
+}
+
+func Index(s, substr string) int {
+       n := len(substr)
+       switch {
+       case n == 0:
+               return 0
+       case n == 1:
+               return IndexByte(s, substr[0])
+       case n == len(s):
+               if substr == s {
+                       return 0
+               }
+               return -1
+       case n > len(s):
+               return -1
+       case n <= bytealg.MaxLen:
+               // Use brute force when s and substr both are small
+               if len(s) <= bytealg.MaxBruteForce {
+                       return bytealg.IndexString(s, substr)
+               }
+               c0 := substr[0]
+               c1 := substr[1]
+               i := 0
+               t := len(s) - n + 1
+               fails := 0
+               for i < t {
+                       if s[i] != c0 {
+                               // IndexByte is faster than bytealg.IndexString, so use it as long as
+                               // we're not getting lots of false positives.
+                               o := IndexByte(s[i+1:t], c0)
+                               if o < 0 {
+                                       return -1
+                               }
+                               i += o + 1
+                       }
+                       if s[i+1] == c1 && s[i:i+n] == substr {
+                               return i
+                       }
+                       fails++
+                       i++
+                       // Switch to bytealg.IndexString when IndexByte produces too many false positives.
+                       if fails > bytealg.Cutover(i) {
+                               r := bytealg.IndexString(s[i:], substr)
+                               if r >= 0 {
+                                       return r + i
+                               }
+                               return -1
+                       }
+               }
+               return -1
+       }
+       c0 := substr[0]
+       c1 := substr[1]
+       i := 0
+       t := len(s) - n + 1
+       fails := 0
+       for i < t {
+               if s[i] != c0 {
+                       o := IndexByte(s[i+1:t], c0)
+                       if o < 0 {
+                               return -1
+                       }
+                       i += o + 1
+               }
+               if s[i+1] == c1 && s[i:i+n] == substr {
+                       return i
+               }
+               i++
+               fails++
+               if fails >= 4+i>>4 && i < t {
+                       // See comment in ../bytes/bytes.go.
+                       j := bytealg.IndexRabinKarp(s[i:], substr)
+                       if j < 0 {
+                               return -1
+                       }
+                       return i + j
+               }
+       }
+       return -1
+}
+
+func Cut(s, sep string) (before, after string, found bool) {
+       if i := Index(s, sep); i >= 0 {
+               return s[:i], s[i+len(sep):], true
+       }
+       return s, "", false
+}
+
+func CutPrefix(s, prefix string) (after string, found bool) {
+       if !HasPrefix(s, prefix) {
+               return s, false
+       }
+       return s[len(prefix):], true
+}
+
+func CutSuffix(s, suffix string) (before string, found bool) {
+       if !HasSuffix(s, suffix) {
+               return s, false
+       }
+       return s[:len(s)-len(suffix)], true
+}
index f53ae1f9a785a3f24d2149395b31e06c0f70f7b5..11c558c4c3b28fa5d1db16bcf5e4cfe2bdc3d619 100644 (file)
@@ -9,6 +9,7 @@ package strings
 
 import (
        "internal/bytealg"
+       "internal/stringslite"
        "unicode"
        "unicode/utf8"
 )
@@ -115,7 +116,7 @@ func LastIndex(s, substr string) int {
 
 // IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
 func IndexByte(s string, c byte) int {
-       return bytealg.IndexByteString(s, c)
+       return stringslite.IndexByte(s, c)
 }
 
 // IndexRune returns the index of the first instance of the Unicode code point
@@ -460,12 +461,12 @@ func Join(elems []string, sep string) string {
 
 // HasPrefix reports whether the string s begins with prefix.
 func HasPrefix(s, prefix string) bool {
-       return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+       return stringslite.HasPrefix(s, prefix)
 }
 
 // HasSuffix reports whether the string s ends with suffix.
 func HasSuffix(s, suffix string) bool {
-       return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+       return stringslite.HasSuffix(s, suffix)
 }
 
 // Map returns a copy of the string s with all its characters modified
@@ -1225,83 +1226,7 @@ hasUnicode:
 
 // Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
 func Index(s, substr string) int {
-       n := len(substr)
-       switch {
-       case n == 0:
-               return 0
-       case n == 1:
-               return IndexByte(s, substr[0])
-       case n == len(s):
-               if substr == s {
-                       return 0
-               }
-               return -1
-       case n > len(s):
-               return -1
-       case n <= bytealg.MaxLen:
-               // Use brute force when s and substr both are small
-               if len(s) <= bytealg.MaxBruteForce {
-                       return bytealg.IndexString(s, substr)
-               }
-               c0 := substr[0]
-               c1 := substr[1]
-               i := 0
-               t := len(s) - n + 1
-               fails := 0
-               for i < t {
-                       if s[i] != c0 {
-                               // IndexByte is faster than bytealg.IndexString, so use it as long as
-                               // we're not getting lots of false positives.
-                               o := IndexByte(s[i+1:t], c0)
-                               if o < 0 {
-                                       return -1
-                               }
-                               i += o + 1
-                       }
-                       if s[i+1] == c1 && s[i:i+n] == substr {
-                               return i
-                       }
-                       fails++
-                       i++
-                       // Switch to bytealg.IndexString when IndexByte produces too many false positives.
-                       if fails > bytealg.Cutover(i) {
-                               r := bytealg.IndexString(s[i:], substr)
-                               if r >= 0 {
-                                       return r + i
-                               }
-                               return -1
-                       }
-               }
-               return -1
-       }
-       c0 := substr[0]
-       c1 := substr[1]
-       i := 0
-       t := len(s) - n + 1
-       fails := 0
-       for i < t {
-               if s[i] != c0 {
-                       o := IndexByte(s[i+1:t], c0)
-                       if o < 0 {
-                               return -1
-                       }
-                       i += o + 1
-               }
-               if s[i+1] == c1 && s[i:i+n] == substr {
-                       return i
-               }
-               i++
-               fails++
-               if fails >= 4+i>>4 && i < t {
-                       // See comment in ../bytes/bytes.go.
-                       j := bytealg.IndexRabinKarp(s[i:], substr)
-                       if j < 0 {
-                               return -1
-                       }
-                       return i + j
-               }
-       }
-       return -1
+       return stringslite.Index(s, substr)
 }
 
 // Cut slices s around the first instance of sep,
@@ -1309,10 +1234,7 @@ func Index(s, substr string) int {
 // The found result reports whether sep appears in s.
 // If sep does not appear in s, cut returns s, "", false.
 func Cut(s, sep string) (before, after string, found bool) {
-       if i := Index(s, sep); i >= 0 {
-               return s[:i], s[i+len(sep):], true
-       }
-       return s, "", false
+       return stringslite.Cut(s, sep)
 }
 
 // CutPrefix returns s without the provided leading prefix string
@@ -1320,10 +1242,7 @@ func Cut(s, sep string) (before, after string, found bool) {
 // If s doesn't start with prefix, CutPrefix returns s, false.
 // If prefix is the empty string, CutPrefix returns s, true.
 func CutPrefix(s, prefix string) (after string, found bool) {
-       if !HasPrefix(s, prefix) {
-               return s, false
-       }
-       return s[len(prefix):], true
+       return stringslite.CutPrefix(s, prefix)
 }
 
 // CutSuffix returns s without the provided ending suffix string
@@ -1331,8 +1250,5 @@ func CutPrefix(s, prefix string) (after string, found bool) {
 // If s doesn't end with suffix, CutSuffix returns s, false.
 // If suffix is the empty string, CutSuffix returns s, true.
 func CutSuffix(s, suffix string) (before string, found bool) {
-       if !HasSuffix(s, suffix) {
-               return s, false
-       }
-       return s[:len(s)-len(suffix)], true
+       return stringslite.CutSuffix(s, suffix)
 }