2-- Module : Streamly.Internal.Data.MutArray.Stream
3-- Copyright : (c) 2019 Composewell Technologies
4-- License : BSD3-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : experimental
9-- Combinators to efficiently manipulate streams of mutable arrays.
11-- We can either push these in the MutArray module with a "chunks" prefix or
12-- keep this as a separate module and release it.
14module Streamly.Internal.Data.MutArray.Stream
18 , MArray.pinnedChunksOf
19 , MArray.writeChunks -- chunksWrite?
20 , MArray.splitOn -- chunksSplitOn
26 , compact -- chunksCompact
32 , MArray.flattenArrays -- chunksConcat
33 , MArray.flattenArraysRev -- chunksConcatRev
34 , MArray.fromArrayStreamK -- chunksCoalesce
39#include "ArrayMacros.h"
41import Control.Monad.IO.Class (MonadIO(..))
42import Control.Monad (when)
43import Data.Bifunctor (first)
44import Data.Proxy (Proxy(..))
45import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
46import Streamly.Internal.Data.MutArray.Type (MutArray(..))
47import Streamly.Internal.Data.Fold.Type (Fold(..))
48import Streamly.Internal.Data.Parser (ParseError)
49import Streamly.Internal.Data.Stream.Type (Stream)
50import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
52import qualified Streamly.Internal.Data.MutArray as MArray
53import qualified Streamly.Internal.Data.Fold.Type as FL
54import qualified Streamly.Internal.Data.Parser as ParserD
55import qualified Streamly.Internal.Data.Stream as D
57-------------------------------------------------------------------------------
59-------------------------------------------------------------------------------
63 | SpliceBuffering s arr
64 | SpliceYielding arr (SpliceState s arr)
67-- XXX This can be removed once compactLEFold/compactLE are implemented.
69-- | This mutates the first array (if it has space) to append values from the
70-- second one. This would work for immutable arrays as well because an
71-- immutable array never has space so a new array is allocated instead of
74-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
75-- maximum specified size. Note that if a single array is bigger than the
76-- specified size we do not split it to fit. When we coalesce multiple arrays
77-- if the size would exceed the specified size we do not coalesce therefore the
78-- actual array size may be less than the specified chunk size.
81{-# INLINE_NORMAL packArraysChunksOf #-}
82packArraysChunksOf :: (MonadIO m, Unbox a)
83 => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
84packArraysChunksOf n (D.Stream step state) =
85 D.Stream step' (SpliceInitial state)
89 {-# INLINE_LATE step' #-}
90 step' gst (SpliceInitial st) = do
92 -- XXX we can pass the module string from the higher level API
93 error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
94 ++ "arrays [" ++ show n ++ "] must be a natural number"
97 D.Yield arr s -> return $
98 let len = MArray.byteLength arr
100 then D.Skip (SpliceYielding arr (SpliceInitial s))
101 else D.Skip (SpliceBuffering s arr)
102 D.Skip s -> return $ D.Skip (SpliceInitial s)
103 D.Stop -> return D.Stop
105 step' gst (SpliceBuffering st buf) = do
109 let len = MArray.byteLength buf + MArray.byteLength arr
112 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
114 buf' <- if MArray.byteCapacity buf < n
115 then liftIO $ MArray.realloc n buf
117 buf'' <- MArray.splice buf' arr
118 return $ D.Skip (SpliceBuffering s buf'')
119 D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
120 D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
122 step' _ SpliceFinish = return D.Stop
124 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
126-- XXX Remove this once compactLEFold is implemented
127-- lpackArraysChunksOf = Fold.many compactLEFold
129{-# INLINE_NORMAL lpackArraysChunksOf #-}
130lpackArraysChunksOf :: (MonadIO m, Unbox a)
131 => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
132lpackArraysChunksOf n (Fold step1 initial1 _ final1) =
133 Fold step initial extract final
139 -- XXX we can pass the module string from the higher level API
140 error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
141 ++ "arrays [" ++ show n ++ "] must be a natural number"
144 return $ first (Tuple' Nothing) r
146 step (Tuple' Nothing r1) arr =
147 let len = MArray.byteLength arr
152 FL.Done _ -> return $ FL.Done ()
156 return $ first (Tuple' Nothing) res
157 else return $ FL.Partial $ Tuple' (Just arr) r1
159 step (Tuple' (Just buf) r1) arr = do
160 let len = MArray.byteLength buf + MArray.byteLength arr
161 buf' <- if MArray.byteCapacity buf < len
162 then liftIO $ MArray.realloc (max n len) buf
164 buf'' <- MArray.splice buf' arr
166 -- XXX this is common in both the equations of step
171 FL.Done _ -> return $ FL.Done ()
175 return $ first (Tuple' Nothing) res
176 else return $ FL.Partial $ Tuple' (Just buf'') r1
178 -- XXX Several folds do extract >=> final, therefore, we need to make final
179 -- return "m b" rather than using extract post it if we want extract to be
182 -- extract forces the pending buffer to be sent to the fold which is not
184 extract _ = error "lpackArraysChunksOf: not designed for scanning"
186 final (Tuple' Nothing r1) = final1 r1
187 final (Tuple' (Just buf) r1) = do
190 FL.Partial rr -> final1 rr
191 FL.Done _ -> return ()
193-- XXX Same as compactLE, to be removed once that is implemented.
195-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
196-- maximum specified size in bytes.
199{-# INLINE compact #-}
200compact :: (MonadIO m, Unbox a)
201 => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
202compact = packArraysChunksOf
204-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
205-- maximum specified size. Note that if a single array is bigger than the
206-- specified size we do not split it to fit. When we coalesce multiple arrays
207-- if the size would exceed the specified size we do not coalesce therefore the
208-- actual array size may be less than the specified chunk size.
211{-# INLINE_NORMAL compactLEParserD #-}
213 forall m a. (MonadIO m, Unbox a)
214 => Int -> ParserD.Parser (MutArray a) m (MutArray a)
215compactLEParserD n = ParserD.Parser step initial extract
219 nBytes = n * SIZE_OF(a)
226 ++ ": the size of arrays ["
227 ++ show n ++ "] must be a natural number"
228 else ParserD.IPartial Nothing
232 $ let len = MArray.byteLength arr
234 then ParserD.Done 0 arr
235 else ParserD.Partial 0 (Just arr)
236 step (Just buf) arr =
237 let len = MArray.byteLength buf + MArray.byteLength arr
239 then return $ ParserD.Done 1 buf
242 if MArray.byteCapacity buf < nBytes
243 then liftIO $ MArray.realloc nBytes buf
245 buf2 <- MArray.splice buf1 arr
246 return $ ParserD.Partial 0 (Just buf2)
248 extract Nothing = return $ ParserD.Done 0 MArray.nil
249 extract (Just buf) = return $ ParserD.Done 0 buf
252 "Streamly.Internal.Data.Stream.MutChunked.compactLEParserD"
254-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
255-- minimum specified size. Note that if all the arrays in the stream together
256-- are smaller than the specified size the resulting array will be smaller than
257-- the specified size. When we coalesce multiple arrays if the size would exceed
258-- the specified size we stop coalescing further.
261{-# INLINE_NORMAL compactGEFold #-}
263 forall m a. (MonadIO m, Unbox a)
264 => Int -> FL.Fold m (MutArray a) (MutArray a)
265compactGEFold n = Fold step initial extract extract
269 nBytes = n * SIZE_OF(a)
276 ++ ": the size of arrays ["
277 ++ show n ++ "] must be a natural number"
278 else FL.Partial Nothing
282 $ let len = MArray.byteLength arr
285 else FL.Partial (Just arr)
286 step (Just buf) arr = do
287 let len = MArray.byteLength buf + MArray.byteLength arr
289 if MArray.byteCapacity buf < len
290 then liftIO $ MArray.realloc (max len nBytes) buf
292 buf2 <- MArray.splice buf1 arr
294 then return $ FL.Done buf2
295 else return $ FL.Partial (Just buf2)
297 extract Nothing = return MArray.nil
298 extract (Just buf) = return buf
301 "Streamly.Internal.Data.Stream.MutChunked.compactGEFold"
303-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
304-- maximum specified size in bytes.
307compactLE :: (MonadIO m, Unbox a) =>
308 Int -> Stream m (MutArray a) -> Stream m (Either ParseError (MutArray a))
309compactLE n = D.parseManyD (compactLEParserD n)
311-- | Like 'compactLE' but generates arrays of exactly equal to the size
312-- specified except for the last array in the stream which could be shorter.
315{-# INLINE compactEQ #-}
316compactEQ :: -- (MonadIO m, Unbox a) =>
317 Int -> Stream m (MutArray a) -> Stream m (MutArray a)
318compactEQ _n _xs = undefined
319 -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
321-- | Like 'compactLE' but generates arrays of size greater than or equal to the
322-- specified except for the last array in the stream which could be shorter.
325{-# INLINE compactGE #-}
328 => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
329compactGE n = D.foldMany (compactGEFold n)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list