1 | module Data.ByteString.Search.KnuthMorrisPratt
3 | import Data.Array.Core
4 | import Data.Array.Mutable
6 | import Data.ByteString
7 | import Data.ByteString.Search.DFA.Types
8 | import Data.ByteString.Search.KnuthMorrisPratt.Internal
10 | import Data.Linear.Ref1
13 | %hide Data.Buffer.Core.get
14 | %hide Data.Buffer.Core.set
37 | -> F1 s (Maybe (List Nat))
38 | matcher overlap pat chunks t =
39 | let patlen := length pat
40 | Just patzero := index Z pat
43 | bords # t := kmpBorders pat t
44 | Just (MkKMPBorders stspace bords') := bords
50 | Just fullstate := tryIndex {r = stspace.states} (cast patlen)
57 | Just stateone := tryIndex {r = stspace.states} 1
60 | fullbord # t := kmpBorder bords' fullstate t
61 | result # t := searcher stspace Z (zeroDFAState stspace) chunks Lin patlen patzero stateone fullbord bords' t
62 | Just result' := result
65 | in Just (result' <>> []) # t
74 | searcher : (stspace : DFAStateSpace)
76 | -> (patpos : DFAState stspace.states)
77 | -> (strs : List ByteString)
78 | -> (final : SnocList Nat)
80 | -> (patzero : Bits8)
81 | -> (stateone : DFAState stspace.states)
82 | -> (fullbord : DFAState stspace.states)
83 | -> (bords : KMPBorderTable s stspace.states)
84 | -> F1 s (Maybe (SnocList Nat))
85 | searcher stspace _ _ [] final _ _ _ _ _ t =
87 | searcher stspace prior patpos (str :: rest) final patlen patzero stateone fullbord bords t =
88 | let strlen := length str
89 | False := dfaStateValue patpos == 0
91 | assert_total (checkHead stspace prior Z str strlen rest final patlen patzero stateone fullbord bords t)
92 | in assert_total (findMatch stspace prior patpos Z str strlen rest final patlen patzero stateone fullbord bords t)
99 | checkHead : (stspace : DFAStateSpace)
102 | -> (str : ByteString)
104 | -> (rest : List ByteString)
105 | -> (final : SnocList Nat)
107 | -> (patzero : Bits8)
108 | -> (stateone : DFAState stspace.states)
109 | -> (fullbord : DFAState stspace.states)
110 | -> (bords : KMPBorderTable s stspace.states)
111 | -> F1 s (Maybe (SnocList Nat))
112 | checkHead stspace prior stri str strlen rest final patlen patzero stateone fullbord bords t =
113 | let False := stri == strlen
115 | assert_total (searcher stspace (plus prior strlen) (zeroDFAState stspace) rest final patlen patzero stateone fullbord bords t)
116 | Just strbyte := index stri str
120 | False := strbyte == patzero
122 | assert_total (findMatch stspace prior stateone nxtstri str strlen rest final patlen patzero stateone fullbord bords t)
123 | in assert_total (checkHead stspace prior nxtstri str strlen rest final patlen patzero stateone fullbord bords t)
133 | findMatch : (stspace : DFAStateSpace)
135 | -> (pati : DFAState stspace.states)
137 | -> (str : ByteString)
139 | -> (rest : List ByteString)
140 | -> (final : SnocList Nat)
142 | -> (patzero : Bits8)
143 | -> (stateone : DFAState stspace.states)
144 | -> (fullbord : DFAState stspace.states)
145 | -> (bords : KMPBorderTable s stspace.states)
146 | -> F1 s (Maybe (SnocList Nat))
147 | findMatch stspace prior pati stri str strlen rest final patlen patzero stateone fullbord bords t =
148 | let patival := dfaStateValue pati
149 | False := patival == cast {to=Bits32} patlen
151 | let matchidx := minus (plus prior stri) patlen
152 | final' := final :< matchidx
155 | let False := dfaStateValue fullbord == 0
157 | assert_total (checkHead stspace prior stri str strlen rest final' patlen patzero stateone fullbord bords t)
158 | in assert_total (findMatch stspace prior fullbord stri str strlen rest final' patlen patzero stateone fullbord bords t)
159 | in assert_total (checkHead stspace prior stri str strlen rest final' patlen patzero stateone fullbord bords t)
160 | False := stri == strlen
162 | assert_total (searcher stspace (plus prior strlen) pati rest final patlen patzero stateone fullbord bords t)
163 | Just strbyte := index stri str
166 | in assert_total (compareAt stspace prior pati stri strbyte str strlen rest final patlen patzero stateone fullbord bords t)
179 | compareAt : (stspace : DFAStateSpace)
181 | -> (pati : DFAState stspace.states)
183 | -> (strbyte : Bits8)
184 | -> (str : ByteString)
186 | -> (rest : List ByteString)
187 | -> (final : SnocList Nat)
189 | -> (patzero : Bits8)
190 | -> (stateone : DFAState stspace.states)
191 | -> (fullbord : DFAState stspace.states)
192 | -> (bords : KMPBorderTable s stspace.states)
193 | -> F1 s (Maybe (SnocList Nat))
194 | compareAt stspace prior pati stri strbyte str strlen rest final patlen patzero stateone fullbord bords t =
195 | let patidx := cast {to=Nat} (dfaStateValue pati)
196 | Just patbyte := index patidx pat
199 | False := strbyte == patbyte
201 | let nextval : Bits32
202 | nextval := dfaStateValue pati + 1
206 | nextstate : DFAState stspace.states
207 | nextstate = I nextval {prf = believe_me ()}
208 | in assert_total (findMatch stspace prior nextstate (S stri) str strlen rest final patlen patzero stateone fullbord bords t)
209 | fallback # t := kmpBorder bords pati t
210 | False := dfaStateValue fallback == 0
212 | assert_total (checkHead stspace prior (S stri) str strlen rest final patlen patzero stateone fullbord bords t)
213 | in assert_total (compareAt stspace prior fallback stri strbyte str strlen rest final patlen patzero stateone fullbord bords t)
241 | matchKMP : (pat : ByteString)
242 | -> (target : ByteString)
243 | -> {0 prfpat : So (not $
null pat)}
244 | -> {0 prftarget : So (not $
null target)}
245 | -> F1 s (Maybe (List Nat))
246 | matchKMP pat target {prfpat} {prftarget} t =
247 | let matcher' # t := matcher False pat [target] t
248 | Just matcher'' := matcher'
251 | in Just matcher'' #t
276 | indicesKMP : (pat : ByteString)
277 | -> (target : ByteString)
278 | -> {0 prfpat : So (not $
null pat)}
279 | -> {0 prftarget : So (not $
null target)}
280 | -> F1 s (Maybe (List Nat))
281 | indicesKMP pat target {prfpat} {prftarget} t =
282 | let matcher' # t := matcher True pat [target] t
283 | Just matcher'' := matcher'
286 | in Just matcher'' # t
300 | breakKMP : (pat : ByteString)
301 | -> (target : ByteString)
302 | -> {0 prfpat : So (not $
null pat)}
303 | -> {0 prftarget : So (not $
null target)}
304 | -> {0 prflength : So ((length target) >= (length pat))}
305 | -> F1 s (Maybe (ByteString, ByteString))
306 | breakKMP pat target {prfpat} {prftarget} {prflength} t =
307 | let matcher' # t := matcher False pat [target] t
308 | Just matcher'' := matcher'
311 | (i :: _) := matcher''
313 | Just (target, empty) # t
314 | target' := splitAt (cast {to=Nat} i) target
315 | Just target'' := target'
318 | in Just target'' # t
333 | breakAfterKMP : (pat : ByteString)
334 | -> (target : ByteString)
335 | -> {0 prfpat : So (not $
null pat)}
336 | -> {0 prftarget : So (not $
null target)}
337 | -> {0 prflength : So ((length target) >= (length pat))}
338 | -> F1 s (Maybe (ByteString, ByteString))
339 | breakAfterKMP pat target {prfpat} {prftarget} {prflength} t =
340 | let matcher' # t := matcher False pat [target] t
341 | Just matcher'' := matcher'
344 | (i :: _) := matcher''
346 | Just (target, empty) # t
347 | target' := splitAt (plus (cast {to=Nat} i) (length pat)) target
348 | Just target'' := target'
351 | in Just target'' # t
368 | splitKeepFrontKMP : (pat : ByteString)
369 | -> (target : ByteString)
370 | -> {0 prfpat : So (not $
null pat)}
371 | -> {0 prftarget : So (not $
null target)}
372 | -> {0 prflength : So ((length target) >= (length pat))}
373 | -> F1 s (Maybe (List ByteString))
374 | splitKeepFrontKMP pat target {prfpat} {prftarget} {prflength} t =
375 | let splitter' # t := splitter pat target Lin t
376 | Just splitter'' := splitter'
379 | in Just (splitter'' <>> []) # t
381 | psSplitter : (pat : ByteString)
382 | -> (target : ByteString)
383 | -> (final : SnocList ByteString)
384 | -> F1 s (Maybe (SnocList ByteString))
385 | psSplitter pat target final t =
386 | let matcher' # t := matcher False pat [(drop (length pat) target)] t
387 | Just matcher'' := matcher'
390 | (i :: _) := matcher''
392 | let final' := final :< target
394 | length' := plus (cast {to=Nat} i) (length pat)
395 | final' := final :< (take length' target)
396 | in assert_total (psSplitter pat (drop length' target) final' t)
397 | splitter : (pat : ByteString)
398 | -> (target : ByteString)
399 | -> (final : SnocList ByteString)
400 | -> F1 s (Maybe (SnocList ByteString))
401 | splitter pat target final t =
402 | let matcher' # t := matcher False pat [target] t
403 | Just matcher'' := matcher'
406 | (i :: _) := matcher''
408 | let final' := final :< target
412 | assert_total (psSplitter pat target final t)
413 | final' := final :< (take (cast {to=Nat} i) target)
414 | in assert_total (psSplitter pat (drop (cast {to=Nat} i) target) final' t)
437 | splitKeepEndKMP : (pat : ByteString)
438 | -> (target : ByteString)
439 | -> {0 prfpat : So (not $
null pat)}
440 | -> {0 prftarget : So (not $
null target)}
441 | -> {0 prflength : So ((length target) >= (length pat))}
442 | -> F1 s (Maybe (List ByteString))
443 | splitKeepEndKMP pat target {prfpat} {prftarget} {prflength} t =
444 | let splitter' # t := splitter pat target Lin t
445 | Just splitter'' := splitter'
448 | in Just (splitter'' <>> []) # t
450 | splitter : (pat : ByteString)
451 | -> (target : ByteString)
452 | -> (final : SnocList ByteString)
453 | -> F1 s (Maybe (SnocList ByteString))
454 | splitter pat target final t =
455 | let matcher' # t := matcher False pat [target] t
456 | Just matcher'' := matcher'
459 | (i :: _) := matcher''
461 | let final' := final :< target
463 | length' := plus (cast {to=Nat} i) (length pat)
464 | final' := final :< (take length' target)
465 | in assert_total (splitter pat (drop length' target) final' t)
490 | splitDropKMP : (pat : ByteString)
491 | -> (target : ByteString)
492 | -> {0 prfpat : So (not $
null pat)}
493 | -> {0 prftarget : So (not $
null target)}
494 | -> {0 prflength : So ((length target) >= (length pat))}
495 | -> F1 s (Maybe (List ByteString))
496 | splitDropKMP pat target {prfpat} {prftarget} {prflength} t =
497 | let splitter' # t := splitter pat target Lin t
498 | Just splitter'' := splitter'
501 | in Just (splitter'' <>> []) # t
503 | splitter : (pat : ByteString)
504 | -> (target : ByteString)
505 | -> (final : SnocList ByteString)
506 | -> F1 s (Maybe (SnocList ByteString))
507 | splitter pat target final t =
508 | let matcher' # t := matcher False pat [target] t
509 | Just matcher'' := matcher'
512 | (i :: _) := matcher''
514 | let final' := final :< target
516 | length' := plus (cast {to=Nat} i) (length pat)
517 | final' := final :< (take (cast {to=Nat} i) target)
518 | in assert_total (splitter pat (drop length' target) final' t)
541 | replaceKMP : (pat : ByteString)
542 | -> (sub : ByteString)
543 | -> (target : ByteString)
544 | -> {0 prfpat : So (not $
null pat)}
545 | -> {0 prftarget : So (not $
null target)}
546 | -> {0 prflength : So ((length target) >= (length pat))}
547 | -> F1 s (Maybe (List ByteString))
548 | replaceKMP pat sub target {prfpat} {prftarget} {prflength} t =
549 | let replacer' # t := replacer pat sub target Lin t
550 | Just replacer'' := replacer'
553 | in Just (replacer'' <>> []) # t
555 | replacer : (pat : ByteString)
556 | -> (sub : ByteString)
557 | -> (target : ByteString)
558 | -> (final : SnocList ByteString)
559 | -> F1 s (Maybe (SnocList ByteString))
560 | replacer pat sub target final t =
561 | let matcher' # t := matcher False pat [target] t
562 | Just matcher'' := matcher'
565 | (i :: _) := matcher''
567 | let final' := final :< target
571 | let False := null sub
573 | let length' := plus (cast {to=Nat} i) (length pat)
574 | final' := final :< (take (cast {to=Nat} i) target)
575 | in assert_total (replacer pat sub (drop length' target) final' t)
576 | length' := plus (cast {to=Nat} i) (length pat)
577 | final' := final :< (take (cast {to=Nat} i) target) :< sub
578 | in assert_total (replacer pat sub (drop length' target) final' t)
581 | assert_total (replacer pat sub (drop (length pat) target) final t)
582 | final' := final :< sub
583 | in assert_total (replacer pat sub (drop (length pat) target) final') t