// 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" "unsafe" ) 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 } func TrimPrefix(s, prefix string) string { if HasPrefix(s, prefix) { return s[len(prefix):] } return s } func TrimSuffix(s, suffix string) string { if HasSuffix(s, suffix) { return s[:len(s)-len(suffix)] } return s } func Clone(s string) string { if len(s) == 0 { return "" } b := make([]byte, len(s)) copy(b, s) return unsafe.String(&b[0], len(b)) }