github.com/haraldrudell/parl@v0.4.176/pslices/index-partial.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pslices
     7  
     8  import (
     9  	"bytes"
    10  
    11  	"golang.org/x/exp/slices"
    12  )
    13  
    14  // IndexPartial returns scan-result in a byte-slice for a key byte-sequence, whether key was found
    15  // or more bytes needs to be read to determine if key is present.
    16  //   - index is the first index to search at and it is checked against the length of byts
    17  //   - return value:
    18  //   - — notKnown: true, newIndex >= index: byts ended during a partial key match, newIndex is first byte of match
    19  //   - — notKnown: false, newIndex >= index: entire key was found at newIndex
    20  //   - — newIndex -1: no key sequence was found in byts
    21  //   - empty or nil key is found immediately, but only if index is less than length of byts
    22  //   - if byts is nil or empty, nothing is found
    23  //   - panic-free
    24  func IndexPartial(byts []byte, index int, key []byte) (newIndex int, notKnown bool) {
    25  	if index < 0 {
    26  		index = 0
    27  	}
    28  	if index < len(byts) {
    29  
    30  		// check for entire key in byts
    31  		// if key is empty, bytes.Index will find it
    32  		if index+len(key) <= len(byts) {
    33  			if newIndex = bytes.Index(byts[index:], key); newIndex != -1 {
    34  				newIndex += index // make index based on byts
    35  				return            // entire key found return: newIndex pos, notKnown: false
    36  			}
    37  		}
    38  
    39  		// if key length is 1, key was not found
    40  		if len(key) == 1 {
    41  			return // 1-byte-key not found: newIndex -1, notKnown: false
    42  		}
    43  
    44  		// check for partial key at end of byts
    45  		firstByte := key[:1]
    46  		restOfKey := key[1:]
    47  		if index+len(restOfKey) < len(byts) {
    48  			index = len(byts) - len(restOfKey) // byts is long, search the last key-length - 1 bytes
    49  		}
    50  		for index < len(byts) {
    51  			if newIndex = bytes.Index(byts[index:], firstByte); newIndex == -1 {
    52  				return // not even partial key found return: newIndex: -1, notKnown: false
    53  			}
    54  			newIndex += index    // make index in byts
    55  			index = newIndex + 1 // next byte to search
    56  			if length := len(byts) - index; length > 0 {
    57  				if slices.Compare(byts[index:index+length], restOfKey[:length]) != 0 {
    58  					continue // restOfKey does not match, continue searching
    59  				}
    60  			}
    61  			notKnown = true
    62  			return // partial key found at end: newIndex: pos, notKnown: true
    63  		}
    64  	}
    65  	newIndex = -1
    66  	return // key not found return: newIndex: -1, notKnown: false
    67  }