Source file src/internal/stringslite/strings.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package stringslite implements a subset of strings,
     6  // only using packages that may be imported by "os".
     7  //
     8  // Tests for these functions are in the strings package.
     9  package stringslite
    10  
    11  import (
    12  	"internal/bytealg"
    13  	"unsafe"
    14  )
    15  
    16  func HasPrefix(s, prefix string) bool {
    17  	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
    18  }
    19  
    20  func HasSuffix(s, suffix string) bool {
    21  	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
    22  }
    23  
    24  func IndexByte(s string, c byte) int {
    25  	return bytealg.IndexByteString(s, c)
    26  }
    27  
    28  func Index(s, substr string) int {
    29  	n := len(substr)
    30  	switch {
    31  	case n == 0:
    32  		return 0
    33  	case n == 1:
    34  		return IndexByte(s, substr[0])
    35  	case n == len(s):
    36  		if substr == s {
    37  			return 0
    38  		}
    39  		return -1
    40  	case n > len(s):
    41  		return -1
    42  	case n <= bytealg.MaxLen:
    43  		// Use brute force when s and substr both are small
    44  		if len(s) <= bytealg.MaxBruteForce {
    45  			return bytealg.IndexString(s, substr)
    46  		}
    47  		c0 := substr[0]
    48  		c1 := substr[1]
    49  		i := 0
    50  		t := len(s) - n + 1
    51  		fails := 0
    52  		for i < t {
    53  			if s[i] != c0 {
    54  				// IndexByte is faster than bytealg.IndexString, so use it as long as
    55  				// we're not getting lots of false positives.
    56  				o := IndexByte(s[i+1:t], c0)
    57  				if o < 0 {
    58  					return -1
    59  				}
    60  				i += o + 1
    61  			}
    62  			if s[i+1] == c1 && s[i:i+n] == substr {
    63  				return i
    64  			}
    65  			fails++
    66  			i++
    67  			// Switch to bytealg.IndexString when IndexByte produces too many false positives.
    68  			if fails > bytealg.Cutover(i) {
    69  				r := bytealg.IndexString(s[i:], substr)
    70  				if r >= 0 {
    71  					return r + i
    72  				}
    73  				return -1
    74  			}
    75  		}
    76  		return -1
    77  	}
    78  	c0 := substr[0]
    79  	c1 := substr[1]
    80  	i := 0
    81  	t := len(s) - n + 1
    82  	fails := 0
    83  	for i < t {
    84  		if s[i] != c0 {
    85  			o := IndexByte(s[i+1:t], c0)
    86  			if o < 0 {
    87  				return -1
    88  			}
    89  			i += o + 1
    90  		}
    91  		if s[i+1] == c1 && s[i:i+n] == substr {
    92  			return i
    93  		}
    94  		i++
    95  		fails++
    96  		if fails >= 4+i>>4 && i < t {
    97  			// See comment in ../bytes/bytes.go.
    98  			j := bytealg.IndexRabinKarp(s[i:], substr)
    99  			if j < 0 {
   100  				return -1
   101  			}
   102  			return i + j
   103  		}
   104  	}
   105  	return -1
   106  }
   107  
   108  func Cut(s, sep string) (before, after string, found bool) {
   109  	if i := Index(s, sep); i >= 0 {
   110  		return s[:i], s[i+len(sep):], true
   111  	}
   112  	return s, "", false
   113  }
   114  
   115  func CutPrefix(s, prefix string) (after string, found bool) {
   116  	if !HasPrefix(s, prefix) {
   117  		return s, false
   118  	}
   119  	return s[len(prefix):], true
   120  }
   121  
   122  func CutSuffix(s, suffix string) (before string, found bool) {
   123  	if !HasSuffix(s, suffix) {
   124  		return s, false
   125  	}
   126  	return s[:len(s)-len(suffix)], true
   127  }
   128  
   129  func TrimPrefix(s, prefix string) string {
   130  	if HasPrefix(s, prefix) {
   131  		return s[len(prefix):]
   132  	}
   133  	return s
   134  }
   135  
   136  func TrimSuffix(s, suffix string) string {
   137  	if HasSuffix(s, suffix) {
   138  		return s[:len(s)-len(suffix)]
   139  	}
   140  	return s
   141  }
   142  
   143  func Clone(s string) string {
   144  	if len(s) == 0 {
   145  		return ""
   146  	}
   147  	b := make([]byte, len(s))
   148  	copy(b, s)
   149  	return unsafe.String(&b[0], len(b))
   150  }
   151  

View as plain text