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 }