Skip to content

Commit 7035f83

Browse files
committed
improved KMP
1 parent b34b444 commit 7035f83

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

src/Suave/Utils/Bytes.fs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,51 @@ module internal Bytes =
4242
let inline initNext p =
4343
let m = Array.length p
4444
let next = Array.create m 0
45-
let i = ref 1
46-
let j = ref 0
47-
while !i < m - 1 do
48-
if p.[!i] = p.[!j] then begin incr i; incr j; next.[!i] <- !j end else
49-
if !j = 0 then begin incr i; next.[!i] <- 0 end else j := next.[!j]
45+
let mutable i = 1
46+
let mutable j = 0
47+
while i < m - 1 do
48+
if p.[i] = p.[j] then
49+
i <- i + 1
50+
j <- j + 1
51+
next.[i] <- j
52+
else
53+
if j = 0 then
54+
i <- i + 1
55+
next.[i] <- 0
56+
else
57+
j <- next.[j]
5058
next
5159

5260
let inline _kmpW (p: byte []) (next: int []) m (xs : ReadOnlySequence<byte>) =
53-
let n = xs.Length
5461
let mutable i = 0L
55-
let mutable j = 0L
56-
let a (x) =
57-
xs.Slice(xs.GetPosition(x)).First.Span[0]
58-
while j < m && i < n do
59-
if a(i) = p.[int j] then
62+
let mutable j = 0
63+
let mutable found = false
64+
let mutable result = ValueNone
65+
// Iterate through segments
66+
let mutable enumerator = xs.GetEnumerator()
67+
while not found && enumerator.MoveNext() do
68+
let span = enumerator.Current.Span
69+
let mutable byteIdx = 0
70+
while not found && byteIdx < span.Length do
71+
// Current byte in the sequence
72+
let b = span.[byteIdx]
73+
74+
// KMP failure function: back up j until we have a match or j is 0
75+
while j > 0 && b <> p.[j] do
76+
j <- next.[j]
77+
78+
// Check if current byte matches pattern[j]
79+
if b = p.[j] then j <- j + 1
80+
81+
// Found complete match - exit early
82+
if j = m then
83+
result <- ValueSome(i - int64(m - 1))
84+
found <- true
85+
6086
i <- i + 1L
61-
j <- j + 1L
62-
else
63-
if j = 0 then
64-
i <- i + 1L
65-
else
66-
j <- next.[int j]
67-
done;
68-
if j >= m then ValueSome(i - m) else ValueNone
87+
byteIdx <- byteIdx + 1
88+
89+
result
6990

7091
let inline kmpW p (xs : ReadOnlySequence<byte>) =
7192
let next = initNext p

0 commit comments

Comments
 (0)