1 | module Data.ByteString.Search.KnuthMorrisPratt
3 | import Data.ByteString.Search.Internal.Utils
5 | import Data.Array.Core
6 | import Data.Array.Mutable
8 | import Data.ByteString
9 | import Data.Linear.Ref1
12 | %hide Data.Buffer.Core.get
13 | %hide Data.Buffer.Core.set
24 | -> F1 s (Maybe (List Nat))
25 | matcher overlap pat chunks t =
26 | let bords # t := kmpBorders pat t
27 | Just bords' := bords
30 | searcher' # t := searcher Z Z pat chunks Lin bords' overlap t
31 | Just searcher'' := searcher'
34 | in Just (searcher'' <>> []) # t
37 | findMatch : (prior : Nat)
40 | -> (pat : ByteString)
41 | -> (strs : List ByteString)
42 | -> (final : SnocList Nat)
43 | -> (bords : MArray s (S (length pat)) Nat)
45 | -> F1 s (Maybe (SnocList Nat))
46 | findMatch _ _ _ _ [] final _ _ t =
48 | findMatch prior pati stri pat strs@(str::rest) final bords overlap t =
49 | let patlen := length pat
50 | False := pati == patlen
54 | let final' := minus (plus prior stri) patlen
55 | final'' := final :< final'
56 | in assert_total (checkHead prior stri pat strs final'' bords overlap t)
57 | Just patlen' := tryNatToFin patlen
60 | final' := minus (plus prior stri) patlen
61 | ami # t := get bords patlen' t
64 | let final'' := final :< final'
65 | in assert_total (checkHead prior stri pat strs final'' bords overlap t)
66 | final'' := final :< final'
67 | in assert_total (findMatch prior ami stri pat strs final'' bords overlap t)
68 | strlen := length str
69 | False := stri == strlen
71 | assert_total (searcher (plus prior strlen) pati pat rest final bords overlap t)
72 | pati' := index pati pat
73 | Just pati'' := pati'
76 | stri' := index stri str
77 | Just stri'' := stri'
80 | False := stri'' == pati''
82 | assert_total (findMatch prior (S pati) (S stri) pat strs final bords overlap t)
83 | Just pati''' := tryNatToFin pati
86 | pati'''' # t := get bords pati''' t
87 | False := pati'''' == Z
89 | assert_total (checkHead prior (S stri) pat strs final bords overlap t)
90 | in assert_total (findMatch prior pati'''' stri pat strs final bords overlap t)
91 | checkHead : (prior : Nat)
93 | -> (pat : ByteString)
94 | -> (strs : List ByteString)
95 | -> (final : SnocList Nat)
96 | -> (bords : MArray s (S (length pat)) Nat)
98 | -> F1 s (Maybe (SnocList Nat))
99 | checkHead _ _ _ [] final _ _ t =
101 | checkHead prior stri pat strs@(str::rest) final bords overlap t =
102 | let strlen := length str
103 | False := stri == strlen
105 | assert_total (searcher (plus prior strlen) Z pat rest final bords overlap t)
106 | stri' := index stri str
107 | Just stri'' := stri'
110 | patzero := index Z pat
111 | Just patzero' := patzero
114 | False := stri'' == patzero'
116 | assert_total (findMatch prior (S Z) (S stri) pat strs final bords overlap t)
117 | in assert_total (checkHead prior (S stri) pat strs final bords overlap t)
118 | searcher : (prior : Nat)
120 | -> (pat : ByteString)
121 | -> (strs : List ByteString)
122 | -> (final : SnocList Nat)
123 | -> (bords : MArray s (S (length pat)) Nat)
124 | -> (overlap : Bool)
125 | -> F1 s (Maybe (SnocList Nat))
126 | searcher _ _ _ [] final _ _ t =
128 | searcher prior Z pat strs final bords overlap t =
129 | assert_total (checkHead prior Z pat strs final bords overlap t)
130 | searcher prior patpos pat strs final bords overlap t =
131 | assert_total (findMatch prior patpos Z pat strs final bords overlap t)
159 | matchKMP : (pat : ByteString)
160 | -> (target : ByteString)
161 | -> {0 prfpat : So (not $
null pat)}
162 | -> {0 prftarget : So (not $
null target)}
163 | -> F1 s (Maybe (List Nat))
164 | matchKMP pat target {prfpat} {prftarget} t =
165 | let matcher' # t := matcher False pat [target] t
166 | Just matcher'' := matcher'
169 | in Just matcher'' #t
194 | indicesKMP : (pat : ByteString)
195 | -> (target : ByteString)
196 | -> {0 prfpat : So (not $
null pat)}
197 | -> {0 prftarget : So (not $
null target)}
198 | -> F1 s (Maybe (List Nat))
199 | indicesKMP pat target {prfpat} {prftarget} t =
200 | let matcher' # t := matcher True pat [target] t
201 | Just matcher'' := matcher'
204 | in Just matcher'' # t
218 | breakKMP : (pat : ByteString)
219 | -> (target : ByteString)
220 | -> {0 prfpat : So (not $
null pat)}
221 | -> {0 prftarget : So (not $
null target)}
222 | -> {0 prflength : So ((length target) >= (length pat))}
223 | -> F1 s (Maybe (ByteString, ByteString))
224 | breakKMP pat target {prfpat} {prftarget} {prflength} t =
225 | let matcher' # t := matcher False pat [target] t
226 | Just matcher'' := matcher'
229 | (i :: _) := matcher''
231 | Just (target, empty) # t
232 | target' := splitAt (cast {to=Nat} i) target
233 | Just target'' := target'
236 | in Just target'' # t
251 | breakAfterKMP : (pat : ByteString)
252 | -> (target : ByteString)
253 | -> {0 prfpat : So (not $
null pat)}
254 | -> {0 prftarget : So (not $
null target)}
255 | -> {0 prflength : So ((length target) >= (length pat))}
256 | -> F1 s (Maybe (ByteString, ByteString))
257 | breakAfterKMP pat target {prfpat} {prftarget} {prflength} t =
258 | let matcher' # t := matcher False pat [target] t
259 | Just matcher'' := matcher'
262 | (i :: _) := matcher''
264 | Just (target, empty) # t
265 | target' := splitAt (plus (cast {to=Nat} i) (length pat)) target
266 | Just target'' := target'
269 | in Just target'' # t
286 | splitKeepFrontKMP : (pat : ByteString)
287 | -> (target : ByteString)
288 | -> {0 prfpat : So (not $
null pat)}
289 | -> {0 prftarget : So (not $
null target)}
290 | -> {0 prflength : So ((length target) >= (length pat))}
291 | -> F1 s (Maybe (List ByteString))
292 | splitKeepFrontKMP pat target {prfpat} {prftarget} {prflength} t =
293 | let splitter' # t := splitter pat target Lin t
294 | Just splitter'' := splitter'
297 | in Just (splitter'' <>> []) # t
299 | psSplitter : (pat : ByteString)
300 | -> (target : ByteString)
301 | -> (final : SnocList ByteString)
302 | -> F1 s (Maybe (SnocList ByteString))
303 | psSplitter pat target final t =
304 | let matcher' # t := matcher False pat [(drop (length pat) target)] t
305 | Just matcher'' := matcher'
308 | (i :: _) := matcher''
310 | let final' := final :< target
312 | length' := plus (cast {to=Nat} i) (length pat)
313 | final' := final :< (take length' target)
314 | in assert_total (psSplitter pat (drop length' target) final' t)
315 | splitter : (pat : ByteString)
316 | -> (target : ByteString)
317 | -> (final : SnocList ByteString)
318 | -> F1 s (Maybe (SnocList ByteString))
319 | splitter pat target final t =
320 | let matcher' # t := matcher False pat [target] t
321 | Just matcher'' := matcher'
324 | (i :: _) := matcher''
326 | let final' := final :< target
330 | assert_total (psSplitter pat target final t)
331 | final' := final :< (take (cast {to=Nat} i) target)
332 | in assert_total (psSplitter pat (drop (cast {to=Nat} i) target) final' t)
355 | splitKeepEndKMP : (pat : ByteString)
356 | -> (target : ByteString)
357 | -> {0 prfpat : So (not $
null pat)}
358 | -> {0 prftarget : So (not $
null target)}
359 | -> {0 prflength : So ((length target) >= (length pat))}
360 | -> F1 s (Maybe (List ByteString))
361 | splitKeepEndKMP pat target {prfpat} {prftarget} {prflength} t =
362 | let splitter' # t := splitter pat target Lin t
363 | Just splitter'' := splitter'
366 | in Just (splitter'' <>> []) # t
368 | splitter : (pat : ByteString)
369 | -> (target : ByteString)
370 | -> (final : SnocList ByteString)
371 | -> F1 s (Maybe (SnocList ByteString))
372 | splitter pat target final t =
373 | let matcher' # t := matcher False pat [target] t
374 | Just matcher'' := matcher'
377 | (i :: _) := matcher''
379 | let final' := final :< target
381 | length' := plus (cast {to=Nat} i) (length pat)
382 | final' := final :< (take length' target)
383 | in assert_total (splitter pat (drop length' target) final' t)
408 | splitDropKMP : (pat : ByteString)
409 | -> (target : ByteString)
410 | -> {0 prfpat : So (not $
null pat)}
411 | -> {0 prftarget : So (not $
null target)}
412 | -> {0 prflength : So ((length target) >= (length pat))}
413 | -> F1 s (Maybe (List ByteString))
414 | splitDropKMP pat target {prfpat} {prftarget} {prflength} t =
415 | let splitter' # t := splitter pat target Lin t
416 | Just splitter'' := splitter'
419 | in Just (splitter'' <>> []) # t
421 | splitter : (pat : ByteString)
422 | -> (target : ByteString)
423 | -> (final : SnocList ByteString)
424 | -> F1 s (Maybe (SnocList ByteString))
425 | splitter pat target final t =
426 | let matcher' # t := matcher False pat [target] t
427 | Just matcher'' := matcher'
430 | (i :: _) := matcher''
432 | let final' := final :< target
434 | length' := plus (cast {to=Nat} i) (length pat)
435 | final' := final :< (take (cast {to=Nat} i) target)
436 | in assert_total (splitter pat (drop length' target) final' t)
459 | replaceKMP : (pat : ByteString)
460 | -> (sub : ByteString)
461 | -> (target : ByteString)
462 | -> {0 prfpat : So (not $
null pat)}
463 | -> {0 prftarget : So (not $
null target)}
464 | -> {0 prflength : So ((length target) >= (length pat))}
465 | -> F1 s (Maybe (List ByteString))
466 | replaceKMP pat sub target {prfpat} {prftarget} {prflength} t =
467 | let replacer' # t := replacer pat sub target Lin t
468 | Just replacer'' := replacer'
471 | in Just (replacer'' <>> []) # t
473 | replacer : (pat : ByteString)
474 | -> (sub : ByteString)
475 | -> (target : ByteString)
476 | -> (final : SnocList ByteString)
477 | -> F1 s (Maybe (SnocList ByteString))
478 | replacer pat sub target final t =
479 | let matcher' # t := matcher False pat [target] t
480 | Just matcher'' := matcher'
483 | (i :: _) := matcher''
485 | let final' := final :< target
489 | let False := null sub
491 | let length' := plus (cast {to=Nat} i) (length pat)
492 | final' := final :< (take (cast {to=Nat} i) target)
493 | in assert_total (replacer pat sub (drop length' target) final' t)
494 | length' := plus (cast {to=Nat} i) (length pat)
495 | final' := final :< (take (cast {to=Nat} i) target) :< sub
496 | in assert_total (replacer pat sub (drop length' target) final' t)
499 | assert_total (replacer pat sub (drop (length pat) target) final t)
500 | final' := final :< sub
501 | in assert_total (replacer pat sub (drop (length pat) target) final') t