0 | module Data.Buffer.Indexed
  1 |
  2 | import public Data.Array.Index
  3 | import public Data.Array.Indexed
  4 | import Data.Buffer
  5 | import Data.Buffer.Mutable
  6 | import Data.List
  7 | import Data.Vect
  8 | import Syntax.PreorderReasoning
  9 |
 10 | %default total
 11 |
 12 | --------------------------------------------------------------------------------
 13 | --          Accessing Data
 14 | --------------------------------------------------------------------------------
 15 |
 16 | ||| Safely access a value in an immutable byte array at position `n - m`.
 17 | export %inline
 18 | ix : IBuffer n -> (0 m : Nat) -> {auto x: Ix (S m) n} -> Bits8
 19 | ix arr _ = at arr (ixToFin x)
 20 |
 21 | ||| Safely access a value in an immutable byte array at the given position.
 22 | export %inline
 23 | atNat : IBuffer n -> (m : Nat) -> {auto 0 lt : LT m n} -> Bits8
 24 | atNat arr x = at arr (natToFinLT x)
 25 |
 26 | ||| Safely access a value at the given byte position.
 27 | export %inline
 28 | atByte : IBuffer 256 -> Bits8 -> Bits8
 29 | atByte arr x = at arr (bits8ToFin x)
 30 |
 31 | --------------------------------------------------------------------------------
 32 | --          Initializing Byte Arrays
 33 | --------------------------------------------------------------------------------
 34 |
 35 | ||| The empty byte array.
 36 | export
 37 | empty : IBuffer 0
 38 | empty = alloc 0 unsafeFreeze
 39 |
 40 | ||| Copy the values in a list to an immutable byte array of the same length.
 41 | export %inline
 42 | bufferL : (ls : List Bits8) -> IBuffer (length ls)
 43 | bufferL xs =
 44 |   alloc (length xs) $ \r,t =>
 45 |     let _ # t := writeList {xs} r xs t
 46 |      in unsafeFreeze r t
 47 |
 48 | ||| Copy the values in a vector to an immutable byte array of the same length.
 49 | export %inline
 50 | buffer : {n : _} -> Vect n Bits8 -> IBuffer n
 51 | buffer xs =
 52 |   alloc n $ \r,t =>
 53 |     let _ # t := writeVect r xs t
 54 |      in unsafeFreeze r t
 55 |
 56 | ||| Copy the values in a vector to an immutable byte array of the same length
 57 | ||| in reverse order.
 58 | |||
 59 | ||| This is useful the values in the byte array have been collected
 60 | ||| from tail to head for instance when parsing some data.
 61 | export %inline
 62 | revBuffer : {n : _} -> Vect n Bits8 -> IBuffer n
 63 | revBuffer xs =
 64 |   alloc n $ \r,t =>
 65 |     let _ # t := writeVectRev r n xs t
 66 |      in unsafeFreeze r t
 67 |
 68 | ||| Generate an immutable byte array of the given size using
 69 | ||| the given iteration function.
 70 | export %inline
 71 | generate : (n : Nat) -> (Fin n -> Bits8) -> IBuffer n
 72 | generate n f =
 73 |   alloc n $ \r,t =>
 74 |     let _ # t := genFrom r n f t
 75 |      in unsafeFreeze r t
 76 |
 77 | ||| Fill an immutable byte array of the given size with the given value.
 78 | export %inline
 79 | fill : (n : Nat) -> Bits8 -> IBuffer n
 80 | fill n = generate n . const
 81 |
 82 | ||| Generate an immutable byte array of the given size by filling it with the
 83 | ||| results of repeatedly applying `f` to the initial value.
 84 | export %inline
 85 | iterate : (n : Nat) -> (f : Bits8 -> Bits8) -> Bits8 -> IBuffer n
 86 | iterate n f v =
 87 |   alloc n $ \r,t =>
 88 |     let _ # t := iterateFrom r n f v t
 89 |      in unsafeFreeze r t
 90 |
 91 | ||| Copy the content of an immutable byte array to a new immutable byte array.
 92 | |||
 93 | ||| This is mainly useful for reducing memory consumption, in case the
 94 | ||| original array is actually backed by a much larger array, for
 95 | ||| instance after taking a smaller prefix of a large array with `take`.
 96 | export
 97 | force : {n : _} -> IBuffer n -> IBuffer n
 98 | force buf = run1 $ \t => let r # t := thaw buf t in unsafeFreeze r t
 99 |
100 | --------------------------------------------------------------------------------
101 | --          Eq and Ord
102 | --------------------------------------------------------------------------------
103 |
104 | ||| Lexicographic comparison of immutable byte arrays of distinct length.
105 | export
106 | hcomp : {m,n : Nat} -> IBuffer m -> IBuffer n -> Ordering
107 | hcomp a1 a2 = go m n
108 |
109 |   where
110 |     go : (k,l : Nat) -> {auto _ : Ix k m} -> {auto _ : Ix l n} -> Ordering
111 |     go 0     0     = EQ
112 |     go 0     (S _) = LT
113 |     go (S _) 0     = GT
114 |     go (S k) (S j) = case compare (ix a1 k) (ix a2 j) of
115 |       EQ => go k j
116 |       r  => r
117 |
118 | ||| Heterogeneous equality for immutable byte arrays.
119 | export
120 | heq : {m,n : Nat} -> IBuffer m -> IBuffer n -> Bool
121 | heq a1 a2 = go m n
122 |
123 |   where
124 |     go : (k,l : Nat) -> {auto _ : Ix k m} -> {auto _ : Ix l n} -> Bool
125 |     go 0     0     = True
126 |     go (S k) (S j) = if ix a1 k == ix a2 j then go k j else False
127 |     go _     _     = False
128 |
129 | export
130 | {n : Nat} -> Eq (IBuffer n) where
131 |   a1 == a2 = go n
132 |
133 |     where
134 |       go : (k : Nat) -> {auto 0 _ : LTE k n} -> Bool
135 |       go 0     = True
136 |       go (S k) = if atNat a1 k == atNat a2 k then go k else False
137 |
138 | export
139 | {n : Nat} -> Ord (IBuffer n) where
140 |   compare a1 a2 = go n
141 |
142 |     where
143 |       go : (k : Nat) -> {auto _ : Ix k n} -> Ordering
144 |       go 0     = EQ
145 |       go (S k) = case compare (ix a1 k) (ix a2 k) of
146 |         EQ => go k
147 |         c  => c
148 |
149 | --------------------------------------------------------------------------------
150 | --          Maps and Folds
151 | --------------------------------------------------------------------------------
152 |
153 | ontoList :
154 |      List Bits8
155 |   -> (m : Nat)
156 |   -> {auto 0 lte : LTE m n}
157 |   -> IBuffer n
158 |   -> List Bits8
159 | ontoList xs 0     arr = xs
160 | ontoList xs (S k) arr = ontoList (atNat arr k :: xs) k arr
161 |
162 | ontoVect :
163 |      Vect k Bits8
164 |   -> (m : Nat)
165 |   -> {auto 0 lte : LTE m n}
166 |   -> IBuffer n
167 |   -> Vect (k + m) Bits8
168 | ontoVect xs 0     arr = rewrite plusZeroRightNeutral k in xs
169 | ontoVect xs (S v) arr =
170 |   rewrite sym (plusSuccRightSucc k v) in ontoVect (atNat arr v :: xs) v arr
171 |
172 | ontoVectWithIndex :
173 |      Vect k (Fin n, Bits8)
174 |   -> (m : Nat)
175 |   -> {auto 0 lte : LTE m n}
176 |   -> IBuffer n
177 |   -> Vect (k + m) (Fin n, Bits8)
178 | ontoVectWithIndex xs 0     arr = rewrite plusZeroRightNeutral k in xs
179 | ontoVectWithIndex xs (S v) arr =
180 |   rewrite sym (plusSuccRightSucc k v)
181 |   in let x := natToFinLT v in ontoVectWithIndex ((x, at arr x) :: xs) v arr
182 |
183 | ||| Convert an immutable byte array to a vector of the same length.
184 | export %inline
185 | toVect : {n : _} -> IBuffer n -> Vect n Bits8
186 | toVect = ontoVect [] n
187 |
188 | ||| Convert an immutable byte array to a vector of the same length
189 | ||| pairing all values with their index.
190 | export %inline
191 | toVectWithIndex : {n : _} -> IBuffer n -> Vect n (Fin n, Bits8)
192 | toVectWithIndex = ontoVectWithIndex [] n
193 |
194 | foldr_ :
195 |      (m : Nat)
196 |   -> {auto 0 _ : LTE m n}
197 |   -> (Bits8 -> a -> a)
198 |   -> a
199 |   -> IBuffer n
200 |   -> a
201 | foldr_ 0     _ x arr = x
202 | foldr_ (S k) f x arr = foldr_ k f (f (atNat arr k) x) arr
203 |
204 | ||| Right fold over the values of an immutable byte array plus their indices.
205 | export %inline
206 | foldr : {n : _} -> (Bits8 -> a -> a) -> a -> IBuffer n -> a
207 | foldr = foldr_ n
208 |
209 | export %inline
210 | toList : {n : _} -> IBuffer n -> List Bits8
211 | toList = foldr (::) Nil
212 |
213 | foldrKV_ :
214 |      (m : Nat)
215 |   -> {auto 0 prf : LTE m n}
216 |   -> (Fin n -> Bits8 -> a -> a)
217 |   -> a
218 |   -> IBuffer n
219 |   -> a
220 | foldrKV_ 0     _ x arr = x
221 | foldrKV_ (S k) f x arr =
222 |   let fin := natToFinLT k @{prf} in foldrKV_ k f (f fin (at arr fin) x) arr
223 |
224 | ||| Right fold over the values of an immutable  byte array plus their indices.
225 | export %inline
226 | foldrKV : {n : _} -> (Fin n -> Bits8 -> a -> a) -> a -> IBuffer n -> a
227 | foldrKV = foldrKV_ n
228 |
229 | foldl_ :
230 |      (m : Nat)
231 |   -> {auto x : Ix m n}
232 |   -> (a -> Bits8 -> a)
233 |   -> a
234 |   -> IBuffer n
235 |   -> a
236 | foldl_ 0     _ v arr = v
237 | foldl_ (S k) f v arr = foldl_ k f (f v (ix arr k)) arr
238 |
239 | ||| Left fold over the values of an immutable byte array.
240 | export %inline
241 | foldl : {n : _} -> (a -> Bits8 -> a) -> a -> IBuffer n -> a
242 | foldl = foldl_ n
243 |
244 | export %inline
245 | toSnocList : {n : _} -> IBuffer n -> SnocList Bits8
246 | toSnocList = foldl (:<) Lin
247 |
248 | foldlKV_ :
249 |      (m : Nat)
250 |   -> {auto x : Ix m n}
251 |   -> (Fin n -> a -> Bits8 -> a)
252 |   -> a
253 |   -> IBuffer n
254 |   -> a
255 | foldlKV_ 0     _ v arr = v
256 | foldlKV_ (S k) f v arr =
257 |   let fin := ixToFin x in foldlKV_ k f (f fin v (at arr fin)) arr
258 |
259 | ||| Left fold over the values of an immutable byte array plus their indices.
260 | export %inline
261 | foldlKV : {n : _} -> (Fin n -> a -> Bits8 -> a) -> a -> IBuffer n -> a
262 | foldlKV = foldlKV_ n
263 |
264 | export
265 | {n : Nat} -> Show (IBuffer n) where
266 |   showPrec p arr = showCon p "buffer" (showArg $ ontoList [] n arr)
267 |
268 | ||| Mapping over the values of an immutable byte array together with their indices.
269 | export %inline
270 | mapWithIndex : {n : _} -> (Fin n -> Bits8 -> Bits8) -> IBuffer n -> IBuffer n
271 | mapWithIndex f arr = generate n (\x => f x (at arr x))
272 |
273 | ||| Mapping over the values of an immutable byte array together with their indices.
274 | export %inline
275 | map : {n : _} -> (Bits8 -> Bits8) -> IBuffer n -> IBuffer n
276 | map f arr = generate n (f . at arr)
277 |
278 | ||| Update a single position in an immutable array by applying the given
279 | ||| function.
280 | |||
281 | ||| This will have to copy the whole array, so it runs in O(n).
282 | export
283 | updateAt : {n : _} -> Fin n -> (Bits8 -> Bits8) -> IBuffer n -> IBuffer n
284 | updateAt x f = mapWithIndex (\k,v => if x == k then f v else v)
285 |
286 | ||| Set a single position in an immutable byte array.
287 | |||
288 | ||| This will have to copy the whole array, so it runs in O(n).
289 | export
290 | setAt : {n : _} -> Fin n -> Bits8 -> IBuffer n -> IBuffer n
291 | setAt x y = mapWithIndex (\k,v => if x == k then y else v)
292 |
293 | --------------------------------------------------------------------------------
294 | --          Traversals
295 | --------------------------------------------------------------------------------
296 |
297 | ||| Effectful traversal of the values in an immutable byte array together with
298 | ||| their corresponding indices.
299 | export
300 | traverseWithIndex :
301 |      {n : _}
302 |   -> {auto app : Applicative f}
303 |   -> (Fin n -> Bits8 -> f Bits8)
304 |   -> IBuffer n
305 |   -> f (IBuffer n)
306 | traverseWithIndex f arr =
307 |   buffer <$> traverse (\(x,v) => f x v) (toVectWithIndex arr)
308 |
309 | export %inline
310 | traverse :
311 |      {n : _}
312 |   -> {auto app : Applicative f}
313 |   -> (Bits8 -> f Bits8)
314 |   -> IBuffer n
315 |   -> f (IBuffer n)
316 | traverse = traverseWithIndex . const
317 |
318 | --------------------------------------------------------------------------------
319 | --          Concatenation
320 | --------------------------------------------------------------------------------
321 |
322 | ||| Concatenate two immutable byte arrays.
323 | export
324 | append : {m,n : _} -> IBuffer m -> IBuffer n -> IBuffer (m + n)
325 | append src1 src2 =
326 |   alloc (m+n) $ \r,t =>
327 |     let _ # t := icopy {n = m+n} src1 0 0 m @{reflexive} @{lteAddRight _} r t
328 |         _ # t := icopy src2 0 m n @{reflexive} @{reflexive} r t
329 |      in unsafeFreeze r t
330 |
331 | --------------------------------------------------------------------------------
332 | --          Sub-Buffers
333 | --------------------------------------------------------------------------------
334 |
335 | ||| Drop n elements from a immutable byte array. O(n)
336 | export
337 | drop : {n : _} -> (m : Nat) -> IBuffer n -> IBuffer (n `minus` m)
338 | drop m buf = generate (n `minus` m) (\f => at buf (inc f))
339 |
340 | --------------------------------------------------------------------------------
341 | --          Non-indexed buffers
342 | --------------------------------------------------------------------------------
343 |
344 | export %inline
345 | Eq AnyBuffer where
346 |   AB _ b1 == AB _ b2 = heq b1 b2
347 |
348 | export %inline
349 | Ord AnyBuffer where
350 |   compare (AB _ b1) (AB _ b2) = hcomp b1 b2
351 |
352 | export %inline
353 | Semigroup AnyBuffer where
354 |   AB _ b1 <+> AB _ b2 = AB _ $ append b1 b2
355 |
356 | export %inline
357 | Monoid AnyBuffer where
358 |   neutral = AB 0 empty
359 |
360 | export
361 | Show AnyBuffer where
362 |   showPrec p (AB n ib) = showCon p "AB" (showArg n ++ showArg ib)
363 |
364 | export %inline
365 | FromString AnyBuffer where
366 |   fromString s = AB _ $ fromString s
367 |
368 | export %inline
369 | Cast AnyBuffer String where
370 |   cast (AB n ib) = toString ib 0 n
371 |
372 | export
373 | pack : List Bits8 -> AnyBuffer
374 | pack bs = AB _ $ bufferL bs
375 |
376 | export
377 | unpack : AnyBuffer -> List Bits8
378 | unpack (AB _ b) = toList b
379 |