@@ -216,15 +216,24 @@ module Streamly.Internal.Data.MutArray.Type
216 , pinnedChunksOf
216 , pinnedChunksOf
217 , buildChunks
217 , buildChunks
219− -- *** Flatten a stream of arrays
223 -- *** Split an array into slices
219 -- *** Split an array into slices
224 -- , getSlicesFromLenN
220 -- , getSlicesFromLenN
225 , splitOn
221 , splitOn
226 -- , slicesOf
222 -- , slicesOf
224+ -- *** Flatten a stream of arrays
228 -- ** Utilities
237 -- ** Utilities
229 , roundUpToPower2
238 , roundUpToPower2
@@ -248,6 +257,7 @@ where
249import Control.Monad (when, void)
258import Control.Monad (when, void)
250import Control.Monad.IO.Class (MonadIO(..))
259import Control.Monad.IO.Class (MonadIO(..))
260+import Data.Bifunctor (first)
251import Data.Bits (shiftR, (.|.), (.&.))
261import Data.Bits (shiftR, (.|.), (.&.))
252import Data.Functor.Identity (Identity(..))
262import Data.Functor.Identity (Identity(..))
253import Data.Proxy (Proxy(..))
263import Data.Proxy (Proxy(..))
@@ -274,13 +284,17 @@ import GHC.Ptr (Ptr(..))
274import Streamly.Internal.Data.Fold.Type (Fold(..))
284import Streamly.Internal.Data.Fold.Type (Fold(..))
275import Streamly.Internal.Data.Producer.Type (Producer (..))
285import Streamly.Internal.Data.Producer.Type (Producer (..))
276import Streamly.Internal.Data.Stream.Type (Stream)
286import Streamly.Internal.Data.Stream.Type (Stream)
287+import Streamly.Internal.Data.Parser.Type (Parser (..))
277import Streamly.Internal.Data.StreamK.Type (StreamK)
288import Streamly.Internal.Data.StreamK.Type (StreamK)
278import Streamly.Internal.Data.SVar.Type (adaptState, defState)
289import Streamly.Internal.Data.SVar.Type (adaptState, defState)
290+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
279import Streamly.Internal.Data.Unfold.Type (Unfold(..))
291import Streamly.Internal.Data.Unfold.Type (Unfold(..))
280import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
292import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
282import qualified Streamly.Internal.Data.Fold.Type as FL
294import qualified Streamly.Internal.Data.Fold.Type as FL
283import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
295import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
296+import qualified Streamly.Internal.Data.Parser.Type as Parser
297+-- import qualified Streamly.Internal.Data.Fold.Type as Fold
284import qualified Streamly.Internal.Data.Producer as Producer
298import qualified Streamly.Internal.Data.Producer as Producer
285import qualified Streamly.Internal.Data.Stream.Type as D
299import qualified Streamly.Internal.Data.Stream.Type as D
286import qualified Streamly.Internal.Data.Stream.Lift as D
300import qualified Streamly.Internal.Data.Stream.Lift as D
@@ -2582,7 +2596,256 @@ byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
2582byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2596byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2584-------------------------------------------------------------------------------
2598-------------------------------------------------------------------------------
2585−-- NFData
2599+-- Compact
2600+-------------------------------------------------------------------------------
2602+-- | Parser @pCompactChunksLE n@ coalesces adjacent arrays in the input stream
2603+-- only if the combined size would be less than or equal to n.
2606+{-# INLINE_NORMAL pCompactChunksLE #-}
2608+ forall m a. (MonadIO m, Unbox a)
2609+ => Int -> Parser (MutArray a) m (MutArray a)
2610+pCompactChunksLE n = Parser step initial extract
2614+ nBytes = n * SIZE_OF(a)
2616+ functionName = "Streamly.Internal.Data.MutArray.pCompactChunksLE"
2623+ ++ ": the size of arrays ["
2624+ ++ show n ++ "] must be a natural number"
2625+ else Parser.IPartial Nothing
2629+ $ let len = byteLength arr
2630+ in if len >= nBytes
2631+ then Parser.Done 0 arr
2632+ else Parser.Partial 0 (Just arr)
2633+ step (Just buf) arr =
2634+ let len = byteLength buf + byteLength arr
2636+ then return $ Parser.Done 1 buf
2638+ -- XXX check this in the Nothing case
2640+ if byteCapacity buf < nBytes
2641+ then liftIO $ realloc nBytes buf
2643+ buf2 <- spliceUnsafe buf1 arr
2644+ return $ Parser.Partial 0 (Just buf2)
2646+ extract Nothing = return $ Parser.Done 0 nil
2647+ extract (Just buf) = return $ Parser.Done 0 buf
2649+data SpliceState s arr
2651+ | SpliceBuffering s arr
2652+ | SpliceYielding arr (SpliceState s arr)
2655+-- This mutates the first array (if it has space) to append values from the
2656+-- second one. This would work for immutable arrays as well because an
2657+-- immutable array never has additional space so a new array is allocated
2658+-- instead of mutating it.
2660+-- | Scan @rCompactChunksLE n@ coalesces adjacent arrays in the input stream
2661+-- only if the combined size would be less than or equal to n.
2664+{-# INLINE_NORMAL rCompactChunksLE #-}
2665+rCompactChunksLE :: (MonadIO m, Unbox a)
2666+ => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
2667+rCompactChunksLE n (D.Stream step state) =
2668+ D.Stream step' (SpliceInitial state)
2672+ functionName = "Streamly.Internal.Data.MutArray.rCompactChunksLE"
2674+ {-# INLINE_LATE step' #-}
2675+ step' gst (SpliceInitial st) = do
2677+ -- XXX we can pass the module string from the higher level API
2678+ error $ functionName ++ ": the size of arrays [" ++ show n
2679+ ++ "] must be a natural number"
2682+ D.Yield arr s -> return $
2683+ let len = byteLength arr
2685+ then D.Skip (SpliceYielding arr (SpliceInitial s))
2686+ else D.Skip (SpliceBuffering s arr)
2687+ D.Skip s -> return $ D.Skip (SpliceInitial s)
2688+ D.Stop -> return D.Stop
2690+ step' gst (SpliceBuffering st buf) = do
2693+ D.Yield arr s -> do
2694+ let len = byteLength buf + byteLength arr
2697+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
2699+ -- XXX check this in the SpliceInitial case
2700+ buf1 <- if byteCapacity buf < n
2701+ then liftIO $ realloc n buf
2703+ buf2 <- spliceUnsafe buf1 arr
2704+ return $ D.Skip (SpliceBuffering s buf2)
2705+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
2706+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
2708+ step' _ SpliceFinish = return D.Stop
2710+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
2712+-- | Fold @fCompactChunksGE n@ coalesces adjacent arrays in the input stream
2713+-- until the size becomes greater than or equal to n.
2715+{-# INLINE_NORMAL fCompactChunksGE #-}
2717+ forall m a. (MonadIO m, Unbox a)
2718+ => Int -> FL.Fold m (MutArray a) (MutArray a)
2719+fCompactChunksGE n = Fold step initial extract extract
2723+ nBytes = n * SIZE_OF(a)
2725+ functionName = "Streamly.Internal.Data.MutArray.fCompactChunksGE"
2732+ ++ ": the size of arrays ["
2733+ ++ show n ++ "] must be a natural number"
2734+ else FL.Partial Nothing
2738+ $ let len = byteLength arr
2739+ in if len >= nBytes
2741+ else FL.Partial (Just arr)
2742+ step (Just buf) arr = do
2743+ let len = byteLength buf + byteLength arr
2745+ if byteCapacity buf < len
2746+ then liftIO $ realloc (max len nBytes) buf
2748+ buf2 <- spliceUnsafe buf1 arr
2750+ then return $ FL.Done buf2
2751+ else return $ FL.Partial (Just buf2)
2753+ extract Nothing = return nil
2754+ extract (Just buf) = return buf
2756+-- | Like 'compactChunksGE' but for transforming folds instead of stream.
2758+-- >>> lCompactChunksGE n = Fold.many (MutArray.fCompactChunksGE n)
2760+{-# INLINE_NORMAL lCompactChunksGE #-}
2761+lCompactChunksGE :: (MonadIO m, Unbox a)
2762+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
2763+-- lCompactChunksGE n = Fold.many (fCompactChunksGE n)
2764+lCompactChunksGE n (Fold step1 initial1 _ final1) =
2765+ Fold step initial extract final
2769+ functionName = "Streamly.Internal.Data.MutArray.lCompactChunksGE"
2773+ -- XXX we can pass the module string from the higher level API
2774+ error $ functionName ++ ": the size of arrays ["
2775+ ++ show n ++ "] must be a natural number"
2778+ return $ first (Tuple' Nothing) r
2780+ step (Tuple' Nothing r1) arr =
2781+ let len = byteLength arr
2786+ FL.Done _ -> return $ FL.Done ()
2790+ return $ first (Tuple' Nothing) res
2791+ else return $ FL.Partial $ Tuple' (Just arr) r1
2793+ step (Tuple' (Just buf) r1) arr = do
2794+ let len = byteLength buf + byteLength arr
2795+ buf1 <- if byteCapacity buf < len
2796+ then liftIO $ realloc (max n len) buf
2798+ buf2 <- spliceUnsafe buf1 arr
2800+ -- XXX this is common in both the equations of step
2805+ FL.Done _ -> return $ FL.Done ()
2809+ return $ first (Tuple' Nothing) res
2810+ else return $ FL.Partial $ Tuple' (Just buf2) r1
2812+ -- XXX Several folds do extract >=> final, therefore, we need to make final
2813+ -- return "m b" rather than using extract post it if we want extract to be
2816+ -- extract forces the pending buffer to be sent to the fold which is not
2818+ extract _ = error "lCompactChunksGE: not designed for scanning"
2820+ final (Tuple' Nothing r1) = final1 r1
2821+ final (Tuple' (Just buf) r1) = do
2824+ FL.Partial rr -> final1 rr
2825+ FL.Done _ -> return ()
2827+-- | @compactChunksGE n stream@ coalesces adjacent arrays in the @stream@ until
2828+-- the size becomes greater than or equal to @n@.
2830+-- >>> compactChunksGE n = Stream.foldMany (MutArray.fCompactChunksGE n)
2832+{-# INLINE compactChunksGE #-}
2834+ (MonadIO m, Unbox a)
2835+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
2836+compactChunksGE n = D.foldMany (fCompactChunksGE n)
2838+-- | 'compactChunksEQ n' coalesces adajacent arrays in the input stream to
2839+-- arrays of exact size @n@.
2842+{-# INLINE compactChunksEQ #-}
2843+compactChunksEQ :: -- (MonadIO m, Unbox a) =>
2844+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
2845+compactChunksEQ _n = undefined -- D.parseManyD (pCompactChunksEQ n)
2847+-------------------------------------------------------------------------------
2848+-- In-place mutation algorithms
2586-------------------------------------------------------------------------------
2849-------------------------------------------------------------------------------
2588-- | Strip elements which match with predicate from both ends.
2851-- | Strip elements which match with predicate from both ends.