1 | module Data.ByteString.Search.BoyerMoore.Internal
3 | import Data.Array.Core
5 | import Data.ByteString
7 | import Data.Linear.Ref1
9 | %hide Data.Buffer.Core.get
10 | %hide Data.Buffer.Core.set
11 | %hide Data.List.Elem.get
20 | bmPatternLimit : Bits32
21 | bmPatternLimit = 0xffffffff
30 | record BMPatternSpace where
31 | constructor MkBMPatternSpace
33 | 0 sizePositive : 0 < size
34 | 0 sizeBounded : size < Data.ByteString.Search.BoyerMoore.Internal.bmPatternLimit
41 | PatternIndex : Bits32 -> Type
42 | PatternIndex = Index
50 | bmPatternSpace : (bs : ByteString)
51 | -> {0 prf : So (not $
null bs)}
52 | -> Maybe BMPatternSpace
55 | size = cast $
length bs
56 | in case tryIndex {r = bmPatternLimit} size of
59 | Just (I size' {prf = sizePrf}) =>
60 | Just (MkBMPatternSpace size' (believe_me ()) sizePrf)
65 | patternIndexValue : {size : Bits32}
66 | -> PatternIndex size
68 | patternIndexValue (I idx) = idx
76 | toPatternIndex : (space : BMPatternSpace)
78 | -> Maybe (PatternIndex space.size)
79 | toPatternIndex space idx =
80 | tryIndex {r = space.size} (cast idx)
87 | record BMIntTable (s : Type) (size : Bits32) where
88 | constructor MkBMIntTable
95 | record BMPatternTable (s : Type) where
96 | constructor MkBMPatternTable
97 | space : BMPatternSpace
98 | table : BMIntTable s space.size
103 | newBMIntTable : {size : Bits32}
104 | -> F1 s (BMIntTable s size)
105 | newBMIntTable {size} t =
106 | let arr # t := ffi (prim__emptyArray $
cast size) t
107 | in MkBMIntTable arr # t
115 | bmGet : {size : Bits32}
116 | -> BMIntTable s size
117 | -> PatternIndex size
119 | bmGet table idx t =
121 | in believe_me (prim__arrayGet table.arr (cast pos)) # t
129 | bmSet : {size : Bits32}
130 | -> BMIntTable s size
131 | -> PatternIndex size
134 | bmSet table idx value t =
136 | in ffi (prim__arraySet table.arr (cast pos) (believe_me value)) t
144 | newBMIntTableWith : {size : Bits32}
146 | -> F1 s (BMIntTable s size)
147 | newBMIntTableWith {size} initial t =
148 | let table # t := newBMIntTable {size} t
151 | fill : {size : Bits32}
153 | -> BMIntTable s size
154 | -> F1 s (BMIntTable s size)
156 | let False := idx == size
159 | () # t := ffi (prim__arraySet table.arr (cast idx) (believe_me initial)) t
160 | in assert_total (fill (idx + 1) table t)
168 | record OccurrenceTable (s : Type) where
169 | constructor MkOccurrenceTable
175 | newOccurrenceTable : F1 s (OccurrenceTable s)
176 | newOccurrenceTable t =
177 | let arr # t := ffi (prim__emptyArray 256) t
178 | table := MkOccurrenceTable arr
182 | -> OccurrenceTable s
183 | -> F1 s (OccurrenceTable s)
185 | let False := idx == 256
188 | () # t := ffi (prim__arraySet table.arr (cast idx) (believe_me $
the Int 1)) t
189 | in assert_total (fill (S idx) table t)
197 | occurrence : OccurrenceTable s
200 | occurrence table byte t =
201 | believe_me (prim__arrayGet table.arr (cast byte)) # t
209 | setOccurrence : OccurrenceTable s
213 | setOccurrence table byte value t =
214 | ffi (prim__arraySet table.arr (cast byte) (believe_me value)) t
228 | occurrences : (bs : ByteString)
229 | -> {0 prf : So (not $
null bs)}
230 | -> F1 s (Maybe (OccurrenceTable s))
232 | let arr # t := newOccurrenceTable t
233 | in go Z (length bs) arr t
237 | -> OccurrenceTable s
238 | -> F1 s (Maybe (OccurrenceTable s))
239 | go i patend arr t =
240 | let False := S i >= patend
243 | Just byte := index i bs
246 | () # t := setOccurrence arr byte (negate $
cast {to=Int} i) t
247 | in assert_total (go (S i) patend arr t)
259 | suffixLengths : (bs : ByteString)
260 | -> {0 prf : So (not $
null bs)}
261 | -> F1 s (Maybe (BMPatternTable s))
262 | suffixLengths bs {prf} t =
263 | let Just stspace := bmPatternSpace bs {prf = prf}
266 | arr # t := newBMIntTableWith {size = stspace.size} 0 t
267 | lastidxnat := minus (length bs) 1
268 | Just lastidx := toPatternIndex stspace lastidxnat
271 | () # t := bmSet arr lastidx (cast {to=Int} $
length bs) t
272 | arr' # t := noSuffix stspace (cast {to=Int} $
minus (length bs) 2) arr t
276 | in Just (MkBMPatternTable stspace arr'') # t
280 | -> F1 s (Maybe Int)
285 | Just jbyte := index (cast {to=Nat} j) bs
288 | Just shifted := index (cast {to=Nat} (j + diff)) bs
291 | False := jbyte /= shifted
294 | in assert_total (dec diff (j - 1) t)
296 | suffixLoop : (stspace : BMPatternSpace)
300 | -> (arr : BMIntTable s stspace.size)
301 | -> F1 s (Maybe (BMIntTable s stspace.size))
302 | suffixLoop _ _ _ 0 arr t =
304 | suffixLoop stspace pre end idx arr t =
305 | let True := pre < idx
307 | noSuffix stspace idx arr t
308 | Just idxbyte := index (cast {to=Nat} idx) bs
311 | Just endbyte := index (minus (length bs) 1) bs
314 | Just idxpos := toPatternIndex stspace (cast {to=Nat} idx)
317 | False := idxbyte /= endbyte
319 | let () # t := bmSet arr idxpos 0 t
320 | in assert_total (suffixLoop stspace pre (end - 1) (idx - 1) arr t)
321 | Just endpos := toPatternIndex stspace (cast {to=Nat} end)
324 | prevs # t := bmGet arr endpos t
325 | False := (pre + prevs) < idx
327 | let () # t := bmSet arr idxpos prevs t
328 | in assert_total (suffixLoop stspace pre (end - 1) (idx - 1) arr t)
329 | pri # t := dec (cast {to=Int} (minus (length bs) (cast {to=Nat} idx))) pre t
333 | () # t := bmSet arr idxpos (idx - pri') t
334 | in assert_total (suffixLoop stspace pri' (cast {to=Int} $
minus (length bs) 2) (idx - 1) arr t)
335 | noSuffix : (stspace : BMPatternSpace)
337 | -> (arr : BMIntTable s stspace.size)
338 | -> F1 s (Maybe (BMIntTable s stspace.size))
339 | noSuffix _ 0 arr t =
341 | noSuffix stspace i arr t =
342 | let Just patati := index (cast {to=Nat} i) bs
345 | Just patatend := index (minus (length bs) 1) bs
348 | Just ipos := toPatternIndex stspace (cast {to=Nat} i)
351 | True := patati == patatend
353 | let () # t := bmSet arr ipos 0 t
354 | in assert_total (noSuffix stspace (i - 1) arr t)
355 | diff := cast {to=Int} (minus (length bs) 1) - i
357 | previ # t := dec diff nexti t
358 | Just previ' := previ
361 | False := previ' == nexti
363 | let () # t := bmSet arr ipos 1 t
364 | in assert_total (noSuffix stspace nexti arr t)
365 | () # t := bmSet arr ipos (i - previ') t
366 | in assert_total (suffixLoop stspace previ' (cast {to=Int} $
minus (length bs) 2) nexti arr t)
377 | suffixShifts : (bs : ByteString)
378 | -> {0 prf : So (not $
null bs)}
379 | -> F1 s (Maybe (BMPatternTable s))
380 | suffixShifts bs {prf} t =
381 | let suff # t := suffixLengths bs {prf = prf} t
382 | Just (MkBMPatternTable stspace suff') := suff
385 | arr # t := newBMIntTableWith {size = stspace.size} (cast {to=Int} $
length bs) t
386 | arr' # t := prefixShift stspace (cast {to=Int} $
minus (length bs) 2) 0 suff' arr t
390 | arr''' # t := suffixShift stspace 0 suff' arr'' t
391 | Just arr'''' := arr'''
394 | in Just (MkBMPatternTable stspace arr'''') # t
396 | fillToShift : (stspace : BMPatternSpace)
399 | -> (arr : BMIntTable s stspace.size)
400 | -> F1 s (Maybe (BMIntTable s stspace.size))
401 | fillToShift stspace i shift arr t =
402 | let False := i == shift
405 | Just ipos := toPatternIndex stspace (cast {to=Nat} i)
408 | () # t := bmSet arr ipos shift t
409 | in assert_total (fillToShift stspace (i + 1) shift arr t)
410 | prefixShift : (stspace : BMPatternSpace)
413 | -> (suff : BMIntTable s stspace.size)
414 | -> (arr : BMIntTable s stspace.size)
415 | -> F1 s (Maybe (BMIntTable s stspace.size))
416 | prefixShift stspace idx j suff arr t =
417 | let False := idx < 0
420 | Just idxpos := toPatternIndex stspace (cast {to=Nat} idx)
423 | idxval # t := bmGet suff idxpos t
424 | True := idxval == idx + 1
426 | assert_total (prefixShift stspace (idx - 1) j suff arr t)
427 | shift := cast {to=Int} (minus (length bs) 1) - idx
428 | arr' # t := fillToShift stspace j shift arr t
432 | in assert_total (prefixShift stspace (idx - 1) shift suff arr'' t)
433 | suffixShift : (stspace : BMPatternSpace)
435 | -> (suff : BMIntTable s stspace.size)
436 | -> (arr : BMIntTable s stspace.size)
437 | -> F1 s (Maybe (BMIntTable s stspace.size))
438 | suffixShift stspace idx suff arr t =
439 | let patend := cast {to=Int} (minus (length bs) 1)
440 | False := idx >= patend
443 | Just idxpos := toPatternIndex stspace (cast {to=Nat} idx)
446 | sufflen # t := bmGet suff idxpos t
447 | target := patend - sufflen
448 | Just targetpos := toPatternIndex stspace (cast {to=Nat} target)
451 | value := patend - idx
452 | () # t := bmSet arr targetpos value t
453 | in assert_total (suffixShift stspace (idx + 1) suff arr t)