@@ -102,38 +102,63 @@ public fun Source.indexOf(byteString: ByteString, startIndex: Long = 0): Long {
102102 }
103103
104104 var offset = startIndex
105- val peek = peek()
106- if (! request(startIndex)) {
107- return - 1L
105+ while (request(offset + byteString.size)) {
106+ val idx = buffer.indexOf(byteString, offset)
107+ if (idx < 0 ) {
108+ // The buffer does not contain the pattern, let's try fetching at least one extra byte
109+ // and start a new search attempt so that the pattern would fit in the suffix of
110+ // the current buffer + 1 extra byte.
111+ offset = buffer.size - byteString.size + 1
112+ } else {
113+ return idx
114+ }
108115 }
109- peek.skip(offset)
110- var resultingIndex = - 1L
111- UnsafeByteStringOperations .withByteArrayUnsafe(byteString) { data ->
112- while (! peek.exhausted()) {
113- val index = peek.indexOf(data[0 ])
114- if (index == - 1L ) {
115- return @withByteArrayUnsafe
116- }
117- offset + = index
118- peek.skip(index)
119- if (! peek.request(byteString.size.toLong())) {
120- return @withByteArrayUnsafe
121- }
116+ return - 1
117+ }
122118
123- var matches = true
124- for (idx in data.indices) {
125- if (data[idx] != peek.buffer[idx.toLong()] ) {
126- matches = false
127- offset ++
128- peek.skip( 1 )
129- break
130- }
131- }
132- if (matches ) {
133- resultingIndex = offset
134- return @withByteArrayUnsafe
119+ @OptIn( UnsafeByteStringApi :: class )
120+ public fun Buffer. indexOf ( byteString : ByteString , startIndex : Long = 0): Long {
121+ require(startIndex <= size ) {
122+ " startIndex ( $startIndex ) should not exceed size ( $size ) "
123+ }
124+ if (byteString.isEmpty()) return 0
125+ if (startIndex > size - byteString.size) return - 1L
126+
127+ UnsafeByteStringOperations .withByteArrayUnsafe(byteString) { byteStringData ->
128+ seek(startIndex ) { seg, o ->
129+ if (o == - 1L ) {
130+ return - 1L
135131 }
132+ var segment = seg!!
133+ var offset = o
134+ do {
135+ // If start index within this segment, the diff will be positive and
136+ // we'll scan the segment starting from the corresponding offset.
137+ // Otherwise, the diff will be negative and we'll scan the segment from the beginning.
138+ val startOffset = maxOf((startIndex - offset).toInt(), 0 )
139+ // Try to search the pattern within the current segment.
140+ val idx = segment.indexOfBytesInbound(byteStringData, startOffset)
141+ if (idx != - 1 ) {
142+ // The offset corresponds to the segment's start, idx - to offset within the segment.
143+ return offset + idx.toLong()
144+ }
145+ // firstOutboundOffset corresponds to a first byte starting reading the pattern from which
146+ // will result in running out of the current segment bounds.
147+ val firstOutboundOffset = maxOf(startOffset, segment.size - byteStringData.size + 1 )
148+ // Try to find a pattern in all suffixes shorter than the pattern. These suffixes start
149+ // in the current segment, but ends in the following segments; thus we're using outbound function.
150+ val idx1 = segment.indexOfBytesOutbound(byteStringData, firstOutboundOffset, head)
151+ if (idx1 != - 1 ) {
152+ // Offset corresponds to the segment's start, idx - to offset within the segment.
153+ return offset + idx1.toLong()
154+ }
155+
156+ // We scanned the whole segment, so let's go to the next one
157+ offset + = segment.size
158+ segment = segment.next!!
159+ } while (segment != = head && offset + byteString.size <= size)
160+ return - 1L
136161 }
137162 }
138- return resultingIndex
163+ return - 1
139164}
0 commit comments