Skip to content

Commit 4ee0048

Browse files
committed
more fully copy Netty Two-Way string matching impl
1 parent 97a4f0c commit 4ee0048

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

actor/src/main/scala/org/apache/pekko/util/ByteString.scala

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,62 @@ object ByteString {
329329
else -1
330330
}
331331

332+
// Derived from code in Netty
333+
// https://github.com/netty/netty/blob/d28a0fc6598b50fbe8f296831777cf4b653a475f/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L242-L325
334+
override def indexOfSlice(slice: Array[Byte], from: Int): Int = {
335+
val n = length - from
336+
val m = slice.length
337+
if (m == 0) return 0
338+
// When the needle has only one byte that can be read,
339+
// the indexOf() can be used
340+
if (m == 1) return indexOf(slice.head, from)
341+
var i = 0
342+
var j = 0
343+
val aStartIndex = 0
344+
val bStartIndex = from
345+
val suffixes = SWARUtil.maxSuf(slice, m, aStartIndex, true)
346+
val prefixes = SWARUtil.maxSuf(slice, m, aStartIndex, false)
347+
val ell = Math.max((suffixes >> 32).toInt, (prefixes >> 32).toInt)
348+
var per = Math.max(suffixes.toInt, prefixes.toInt)
349+
var memory = 0
350+
val checkLen = Math.min(m - per, ell + 1)
351+
if (SWARUtil.arrayBytesMatch(slice, aStartIndex, slice, aStartIndex + per, checkLen)) {
352+
memory = -1
353+
while (j <= n - m) {
354+
i = Math.max(ell, memory) + 1
355+
while (i < m && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i += 1
356+
if (i > n) return -1
357+
if (i >= m) {
358+
i = ell
359+
while (i > memory && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i -= 1
360+
if (i <= memory) return j + bStartIndex
361+
j += per
362+
memory = m - per - 1
363+
}
364+
else {
365+
j += i - ell
366+
memory = -1
367+
}
368+
}
369+
}
370+
else {
371+
per = Math.max(ell + 1, m - ell - 1) + 1
372+
while (j <= n - m) {
373+
i = ell + 1
374+
while (i < m && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i += 1
375+
if (i > n) return -1
376+
if (i >= m) {
377+
i = ell
378+
while (i >= 0 && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i -= 1
379+
if (i < 0) return j + bStartIndex
380+
j += per
381+
}
382+
else j += i - ell
383+
}
384+
}
385+
-1
386+
}
387+
332388
// Derived from code in Netty
333389
// https://github.com/netty/netty/blob/d28a0fc6598b50fbe8f296831777cf4b653a475f/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L366-L408
334390
override private[util] def bytesMatch(fromIndex: Int, checkBytes: Array[Byte], bytesFromIndex: Int,
@@ -615,6 +671,62 @@ object ByteString {
615671
else -1
616672
}
617673

674+
// Derived from code in Netty
675+
// https://github.com/netty/netty/blob/d28a0fc6598b50fbe8f296831777cf4b653a475f/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L242-L325
676+
override def indexOfSlice(slice: Array[Byte], from: Int): Int = {
677+
val n = length - from
678+
val m = slice.length
679+
if (m == 0) return 0
680+
// When the needle has only one byte that can be read,
681+
// the indexOf() can be used
682+
if (m == 1) return indexOf(slice.head, from)
683+
var i = 0
684+
var j = 0
685+
val aStartIndex = 0
686+
val bStartIndex = from + startIndex
687+
val suffixes = SWARUtil.maxSuf(slice, m, aStartIndex, true)
688+
val prefixes = SWARUtil.maxSuf(slice, m, aStartIndex, false)
689+
val ell = Math.max((suffixes >> 32).toInt, (prefixes >> 32).toInt)
690+
var per = Math.max(suffixes.toInt, prefixes.toInt)
691+
var memory = 0
692+
val checkLen = Math.min(m - per, ell + 1)
693+
if (SWARUtil.arrayBytesMatch(slice, aStartIndex, slice, aStartIndex + per, checkLen)) {
694+
memory = -1
695+
while (j <= n - m) {
696+
i = Math.max(ell, memory) + 1
697+
while (i < m && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i += 1
698+
if (i > n) return -1
699+
if (i >= m) {
700+
i = ell
701+
while (i > memory && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i -= 1
702+
if (i <= memory) return j + bStartIndex - startIndex
703+
j += per
704+
memory = m - per - 1
705+
}
706+
else {
707+
j += i - ell
708+
memory = -1
709+
}
710+
}
711+
}
712+
else {
713+
per = Math.max(ell + 1, m - ell - 1) + 1
714+
while (j <= n - m) {
715+
i = ell + 1
716+
while (i < m && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i += 1
717+
if (i > n) return -1
718+
if (i >= m) {
719+
i = ell
720+
while (i >= 0 && (slice(i + aStartIndex) == bytes(i + j + bStartIndex))) i -= 1
721+
if (i < 0) return j + bStartIndex - startIndex
722+
j += per
723+
}
724+
else j += i - ell
725+
}
726+
}
727+
-1
728+
}
729+
618730
// Derived from code in Netty
619731
// https://github.com/netty/netty/blob/d28a0fc6598b50fbe8f296831777cf4b653a475f/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L366-L408
620732
override private[util] def bytesMatch(fromIndex: Int,

actor/src/main/scala/org/apache/pekko/util/SWARUtil.scala

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,66 @@ private[util] object SWARUtil {
9393
(array(index + 7).toLong & 0xFF)
9494
}
9595
}
96+
97+
// Derived from code in Netty
98+
// https://github.com/netty/netty/blob/d28a0fc6598b50fbe8f296831777cf4b653a475f/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L366-L408
99+
def arrayBytesMatch(arrayBytes: Array[Byte],
100+
fromIndex: Int,
101+
checkBytes: Array[Byte],
102+
bytesFromIndex: Int,
103+
checkLength: Int): Boolean = {
104+
var aIndex = fromIndex
105+
var bIndex = bytesFromIndex
106+
val longCount = checkLength >>> 3
107+
val byteCount = checkLength & 7
108+
var i = 0
109+
while (i < longCount) {
110+
if (SWARUtil.getLong(arrayBytes, aIndex) != SWARUtil.getLong(checkBytes, bIndex)) return false
111+
aIndex += 8
112+
bIndex += 8
113+
i += 1
114+
}
115+
i = 0
116+
while (i < byteCount) {
117+
if (arrayBytes(aIndex) != checkBytes(bIndex)) return false
118+
aIndex += 1
119+
bIndex += 1
120+
i += 1
121+
}
122+
true
123+
}
124+
125+
// Derived from code in Netty
126+
// https://github.com/netty/netty/blob/a5343227b10456ec889a3fdc5fa4246f036a216d/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java#L327-L356
127+
def maxSuf(arrayBytes: Array[Byte], m: Int, start: Int, isSuffix: Boolean): Long = {
128+
var p = 1
129+
var ms = -1
130+
var j = start
131+
var k = 1
132+
var a = 0
133+
var b = 0
134+
while (j + k < m) {
135+
a = arrayBytes(j + k)
136+
b = arrayBytes(ms + k)
137+
val suffix = if (isSuffix) a < b
138+
else a > b
139+
if (suffix) {
140+
j += k
141+
k = 1
142+
p = j - ms
143+
}
144+
else if (a == b) if (k != p) k += 1
145+
else {
146+
j += p
147+
k = 1
148+
}
149+
else {
150+
ms = j
151+
j = ms + 1
152+
k = 1
153+
p = 1
154+
}
155+
}
156+
(ms.toLong << 32) + p
157+
}
96158
}

0 commit comments

Comments
 (0)