2-- Module : Streamly.Internal.Data.Array.Stream.Mut.Foreign
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.Stream.Mut.Foreign
29import Control.Monad.IO.Class (MonadIO(..))
30import Control.Monad (when)
31import Data.Bifunctor (first)
32import Foreign.Storable (Storable(..))
33import Streamly.Internal.Data.Array.Foreign.Mut.Type (Array(..))
34import Streamly.Internal.Data.Fold.Type (Fold(..))
35import Streamly.Internal.Data.Stream.Serial (SerialT(..))
36import Streamly.Internal.Data.Stream.IsStream.Type
37 (IsStream, fromStreamD, toStreamD)
38import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
40import qualified Streamly.Internal.Data.Array.Foreign.Mut.Type as MArray
41import qualified Streamly.Internal.Data.Fold.Type as FL
42import qualified Streamly.Internal.Data.Stream.StreamD as D
44-- | @arraysOf n stream@ groups the elements in the input stream into arrays of
47-- Same as the following but may be more efficient:
49-- > arraysOf n = Stream.foldMany (MArray.writeN n)
52{-# INLINE arraysOf #-}
53arraysOf :: (IsStream t, MonadIO m, Storable a)
54 => Int -> t m a -> t m (Array a)
55arraysOf n = fromStreamD . MArray.arraysOf n . toStreamD
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, Storable a)
83 => Int -> D.Stream m (Array a) -> D.Stream m (Array 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.Array.Foreign.Mut.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, Storable a)
131 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
132lpackArraysChunksOf n (Fold step1 initial1 extract1) =
133 Fold step initial extract
139 -- XXX we can pass the module string from the higher level API
140 error $ "Streamly.Internal.Data.Array.Foreign.Mut.Type.packArraysChunksOf: the size of "
141 ++ "arrays [" ++ show n ++ "] must be a natural number"
144 return $ first (Tuple' Nothing) r
146 extract (Tuple' Nothing r1) = extract1 r1
147 extract (Tuple' (Just buf) r1) = do
150 FL.Partial rr -> extract1 rr
151 FL.Done _ -> return ()
153 step (Tuple' Nothing r1) arr =
154 let len = MArray.byteLength arr
159 FL.Done _ -> return $ FL.Done ()
163 return $ first (Tuple' Nothing) res
164 else return $ FL.Partial $ Tuple' (Just arr) r1
166 step (Tuple' (Just buf) r1) arr = do
167 let len = MArray.byteLength buf + MArray.byteLength arr
168 buf' <- if MArray.byteCapacity buf < len
169 then liftIO $ MArray.realloc (max n len) buf
171 buf'' <- MArray.splice buf' arr
173 -- XXX this is common in both the equations of step
178 FL.Done _ -> return $ FL.Done ()
182 return $ first (Tuple' Nothing) res
183 else return $ FL.Partial $ Tuple' (Just buf'') r1
185-- XXX Same as compactLE, to be removed once that is implemented.
187-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
188-- maximum specified size in bytes.
191{-# INLINE compact #-}
192compact :: (MonadIO m, Storable a)
193 => Int -> SerialT m (Array a) -> SerialT m (Array a)
194compact n (SerialT xs) =
195 SerialT $ D.toStreamK $ packArraysChunksOf n (D.fromStreamK xs)
197-- See lpackArraysChunksOf/packArraysChunksOf to implement this.
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 compactLEFold #-}
207compactLEFold :: -- (MonadIO m, Storable a) =>
208 Int -> Fold m (Array a) (Array a)
209compactLEFold = undefined
211-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
212-- maximum specified size in bytes.
215compactLE :: (MonadIO m {-, Storable a-}) =>
216 Int -> SerialT m (Array a) -> SerialT m (Array a)
217compactLE n (SerialT xs) =
218 SerialT $ D.toStreamK $ D.foldMany (compactLEFold n) (D.fromStreamK xs)
220-- | Like 'compactLE' but generates arrays of exactly equal to the size
221-- specified except for the last array in the stream which could be shorter.
224{-# INLINE compactEQ #-}
225compactEQ :: -- (MonadIO m, Storable a) =>
226 Int -> SerialT m (Array a) -> SerialT m (Array a)
227compactEQ _n _xs = undefined
228 -- IsStream.fromStreamD $ D.foldMany (compactEQFold n) (IsStream.toStreamD xs)
230-- | Like 'compactLE' but generates arrays of size greater than or equal to the
231-- specified except for the last array in the stream which could be shorter.
234{-# INLINE compactGE #-}
235compactGE :: -- (MonadIO m, Storable a) =>
236 Int -> SerialT m (Array a) -> SerialT m (Array a)
237compactGE _n _xs = undefined
238 -- IsStream.fromStreamD $ D.foldMany (compactGEFold n) (IsStream.toStreamD xs)
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