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. 9package stringslite 10 11import ( 12 "internal/bytealg" 13 "unsafe" 14) 15 16func HasPrefix(s, prefix string) bool { 17 return len(s) >= len(prefix) && s[0:len(prefix)] == prefix 18} 19 20func HasSuffix(s, suffix string) bool { 21 return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix 22} 23 24func IndexByte(s string, c byte) int { 25 return bytealg.IndexByteString(s, c) 26} 27 28func 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 108func 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 115func 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 122func 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 129func TrimPrefix(s, prefix string) string { 130 if HasPrefix(s, prefix) { 131 return s[len(prefix):] 132 } 133 return s 134} 135 136func TrimSuffix(s, suffix string) string { 137 if HasSuffix(s, suffix) { 138 return s[:len(s)-len(suffix)] 139 } 140 return s 141} 142 143func 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