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 (MutArray(..))
36import Streamly.Internal.Data.Fold.Type (Fold(..))
37import Streamly.Internal.Data.Parser (ParseError)
38import Streamly.Internal.Data.Stream.StreamD.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
46-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
49-- Same as the following but may be more efficient:
51-- > chunksOf n = Stream.foldMany (MArray.writeN n)
54{-# INLINE chunksOf #-}
55chunksOf :: (MonadIO m, Unbox a)
56 => Int -> Stream m a -> Stream m (MutArray a)
57chunksOf = MArray.chunksOf
59-------------------------------------------------------------------------------
61-------------------------------------------------------------------------------
65 | SpliceBuffering s arr
66 | SpliceYielding arr (SpliceState s arr)
69-- XXX This can be removed once compactLEFold/compactLE are implemented.
71-- | This mutates the first array (if it has space) to append values from the
72-- second one. This would work for immutable arrays as well because an
73-- immutable array never has space so a new array is allocated instead of
76-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
77-- maximum specified size. Note that if a single array is bigger than the
78-- specified size we do not split it to fit. When we coalesce multiple arrays
79-- if the size would exceed the specified size we do not coalesce therefore the
80-- actual array size may be less than the specified chunk size.
83{-# INLINE_NORMAL packArraysChunksOf #-}
84packArraysChunksOf :: (MonadIO m, Unbox a)
85 => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
86packArraysChunksOf n (D.Stream step state) =
87 D.Stream step' (SpliceInitial state)
91 {-# INLINE_LATE step' #-}
92 step' gst (SpliceInitial st) = do
94 -- XXX we can pass the module string from the higher level API
95 error $ "Streamly.Internal.Data.Array.Mut.Type.packArraysChunksOf: the size of "
96 ++ "arrays [" ++ show n ++ "] must be a natural number"
99 D.Yield arr s -> return $
100 let len = MArray.byteLength arr
102 then D.Skip (SpliceYielding arr (SpliceInitial s))
103 else D.Skip (SpliceBuffering s arr)
104 D.Skip s -> return $ D.Skip (SpliceInitial s)
105 D.Stop -> return D.Stop
107 step' gst (SpliceBuffering st buf) = do
111 let len = MArray.byteLength buf + MArray.byteLength arr
114 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
116 buf' <- if MArray.byteCapacity buf < n
117 then liftIO $ MArray.realloc n buf
119 buf'' <- MArray.splice buf' arr
120 return $ D.Skip (SpliceBuffering s buf'')
121 D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
122 D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
124 step' _ SpliceFinish = return D.Stop
126 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
128-- XXX Remove this once compactLEFold is implemented
129-- lpackArraysChunksOf = Fold.many compactLEFold
131{-# INLINE_NORMAL lpackArraysChunksOf #-}
132lpackArraysChunksOf :: (MonadIO m, Unbox a)
133 => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
134lpackArraysChunksOf n (Fold step1 initial1 extract1) =
135 Fold step initial extract
141 -- XXX we can pass the module string from the higher level API
142 error $ "Streamly.Internal.Data.Array.Mut.Type.packArraysChunksOf: the size of "
143 ++ "arrays [" ++ show n ++ "] must be a natural number"
146 return $ first (Tuple' Nothing) r
148 extract (Tuple' Nothing r1) = extract1 r1
149 extract (Tuple' (Just buf) r1) = do
152 FL.Partial rr -> extract1 rr
153 FL.Done _ -> return ()
155 step (Tuple' Nothing r1) arr =
156 let len = MArray.byteLength arr
161 FL.Done _ -> return $ FL.Done ()
165 return $ first (Tuple' Nothing) res
166 else return $ FL.Partial $ Tuple' (Just arr) r1
168 step (Tuple' (Just buf) r1) arr = do
169 let len = MArray.byteLength buf + MArray.byteLength arr
170 buf' <- if MArray.byteCapacity buf < len
171 then liftIO $ MArray.realloc (max n len) buf
173 buf'' <- MArray.splice buf' arr
175 -- XXX this is common in both the equations of step
180 FL.Done _ -> return $ FL.Done ()
184 return $ first (Tuple' Nothing) res
185 else return $ FL.Partial $ Tuple' (Just buf'') r1
187-- XXX Same as compactLE, to be removed once that is implemented.
189-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
190-- maximum specified size in bytes.
193{-# INLINE compact #-}
194compact :: (MonadIO m, Unbox a)
195 => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
196compact = packArraysChunksOf
198-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
199-- maximum specified size. Note that if a single array is bigger than the
200-- specified size we do not split it to fit. When we coalesce multiple arrays
201-- if the size would exceed the specified size we do not coalesce therefore the
202-- actual array size may be less than the specified chunk size.
205{-# INLINE_NORMAL compactLEParserD #-}
207 forall m a. (MonadIO m, Unbox a)
208 => Int -> ParserD.Parser (MutArray a) m (MutArray a)
209compactLEParserD n = ParserD.Parser step initial extract
213 nBytes = n * SIZE_OF(a)
220 ++ ": the size of arrays ["
221 ++ show n ++ "] must be a natural number"
222 else ParserD.IPartial Nothing
226 $ let len = MArray.byteLength arr
228 then ParserD.Done 0 arr
229 else ParserD.Partial 0 (Just arr)
230 step (Just buf) arr =
231 let len = MArray.byteLength buf + MArray.byteLength arr
233 then return $ ParserD.Done 1 buf
236 if MArray.byteCapacity buf < nBytes
237 then liftIO $ MArray.realloc nBytes buf
239 buf2 <- MArray.splice buf1 arr
240 return $ ParserD.Partial 0 (Just buf2)
242 extract Nothing = return $ ParserD.Done 0 MArray.nil
243 extract (Just buf) = return $ ParserD.Done 0 buf
246 "Streamly.Internal.Data.Array.Mut.Stream.compactLEParserD"
248-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
249-- minimum specified size. Note that if all the arrays in the stream together
250-- are smaller than the specified size the resulting array will be smaller than
251-- the specified size. When we coalesce multiple arrays if the size would exceed
252-- the specified size we stop coalescing further.
255{-# INLINE_NORMAL compactGEFold #-}
257 forall m a. (MonadIO m, Unbox a)
258 => Int -> FL.Fold m (MutArray a) (MutArray a)
259compactGEFold n = Fold step initial extract
263 nBytes = n * SIZE_OF(a)
270 ++ ": the size of arrays ["
271 ++ show n ++ "] must be a natural number"
272 else FL.Partial Nothing
276 $ let len = MArray.byteLength arr
279 else FL.Partial (Just arr)
280 step (Just buf) arr = do
281 let len = MArray.byteLength buf + MArray.byteLength arr
283 if MArray.byteCapacity buf < len
284 then liftIO $ MArray.realloc (max len nBytes) buf
286 buf2 <- MArray.splice buf1 arr
288 then return $ FL.Done buf2
289 else return $ FL.Partial (Just buf2)
291 extract Nothing = return MArray.nil
292 extract (Just buf) = return buf
295 "Streamly.Internal.Data.Array.Mut.Stream.compactGEFold"
297-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
298-- maximum specified size in bytes.
301compactLE :: (MonadIO m, Unbox a) =>
302 Int -> Stream m (MutArray a) -> Stream m (Either ParseError (MutArray a))
303compactLE n = D.parseManyD (compactLEParserD n)
305-- | Like 'compactLE' but generates arrays of exactly equal to the size
306-- specified except for the last array in the stream which could be shorter.
309{-# INLINE compactEQ #-}
310compactEQ :: -- (MonadIO m, Unbox a) =>
311 Int -> Stream m (MutArray a) -> Stream m (MutArray a)
312compactEQ _n _xs = undefined
313 -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
315-- | Like 'compactLE' but generates arrays of size greater than or equal to the
316-- specified except for the last array in the stream which could be shorter.
319{-# INLINE compactGE #-}
322 => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
323compactGE 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