github.com/primecitizens/pcz/std@v0.2.1/core/bytealg/index.generic.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  //
     4  // Copyright 2018 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  //go:build pcz && !(amd64 || arm64 || s390x || ppc64le || ppc64)
     9  
    10  package bytealg
    11  
    12  import (
    13  	"github.com/primecitizens/pcz/std/core/cmp"
    14  )
    15  
    16  const (
    17  	// indexArgBMaxLen is the maximum length of the string to be searched for (argument b) in Index.
    18  	// If indexArgBMaxLen is not 0, make sure indexArgBMaxLen >= 4.
    19  	indexArgBMaxLen = 0
    20  	MaxBruteForce   = 0
    21  )
    22  
    23  // cutover reports the number of failures of IndexByte we should tolerate
    24  // before switching over to Index.
    25  // n is the number of bytes processed so far.
    26  // See the bytes.Index implementation for details.
    27  func cutover(n int) int {
    28  	return 0
    29  }
    30  
    31  // Index returns the index of the first instance of b in a,
    32  // or -1 if b is not present in a.
    33  func Index(s, sep []byte) int {
    34  	n := len(sep)
    35  	switch {
    36  	case n == 0:
    37  		return 0
    38  	case n == 1:
    39  		return IndexSliceByte(s, sep[0])
    40  	case n == len(s):
    41  		if cmp.BytesEqual(sep, s) {
    42  			return 0
    43  		}
    44  		return -1
    45  	case n > len(s):
    46  		return -1
    47  	case n <= indexArgBMaxLen:
    48  		c0 := sep[0]
    49  		c1 := sep[1]
    50  		i := 0
    51  		t := len(s) - n + 1
    52  		fails := 0
    53  		for i < t {
    54  			if s[i] != c0 {
    55  				// IndexByte is faster than Index, so use it as long as
    56  				// we're not getting lots of false positives.
    57  				o := IndexSliceByte(s[i+1:t], c0)
    58  				if o < 0 {
    59  					return -1
    60  				}
    61  				i += o + 1
    62  			}
    63  			if s[i+1] == c1 && cmp.BytesEqual(s[i:i+n], sep) {
    64  				return i
    65  			}
    66  			fails++
    67  			i++
    68  			// Switch to Index when IndexByte produces too many false positives.
    69  			if fails > cutover(i) {
    70  				r := Index(s[i:], sep)
    71  				if r >= 0 {
    72  					return r + i
    73  				}
    74  				return -1
    75  			}
    76  		}
    77  		return -1
    78  	}
    79  	c0 := sep[0]
    80  	c1 := sep[1]
    81  	i := 0
    82  	fails := 0
    83  	t := len(s) - n + 1
    84  	for i < t {
    85  		if s[i] != c0 {
    86  			o := IndexSliceByte(s[i+1:t], c0)
    87  			if o < 0 {
    88  				break
    89  			}
    90  			i += o + 1
    91  		}
    92  		if s[i+1] == c1 && cmp.BytesEqual(s[i:i+n], sep) {
    93  			return i
    94  		}
    95  		i++
    96  		fails++
    97  		if fails >= 4+i>>4 && i < t {
    98  			// Give up on IndexByte, it isn't skipping ahead
    99  			// far enough to be better than Rabin-Karp.
   100  			// Experiments (using IndexPeriodic) suggest
   101  			// the cutover is about 16 byte skips.
   102  			// TODO: if large prefixes of sep are matching
   103  			// we should cutover at even larger average skips,
   104  			// because Equal becomes that much more expensive.
   105  			// This code does not take that effect into account.
   106  			j := IndexRabinKarpBytes(s[i:], sep)
   107  			if j < 0 {
   108  				return -1
   109  			}
   110  			return i + j
   111  		}
   112  	}
   113  	return -1
   114  }
   115  
   116  // IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
   117  func IndexString(s, substr string) int {
   118  	n := len(substr)
   119  	switch {
   120  	case n == 0:
   121  		return 0
   122  	case n == 1:
   123  		return IndexByte(s, substr[0])
   124  	case n == len(s):
   125  		if substr == s {
   126  			return 0
   127  		}
   128  		return -1
   129  	case n > len(s):
   130  		return -1
   131  	case n <= indexArgBMaxLen:
   132  		c0 := substr[0]
   133  		c1 := substr[1]
   134  		i := 0
   135  		t := len(s) - n + 1
   136  		fails := 0
   137  		for i < t {
   138  			if s[i] != c0 {
   139  				// IndexByteString is faster than IndexString, so use it as long as
   140  				// we're not getting lots of false positives.
   141  				o := IndexByte(s[i+1:t], c0)
   142  				if o < 0 {
   143  					return -1
   144  				}
   145  				i += o + 1
   146  			}
   147  			if s[i+1] == c1 && s[i:i+n] == substr {
   148  				return i
   149  			}
   150  			fails++
   151  			i++
   152  			// Switch to IndexString when IndexByte produces too many false positives.
   153  			if fails > cutover(i) {
   154  				r := IndexString(s[i:], substr)
   155  				if r >= 0 {
   156  					return r + i
   157  				}
   158  				return -1
   159  			}
   160  		}
   161  		return -1
   162  	}
   163  	c0 := substr[0]
   164  	c1 := substr[1]
   165  	i := 0
   166  	t := len(s) - n + 1
   167  	fails := 0
   168  	for i < t {
   169  		if s[i] != c0 {
   170  			o := IndexByte(s[i+1:t], c0)
   171  			if o < 0 {
   172  				return -1
   173  			}
   174  			i += o + 1
   175  		}
   176  		if s[i+1] == c1 && s[i:i+n] == substr {
   177  			return i
   178  		}
   179  		i++
   180  		fails++
   181  		if fails >= 4+i>>4 && i < t {
   182  			// See comment in ../bytes/bytes.go.
   183  			j := IndexRabinKarp(s[i:], substr)
   184  			if j < 0 {
   185  				return -1
   186  			}
   187  			return i + j
   188  		}
   189  	}
   190  	return -1
   191  }