github.com/primecitizens/pcz/std@v0.2.1/core/bytealg/index.native.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 "github.com/primecitizens/pcz/std/core/cmp"
    13  
    14  //go:noescape
    15  
    16  // indeSlice returns the index of the first instance of b in a, or -1 if b is not present in a.
    17  // Requires 2 <= len(b) <= indexArgBMaxLen.
    18  func indexSlice(a, b []byte) int
    19  
    20  //go:noescape
    21  
    22  // index returns the index of the first instance of b in a, or -1 if b is not present in a.
    23  // Requires 2 <= len(b) <= indexArgBMaxLen.
    24  func index(a, b string) int
    25  
    26  // IndexSlice returns the index of the first instance of sep in s,
    27  // or -1 if sep is not present in s.
    28  func IndexSlice(s, sep []byte) int {
    29  	n := len(sep)
    30  	switch {
    31  	case n == 0:
    32  		return 0
    33  	case n == 1:
    34  		return IndexSliceByte(s, sep[0])
    35  	case n == len(s):
    36  		if cmp.BytesEqual(sep, s) {
    37  			return 0
    38  		}
    39  		return -1
    40  	case n > len(s):
    41  		return -1
    42  	case n <= indexArgBMaxLen:
    43  		// Use brute force when s and sep both are small
    44  		if len(s) <= MaxBruteForce {
    45  			return indexSlice(s, sep)
    46  		}
    47  		c0 := sep[0]
    48  		c1 := sep[1]
    49  		i := 0
    50  		t := len(s) - n + 1
    51  		fails := 0
    52  		for i < t {
    53  			if s[i] != c0 {
    54  				// IndexSliceByte is faster than indexSlice, so use it as long as
    55  				// we're not getting lots of false positives.
    56  				o := IndexSliceByte(s[i+1:t], c0)
    57  				if o < 0 {
    58  					return -1
    59  				}
    60  				i += o + 1
    61  			}
    62  			if s[i+1] == c1 && cmp.BytesEqual(s[i:i+n], sep) {
    63  				return i
    64  			}
    65  			fails++
    66  			i++
    67  			// Switch to indexSlice when IndexByte produces too many false positives.
    68  			if fails > cutover(i) {
    69  				r := indexSlice(s[i:], sep)
    70  				if r >= 0 {
    71  					return r + i
    72  				}
    73  				return -1
    74  			}
    75  		}
    76  		return -1
    77  	}
    78  	c0 := sep[0]
    79  	c1 := sep[1]
    80  	i := 0
    81  	fails := 0
    82  	t := len(s) - n + 1
    83  	for i < t {
    84  		if s[i] != c0 {
    85  			o := IndexSliceByte(s[i+1:t], c0)
    86  			if o < 0 {
    87  				break
    88  			}
    89  			i += o + 1
    90  		}
    91  		if s[i+1] == c1 && cmp.BytesEqual(s[i:i+n], sep) {
    92  			return i
    93  		}
    94  		i++
    95  		fails++
    96  		if fails >= 4+i>>4 && i < t {
    97  			// Give up on IndexByte, it isn't skipping ahead
    98  			// far enough to be better than Rabin-Karp.
    99  			// Experiments (using IndexPeriodic) suggest
   100  			// the cutover is about 16 byte skips.
   101  			// TODO: if large prefixes of sep are matching
   102  			// we should cutover at even larger average skips,
   103  			// because Equal becomes that much more expensive.
   104  			// This code does not take that effect into account.
   105  			j := IndexRabinKarpBytes(s[i:], sep)
   106  			if j < 0 {
   107  				return -1
   108  			}
   109  			return i + j
   110  		}
   111  	}
   112  	return -1
   113  }
   114  
   115  // Index returns the index of the first instance of substr in s,
   116  // or -1 if substr is not present in s.
   117  func Index(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  		// Use brute force when s and substr both are small
   133  		if len(s) <= MaxBruteForce {
   134  			return index(s, substr)
   135  		}
   136  		c0 := substr[0]
   137  		c1 := substr[1]
   138  		i := 0
   139  		t := len(s) - n + 1
   140  		fails := 0
   141  		for i < t {
   142  			if s[i] != c0 {
   143  				// IndexByte is faster than index, so use it as long as
   144  				// we're not getting lots of false positives.
   145  				o := IndexByte(s[i+1:t], c0)
   146  				if o < 0 {
   147  					return -1
   148  				}
   149  				i += o + 1
   150  			}
   151  			if s[i+1] == c1 && s[i:i+n] == substr {
   152  				return i
   153  			}
   154  			fails++
   155  			i++
   156  			// Switch to index when IndexByte produces too many false positives.
   157  			if fails > cutover(i) {
   158  				r := index(s[i:], substr)
   159  				if r >= 0 {
   160  					return r + i
   161  				}
   162  				return -1
   163  			}
   164  		}
   165  		return -1
   166  	}
   167  	c0 := substr[0]
   168  	c1 := substr[1]
   169  	i := 0
   170  	t := len(s) - n + 1
   171  	fails := 0
   172  	for i < t {
   173  		if s[i] != c0 {
   174  			o := IndexByte(s[i+1:t], c0)
   175  			if o < 0 {
   176  				return -1
   177  			}
   178  			i += o + 1
   179  		}
   180  		if s[i+1] == c1 && s[i:i+n] == substr {
   181  			return i
   182  		}
   183  		i++
   184  		fails++
   185  		if fails >= 4+i>>4 && i < t {
   186  			// See comment in ../bytes/bytes.go.
   187  			j := IndexRabinKarp(s[i:], substr)
   188  			if j < 0 {
   189  				return -1
   190  			}
   191  			return i + j
   192  		}
   193  	}
   194  	return -1
   195  }