2-- Module : Streamly.Internal.Data.Array.Mut.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.
11module Streamly.Internal.Data.Array.Mut.Stream
28#include "ArrayMacros.h"
30import Control.Monad.IO.Class (MonadIO(..))
31import Control.Monad (when)
32import Data.Bifunctor (first)
33import Data.Proxy (Proxy(..))
34import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
35import Streamly.Internal.Data.Array.Mut.Type (Array(..))
36import Streamly.Internal.Data.Fold.Type (Fold(..))
37import Streamly.Internal.Data.Parser (ParseError)
38import Streamly.Internal.Data.Stream.Type (Stream)
39import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
41import qualified Streamly.Internal.Data.Array.Mut.Type as MArray
42import qualified Streamly.Internal.Data.Fold.Type as FL
43import qualified Streamly.Internal.Data.Stream.StreamD as D
44import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
45import qualified Streamly.Internal.Data.Stream.Type as Stream
47-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
50-- Same as the following but may be more efficient:
52-- > arraysOf n = Stream.foldMany (MArray.writeN n)
55{-# INLINE arraysOf #-}
56arraysOf :: (MonadIO m, Unbox a)
57 => Int -> Stream m a -> Stream m (Array a)
58arraysOf n = Stream.fromStreamD . MArray.arraysOf n . Stream.toStreamD
60-------------------------------------------------------------------------------
62-------------------------------------------------------------------------------
66 | SpliceBuffering s arr
67 | SpliceYielding arr (SpliceState s arr)
70-- XXX This can be removed once compactLEFold/compactLE are implemented.
72-- | This mutates the first array (if it has space) to append values from the
73-- second one. This would work for immutable arrays as well because an
74-- immutable array never has space so a new array is allocated instead of
77-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
78-- maximum specified size. Note that if a single array is bigger than the
79-- specified size we do not split it to fit. When we coalesce multiple arrays
80-- if the size would exceed the specified size we do not coalesce therefore the
81-- actual array size may be less than the specified chunk size.
84{-# INLINE_NORMAL packArraysChunksOf #-}
85packArraysChunksOf :: (MonadIO m, Unbox a)
86 => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
87packArraysChunksOf n (D.Stream step state) =
88 D.Stream step' (SpliceInitial state)
92 {-# INLINE_LATE step' #-}
93 step' gst (SpliceInitial st) = do
95 -- XXX we can pass the module string from the higher level API
96 error $ "Streamly.Internal.Data.Array.Mut.Type.packArraysChunksOf: the size of "
97 ++ "arrays [" ++ show n ++ "] must be a natural number"
100 D.Yield arr s -> return $
101 let len = MArray.byteLength arr
103 then D.Skip (SpliceYielding arr (SpliceInitial s))
104 else D.Skip (SpliceBuffering s arr)
105 D.Skip s -> return $ D.Skip (SpliceInitial s)
106 D.Stop -> return D.Stop
108 step' gst (SpliceBuffering st buf) = do
112 let len = MArray.byteLength buf + MArray.byteLength arr
115 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
117 buf' <- if MArray.byteCapacity buf < n
118 then liftIO $ MArray.realloc n buf
120 buf'' <- MArray.splice buf' arr
121 return $ D.Skip (SpliceBuffering s buf'')
122 D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
123 D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
125 step' _ SpliceFinish = return D.Stop
127 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
129-- XXX Remove this once compactLEFold is implemented
130-- lpackArraysChunksOf = Fold.many compactLEFold
132{-# INLINE_NORMAL lpackArraysChunksOf #-}
133lpackArraysChunksOf :: (MonadIO m, Unbox a)
134 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
135lpackArraysChunksOf n (Fold step1 initial1 extract1) =
136 Fold step initial extract
142 -- XXX we can pass the module string from the higher level API
143 error $ "Streamly.Internal.Data.Array.Mut.Type.packArraysChunksOf: the size of "
144 ++ "arrays [" ++ show n ++ "] must be a natural number"
147 return $ first (Tuple' Nothing) r
149 extract (Tuple' Nothing r1) = extract1 r1
150 extract (Tuple' (Just buf) r1) = do
153 FL.Partial rr -> extract1 rr
154 FL.Done _ -> return ()
156 step (Tuple' Nothing r1) arr =
157 let len = MArray.byteLength arr
162 FL.Done _ -> return $ FL.Done ()
166 return $ first (Tuple' Nothing) res
167 else return $ FL.Partial $ Tuple' (Just arr) r1
169 step (Tuple' (Just buf) r1) arr = do
170 let len = MArray.byteLength buf + MArray.byteLength arr
171 buf' <- if MArray.byteCapacity buf < len
172 then liftIO $ MArray.realloc (max n len) buf
174 buf'' <- MArray.splice buf' arr
176 -- XXX this is common in both the equations of step
181 FL.Done _ -> return $ FL.Done ()
185 return $ first (Tuple' Nothing) res
186 else return $ FL.Partial $ Tuple' (Just buf'') r1
188-- XXX Same as compactLE, to be removed once that is implemented.
190-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
191-- maximum specified size in bytes.
194{-# INLINE compact #-}
195compact :: (MonadIO m, Unbox a)
196 => Int -> Stream m (Array a) -> Stream m (Array a)
197compact n = Stream.fromStreamD . packArraysChunksOf n . Stream.toStreamD
199-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
200-- maximum specified size. Note that if a single array is bigger than the
201-- specified size we do not split it to fit. When we coalesce multiple arrays
202-- if the size would exceed the specified size we do not coalesce therefore the
203-- actual array size may be less than the specified chunk size.
206{-# INLINE_NORMAL compactLEParserD #-}
208 forall m a. (MonadIO m, Unbox a)
209 => Int -> ParserD.Parser (Array a) m (Array a)
210compactLEParserD n = ParserD.Parser step initial extract
214 nBytes = n * SIZE_OF(a)
221 ++ ": the size of arrays ["
222 ++ show n ++ "] must be a natural number"
223 else ParserD.IPartial Nothing
227 $ let len = MArray.byteLength arr
229 then ParserD.Done 0 arr
230 else ParserD.Partial 0 (Just arr)
231 step (Just buf) arr =
232 let len = MArray.byteLength buf + MArray.byteLength arr
234 then return $ ParserD.Done 1 buf
237 if MArray.byteCapacity buf < nBytes
238 then liftIO $ MArray.realloc nBytes buf
240 buf2 <- MArray.splice buf1 arr
241 return $ ParserD.Partial 0 (Just buf2)
243 extract Nothing = return $ ParserD.Done 0 MArray.nil
244 extract (Just buf) = return $ ParserD.Done 0 buf
247 "Streamly.Internal.Data.Array.Mut.Stream.compactLEParserD"
249-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
250-- minimum specified size. Note that if all the arrays in the stream together
251-- are smaller than the specified size the resulting array will be smaller than
252-- the specified size. When we coalesce multiple arrays if the size would exceed
253-- the specified size we stop coalescing further.
256{-# INLINE_NORMAL compactGEFold #-}
258 forall m a. (MonadIO m, Unbox a)
259 => Int -> FL.Fold m (Array a) (Array a)
260compactGEFold n = Fold step initial extract
264 nBytes = n * SIZE_OF(a)
271 ++ ": the size of arrays ["
272 ++ show n ++ "] must be a natural number"
273 else FL.Partial Nothing
277 $ let len = MArray.byteLength arr
280 else FL.Partial (Just arr)
281 step (Just buf) arr = do
282 let len = MArray.byteLength buf + MArray.byteLength arr
284 if MArray.byteCapacity buf < len
285 then liftIO $ MArray.realloc (max len nBytes) buf
287 buf2 <- MArray.splice buf1 arr
289 then return $ FL.Done buf2
290 else return $ FL.Partial (Just buf2)
292 extract Nothing = return MArray.nil
293 extract (Just buf) = return buf
296 "Streamly.Internal.Data.Array.Mut.Stream.compactGEFold"
298-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
299-- maximum specified size in bytes.
302compactLE :: (Monad m, MonadIO m, Unbox a) =>
303 Int -> Stream m (Array a) -> Stream m (Either ParseError (Array a))
305 Stream.fromStreamD . D.parseMany (compactLEParserD n) . Stream.toStreamD
307-- | Like 'compactLE' but generates arrays of exactly equal to the size
308-- specified except for the last array in the stream which could be shorter.
311{-# INLINE compactEQ #-}
312compactEQ :: -- (MonadIO m, Unbox a) =>
313 Int -> Stream m (Array a) -> Stream m (Array a)
314compactEQ _n _xs = undefined
315 -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
317-- | Like 'compactLE' but generates arrays of size greater than or equal to the
318-- specified except for the last array in the stream which could be shorter.
321{-# INLINE compactGE #-}
324 => Int -> Stream m (Array a) -> Stream m (Array a)
326 Stream.fromStreamD . D.foldMany (compactGEFold n) . Stream.toStreamD
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