@@ -5,7 +5,6 @@
5-- Copyright : (c) 2018 Composewell Technologies
5-- Copyright : (c) 2018 Composewell Technologies
6-- (c) Roman Leshchinskiy 2008-2010
6-- (c) Roman Leshchinskiy 2008-2010
7-- (c) The University of Glasgow, 2009
7-- (c) The University of Glasgow, 2009
9-- License : BSD3
8-- License : BSD3
10-- Maintainer : streamly@composewell.com
9-- Maintainer : streamly@composewell.com
11-- Stability : experimental
10-- Stability : experimental
@@ -302,11 +301,11 @@ module Streamly.Internal.Data.Stream.StreamD
305−import Control.Concurrent (killThread, myThreadId, takeMVar, threadDelay)
304+import Control.Concurrent (myThreadId)
306import Control.Exception
305import Control.Exception
307− (assert, Exception, SomeException, AsyncException, mask_)
306+ (Exception, SomeException, mask_)
308−import Control.Monad (void, when)
307+import Control.Monad (void)
309−import Control.Monad.Catch (MonadCatch, MonadThrow, throwM)
308+import Control.Monad.Catch (MonadCatch)
310import Control.Monad.IO.Class (MonadIO(..))
309import Control.Monad.IO.Class (MonadIO(..))
311import Control.Monad.Trans.Reader (ReaderT)
310import Control.Monad.Trans.Reader (ReaderT)
312import Control.Monad.Trans.State.Strict (StateT)
311import Control.Monad.Trans.State.Strict (StateT)
@@ -315,31 +314,19 @@ import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_, control)
315import Data.Functor.Identity (Identity(..))
314import Data.Functor.Identity (Identity(..))
316import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef, IORef)
315import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef, IORef)
317import Data.Maybe (fromJust, isJust)
316import Data.Maybe (fromJust, isJust)
318−import Foreign.Storable (Storable(..))
319−import GHC.Exts (SpecConstrAnnotation(..))
320−import GHC.Types (SPEC(..))
321import Fusion.Plugin.Types (Fuse(..))
317import Fusion.Plugin.Types (Fuse(..))
322import Streamly.Internal.Data.Time.Units
318import Streamly.Internal.Data.Time.Units
323 (TimeUnit64, toRelTime64, diffAbsTime64)
319 (TimeUnit64, toRelTime64, diffAbsTime64)
324−import Streamly.Internal.Data.Atomics (atomicModifyIORefCAS_)
325−import Streamly.Internal.Data.Fold.Types (Fold(..))
326−import Streamly.Internal.Data.Parser (ParseError(..))
327import Streamly.Internal.Data.Pipe.Types (Pipe(..), PipeState(..))
320import Streamly.Internal.Data.Pipe.Types (Pipe(..), PipeState(..))
328import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
321import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
329import Streamly.Internal.Data.Unfold.Types (Unfold(..))
322import Streamly.Internal.Data.Unfold.Types (Unfold(..))
330−import Streamly.Internal.Data.Stream.SVar (fromConsumer, pushToFold)
332−import qualified Streamly.Internal.Data.IORef.Prim as Prim
333import qualified Streamly.Internal.Data.Pipe.Types as Pipe
324import qualified Streamly.Internal.Data.Pipe.Types as Pipe
334−import qualified Streamly.Internal.Data.Array.Storable.Foreign.Types as A
335import qualified Streamly.Internal.Data.Fold as FL
325import qualified Streamly.Internal.Data.Fold as FL
336import qualified Streamly.Internal.Data.Stream.StreamK as K
326import qualified Streamly.Internal.Data.Stream.StreamK as K
337−import qualified Streamly.Internal.Data.Parser as PR
338−import qualified Streamly.Internal.Data.Parser.ParserD as PRD
339import qualified Control.Monad.Catch as MC
327import qualified Control.Monad.Catch as MC
340import qualified Control.Monad.Trans.Reader as Reader
328import qualified Control.Monad.Trans.Reader as Reader
341import qualified Control.Monad.Trans.State.Strict as State
329import qualified Control.Monad.Trans.State.Strict as State
342−import qualified Prelude
344import Prelude hiding
331import Prelude hiding
345 ( map, mapM, mapM_, repeat, foldr, last, take, filter
332 ( map, mapM, mapM_, repeat, foldr, last, take, filter
@@ -349,6 +336,7 @@ import Prelude hiding
349 , reverse, iterate, splitAt)
336 , reverse, iterate, splitAt)
350import Streamly.Internal.Data.Stream.StreamD.Type
337import Streamly.Internal.Data.Stream.StreamD.Type
351import Streamly.Internal.Data.Stream.StreamD.Generate
338import Streamly.Internal.Data.Stream.StreamD.Generate
339+import Streamly.Internal.Data.Stream.StreamD.Eliminate
352import Streamly.Internal.Data.Stream.StreamD.SplitGroup
340import Streamly.Internal.Data.Stream.StreamD.SplitGroup
353import Streamly.Internal.Data.SVar
341import Streamly.Internal.Data.SVar
@@ -534,621 +522,6 @@ foldr1 f m = do
534 Nothing -> return Nothing
522 Nothing -> return Nothing
535 Just (h, t) -> fmap Just (foldr f h t)
523 Just (h, t) -> fmap Just (foldr f h t)
537−------------------------------------------------------------------------------
539−------------------------------------------------------------------------------
541−{-# INLINE_NORMAL foldlT #-}
542−foldlT :: (Monad m, Monad (s m), MonadTrans s)
543− => (s m b -> a -> s m b) -> s m b -> Stream m a -> s m b
544−foldlT fstep begin (Stream step state) = go SPEC begin state
547− r <- lift $ step defState st
549− Yield x s -> go SPEC (fstep acc x) s
550− Skip s -> go SPEC acc s
553−-- Note, this is going to have horrible performance, because of the nature of
554−-- the stream type (i.e. direct stream vs CPS). Its only for reference, it is
555−-- likely be practically unusable.
556−{-# INLINE_NORMAL foldlS #-}
558− => (Stream m b -> a -> Stream m b) -> Stream m b -> Stream m a -> Stream m b
559−foldlS fstep begin (Stream step state) = Stream step' (Left (state, begin))
561− step' gst (Left (st, acc)) = do
562− r <- step (adaptState gst) st
564− Yield x s -> Skip (Left (s, fstep acc x))
565− Skip s -> Skip (Left (s, acc))
566− Stop -> Skip (Right acc)
568− step' gst (Right (Stream stp stt)) = do
569− r <- stp (adaptState gst) stt
571− Yield x s -> Yield x (Right (Stream stp s))
572− Skip s -> Skip (Right (Stream stp s))
575−------------------------------------------------------------------------------
577−------------------------------------------------------------------------------
579−-- Inlined definition. Without the inline "serially/parser/take" benchmark
580−-- degrades and parseMany does not fuse. Even using "inline" at the callsite
582−{-# INLINE splitAt #-}
583−splitAt :: Int -> [a] -> ([a],[a])
586− | otherwise = splitAt' n ls
588− splitAt' :: Int -> [a] -> ([a], [a])
589− splitAt' _ [] = ([], [])
590− splitAt' 1 (x:xs) = ([x], xs)
591− splitAt' m (x:xs) = (x:xs', xs'')
593− (xs', xs'') = splitAt' (m - 1) xs
595−-- GHC parser does not accept {-# ANN type [] NoSpecConstr #-}, so we need
596−-- to make a newtype.
597−{-# ANN type List NoSpecConstr #-}
598−newtype List a = List {getList :: [a]}
600−-- | Run a 'Parse' over a stream.
601−{-# INLINE_NORMAL parselMx' #-}
604− => (s -> a -> m (PR.Step s b))
609−parselMx' pstep initial extract (Stream step state) = do
610− initial >>= go SPEC state (List [])
614− -- XXX currently we are using a dumb list based approach for backtracking
615− -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
616− -- That will allow us more efficient random back and forth movement.
618− go !_ st buf !pst = do
619− r <- step defState st
624− PR.Partial 0 pst1 -> go SPEC s (List []) pst1
625− PR.Partial n pst1 -> do
626− assert (n <= length (x:getList buf)) (return ())
627− let src0 = Prelude.take n (x:getList buf)
628− src = Prelude.reverse src0
629− gobuf SPEC s (List []) (List src) pst1
630− PR.Continue 0 pst1 -> go SPEC s (List (x:getList buf)) pst1
631− PR.Continue n pst1 -> do
632− assert (n <= length (x:getList buf)) (return ())
633− let (src0, buf1) = splitAt n (x:getList buf)
634− src = Prelude.reverse src0
635− gobuf SPEC s (List buf1) (List src) pst1
636− PR.Done _ b -> return b
637− PR.Error err -> throwM $ ParseError err
638− Skip s -> go SPEC s buf pst
641− gobuf !_ s buf (List []) !pst = go SPEC s buf pst
642− gobuf !_ s buf (List (x:xs)) !pst = do
645− PR.Partial 0 pst1 ->
646− gobuf SPEC s (List []) (List xs) pst1
647− PR.Partial n pst1 -> do
648− assert (n <= length (x:getList buf)) (return ())
649− let src0 = Prelude.take n (x:getList buf)
650− src = Prelude.reverse src0 ++ xs
651− gobuf SPEC s (List []) (List src) pst1
652− PR.Continue 0 pst1 ->
653− gobuf SPEC s (List (x:getList buf)) (List xs) pst1
654− PR.Continue n pst1 -> do
655− assert (n <= length (x:getList buf)) (return ())
656− let (src0, buf1) = splitAt n (x:getList buf)
657− src = Prelude.reverse src0 ++ xs
658− gobuf SPEC s (List buf1) (List src) pst1
659− PR.Done _ b -> return b
660− PR.Error err -> throwM $ ParseError err
662−------------------------------------------------------------------------------
664−------------------------------------------------------------------------------
666−{-# ANN type ParseChunksState Fuse #-}
667−data ParseChunksState x inpBuf st pst =
668− ParseChunksInit inpBuf st
669− | ParseChunksInitLeftOver inpBuf
670− | ParseChunksStream st inpBuf !pst
671− | ParseChunksBuf inpBuf st inpBuf !pst
672− | ParseChunksYield x (ParseChunksState x inpBuf st pst)
674−{-# INLINE_NORMAL parseMany #-}
680−parseMany (PRD.Parser pstep initial extract) (Stream step state) =
681− Stream stepOuter (ParseChunksInit [] state)
685− {-# INLINE_LATE stepOuter #-}
686− -- Buffer is empty, get the first element from the stream, initialize the
687− -- fold and then go to stream processing loop.
688− stepOuter gst (ParseChunksInit [] st) = do
689− r <- step (adaptState gst) st
691− Yield x s -> initial >>= return . Skip . ParseChunksBuf [x] s []
692− Skip s -> return $ Skip $ ParseChunksInit [] s
695− -- Buffer is not empty, go to buffered processing loop
696− stepOuter _ (ParseChunksInit src st) = do
697− initial >>= return . Skip . ParseChunksBuf src st []
699− -- XXX we just discard any leftover input at the end
700− stepOuter _ (ParseChunksInitLeftOver _) = return Stop
702− -- Buffer is empty, process elements from the stream
703− stepOuter gst (ParseChunksStream st buf pst) = do
704− r <- step (adaptState gst) st
709− PR.Partial 0 pst1 ->
710− return $ Skip $ ParseChunksStream s [] pst1
711− PR.Partial n pst1 -> do
712− assert (n <= length (x:buf)) (return ())
713− let src0 = Prelude.take n (x:buf)
714− src = Prelude.reverse src0
715− return $ Skip $ ParseChunksBuf src s [] pst1
716− PR.Continue 0 pst1 ->
717− return $ Skip $ ParseChunksStream s (x:buf) pst1
718− PR.Continue n pst1 -> do
719− assert (n <= length (x:buf)) (return ())
720− let (src0, buf1) = splitAt n (x:buf)
721− src = Prelude.reverse src0
722− return $ Skip $ ParseChunksBuf src s buf1 pst1
725− ParseChunksYield b (ParseChunksInit [] s)
727− assert (n <= length (x:buf)) (return ())
728− let src = Prelude.reverse (Prelude.take n (x:buf))
730− ParseChunksYield b (ParseChunksInit src s)
731− PR.Error err -> throwM $ ParseError err
732− Skip s -> return $ Skip $ ParseChunksStream s buf pst
735− let src = Prelude.reverse buf
737− ParseChunksYield b (ParseChunksInitLeftOver src)
739− -- go back to stream processing mode
740− stepOuter _ (ParseChunksBuf [] s buf pst) =
741− return $ Skip $ ParseChunksStream s buf pst
743− -- buffered processing loop
744− stepOuter _ (ParseChunksBuf (x:xs) s buf pst) = do
747− PR.Partial 0 pst1 ->
748− return $ Skip $ ParseChunksBuf xs s [] pst1
749− PR.Partial n pst1 -> do
750− assert (n <= length (x:buf)) (return ())
751− let src0 = Prelude.take n (x:buf)
752− src = Prelude.reverse src0 ++ xs
753− return $ Skip $ ParseChunksBuf src s [] pst1
754− PR.Continue 0 pst1 ->
755− return $ Skip $ ParseChunksBuf xs s (x:buf) pst1
756− PR.Continue n pst1 -> do
757− assert (n <= length (x:buf)) (return ())
758− let (src0, buf1) = splitAt n (x:buf)
759− src = Prelude.reverse src0 ++ xs
760− return $ Skip $ ParseChunksBuf src s buf1 pst1
762− return $ Skip $ ParseChunksYield b (ParseChunksInit xs s)
764− assert (n <= length (x:buf)) (return ())
765− let src = Prelude.reverse (Prelude.take n (x:buf)) ++ xs
766− return $ Skip $ ParseChunksYield b (ParseChunksInit src s)
767− PR.Error err -> throwM $ ParseError err
769− stepOuter _ (ParseChunksYield a next) = return $ Yield a next
771−{-# ANN type ConcatParseState Fuse #-}
772−data ConcatParseState x inpBuf st p =
773− ConcatParseInit inpBuf st p
774− | ConcatParseInitLeftOver inpBuf
775− | ConcatParseStream st inpBuf p
776− | ConcatParseBuf inpBuf st inpBuf p
777− | ConcatParseYield x (ConcatParseState x inpBuf st p)
779−{-# INLINE_NORMAL parseIterate #-}
782− => (b -> PRD.Parser m a b)
786−parseIterate func seed (Stream step state) =
787− Stream stepOuter (ConcatParseInit [] state (func seed))
791− {-# INLINE_LATE stepOuter #-}
792− -- Buffer is empty, go to stream processing loop
793− stepOuter _ (ConcatParseInit [] st (PRD.Parser pstep initial extract)) = do
794− initial >>= \r -> return $ Skip $ ConcatParseStream st []
795− (PRD.Parser pstep (return r) extract)
797− -- Buffer is not empty, go to buffered processing loop
798− stepOuter _ (ConcatParseInit src st
799− (PRD.Parser pstep initial extract)) = do
800− initial >>= \r -> return $ Skip $ ConcatParseBuf src st []
801− (PRD.Parser pstep (return r) extract)
803− -- XXX we just discard any leftover input at the end
804− stepOuter _ (ConcatParseInitLeftOver _) = return Stop
806− -- Buffer is empty process elements from the stream
807− stepOuter gst (ConcatParseStream st buf
808− p@(PRD.Parser pstep initial extract)) = do
809− r <- step (adaptState gst) st
815− PR.Partial 0 pst1 ->
816− return $ Skip $ ConcatParseStream s []
817− (PRD.Parser pstep (return pst1) extract)
818− PR.Partial n pst1 -> do
819− assert (n <= length (x:buf)) (return ())
820− let src0 = Prelude.take n (x:buf)
821− src = Prelude.reverse src0
822− return $ Skip $ ConcatParseBuf src s []
823− (PRD.Parser pstep (return pst1) extract)
824− -- PR.Continue 0 pst1 ->
825− -- return $ Skip $ ConcatParseStream s (x:buf) pst1
826− PR.Continue n pst1 -> do
827− assert (n <= length (x:buf)) (return ())
828− let (src0, buf1) = splitAt n (x:buf)
829− src = Prelude.reverse src0
830− return $ Skip $ ConcatParseBuf src s buf1
831− (PRD.Parser pstep (return pst1) extract)
832− -- XXX Specialize for Stop 0 common case?
834− assert (n <= length (x:buf)) (return ())
835− let src = Prelude.reverse (Prelude.take n (x:buf))
837− ConcatParseYield b (ConcatParseInit src s (func b))
838− PR.Error err -> throwM $ ParseError err
839− Skip s -> return $ Skip $ ConcatParseStream s buf p
843− let src = Prelude.reverse buf
845− ConcatParseYield b (ConcatParseInitLeftOver src)
847− -- go back to stream processing mode
848− stepOuter _ (ConcatParseBuf [] s buf p) =
849− return $ Skip $ ConcatParseStream s buf p
851− -- buffered processing loop
852− stepOuter _ (ConcatParseBuf (x:xs) s buf
853− (PRD.Parser pstep initial extract)) = do
857− PR.Partial 0 pst1 ->
858− return $ Skip $ ConcatParseBuf xs s []
859− (PRD.Parser pstep (return pst1) extract)
860− PR.Partial n pst1 -> do
861− assert (n <= length (x:buf)) (return ())
862− let src0 = Prelude.take n (x:buf)
863− src = Prelude.reverse src0 ++ xs
864− return $ Skip $ ConcatParseBuf src s []
865− (PRD.Parser pstep (return pst1) extract)
866− -- PR.Continue 0 pst1 -> return $ Skip $ ConcatParseBuf xs s (x:buf) pst1
867− PR.Continue n pst1 -> do
868− assert (n <= length (x:buf)) (return ())
869− let (src0, buf1) = splitAt n (x:buf)
870− src = Prelude.reverse src0 ++ xs
871− return $ Skip $ ConcatParseBuf src s buf1
872− (PRD.Parser pstep (return pst1) extract)
873− -- XXX Specialize for Stop 0 common case?
875− assert (n <= length (x:buf)) (return ())
876− let src = Prelude.reverse (Prelude.take n (x:buf)) ++ xs
877− return $ Skip $ ConcatParseYield b
878− (ConcatParseInit src s (func b))
879− PR.Error err -> throwM $ ParseError err
881− stepOuter _ (ConcatParseYield a next) = return $ Yield a next
883−------------------------------------------------------------------------------
885−------------------------------------------------------------------------------
887−-- | Run a streaming composition, discard the results.
888−{-# INLINE_LATE drain #-}
889−drain :: Monad m => Stream m a -> m ()
890−-- drain = foldrM (\_ xs -> xs) (return ())
891−drain (Stream step state) = go SPEC state
894− r <- step defState st
896− Yield _ s -> go SPEC s
900−{-# INLINE_NORMAL null #-}
901−null :: Monad m => Stream m a -> m Bool
902−null m = foldrM (\_ _ -> return False) (return True) m
904−{-# INLINE_NORMAL head #-}
905−head :: Monad m => Stream m a -> m (Maybe a)
906−head m = foldrM (\x _ -> return (Just x)) (return Nothing) m
908−{-# INLINE_NORMAL headElse #-}
909−headElse :: Monad m => a -> Stream m a -> m a
910−headElse a m = foldrM (\x _ -> return x) (return a) m
912−-- Does not fuse, has the same performance as the StreamK version.
913−{-# INLINE_NORMAL tail #-}
914−tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
915−tail (UnStream step state) = go state
918− r <- step defState st
920− Yield _ s -> return (Just $ Stream step s)
922− Stop -> return Nothing
924−-- XXX will it fuse? need custom impl?
925−{-# INLINE_NORMAL last #-}
926−last :: Monad m => Stream m a -> m (Maybe a)
927−last = foldl' (\_ y -> Just y) Nothing
929−{-# INLINE_NORMAL elem #-}
930−elem :: (Monad m, Eq a) => a -> Stream m a -> m Bool
931−-- elem e m = foldrM (\x xs -> if x == e then return True else xs) (return False) m
932−elem e (Stream step state) = go state
935− r <- step defState st
938− | x == e -> return True
941− Stop -> return False
943−{-# INLINE_NORMAL notElem #-}
944−notElem :: (Monad m, Eq a) => a -> Stream m a -> m Bool
945−notElem e s = fmap not (elem e s)
947−{-# INLINE_NORMAL all #-}
948−all :: Monad m => (a -> Bool) -> Stream m a -> m Bool
949−-- all p m = foldrM (\x xs -> if p x then xs else return False) (return True) m
950−all p (Stream step state) = go state
953− r <- step defState st
957− | otherwise -> return False
961−{-# INLINE_NORMAL any #-}
962−any :: Monad m => (a -> Bool) -> Stream m a -> m Bool
963−-- any p m = foldrM (\x xs -> if p x then return True else xs) (return False) m
964−any p (Stream step state) = go state
967− r <- step defState st
970− | p x -> return True
973− Stop -> return False
975−{-# INLINE_NORMAL maximum #-}
976−maximum :: (Monad m, Ord a) => Stream m a -> m (Maybe a)
977−maximum (Stream step state) = go Nothing state
980− r <- step defState st
982− Yield x s -> go (Just x) s
983− Skip s -> go Nothing s
984− Stop -> return Nothing
985− go (Just acc) st = do
986− r <- step defState st
989− | acc <= x -> go (Just x) s
990− | otherwise -> go (Just acc) s
991− Skip s -> go (Just acc) s
992− Stop -> return (Just acc)
994−{-# INLINE_NORMAL maximumBy #-}
995−maximumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
996−maximumBy cmp (Stream step state) = go Nothing state
999− r <- step defState st
1001− Yield x s -> go (Just x) s
1002− Skip s -> go Nothing s
1003− Stop -> return Nothing
1004− go (Just acc) st = do
1005− r <- step defState st
1007− Yield x s -> case cmp acc x of
1008− GT -> go (Just acc) s
1010− Skip s -> go (Just acc) s
1011− Stop -> return (Just acc)
1013−{-# INLINE_NORMAL minimum #-}
1014−minimum :: (Monad m, Ord a) => Stream m a -> m (Maybe a)
1015−minimum (Stream step state) = go Nothing state
1018− r <- step defState st
1020− Yield x s -> go (Just x) s
1021− Skip s -> go Nothing s
1022− Stop -> return Nothing
1023− go (Just acc) st = do
1024− r <- step defState st
1027− | acc <= x -> go (Just acc) s
1028− | otherwise -> go (Just x) s
1029− Skip s -> go (Just acc) s
1030− Stop -> return (Just acc)
1032−{-# INLINE_NORMAL minimumBy #-}
1033−minimumBy :: Monad m => (a -> a -> Ordering) -> Stream m a -> m (Maybe a)
1034−minimumBy cmp (Stream step state) = go Nothing state
1037− r <- step defState st
1039− Yield x s -> go (Just x) s
1040− Skip s -> go Nothing s
1041− Stop -> return Nothing
1042− go (Just acc) st = do
1043− r <- step defState st
1045− Yield x s -> case cmp acc x of
1046− GT -> go (Just x) s
1047− _ -> go (Just acc) s
1048− Skip s -> go (Just acc) s
1049− Stop -> return (Just acc)
1051−{-# INLINE_NORMAL (!!) #-}
1052−(!!) :: (Monad m) => Stream m a -> Int -> m (Maybe a)
1053−(Stream step state) !! i = go i state
1056− r <- step defState st
1058− Yield x s | n < 0 -> return Nothing
1059− | n == 0 -> return $ Just x
1060− | otherwise -> go (n - 1) s
1062− Stop -> return Nothing
1064−{-# INLINE_NORMAL lookup #-}
1065−lookup :: (Monad m, Eq a) => a -> Stream m (a, b) -> m (Maybe b)
1066−lookup e m = foldrM (\(a, b) xs -> if e == a then return (Just b) else xs)
1069−{-# INLINE_NORMAL findM #-}
1070−findM :: Monad m => (a -> m Bool) -> Stream m a -> m (Maybe a)
1071−findM p m = foldrM (\x xs -> p x >>= \r -> if r then return (Just x) else xs)
1075−find :: Monad m => (a -> Bool) -> Stream m a -> m (Maybe a)
1076−find p = findM (return . p)
1078−{-# INLINE_NORMAL findIndices #-}
1079−findIndices :: Monad m => (a -> Bool) -> Stream m a -> Stream m Int
1080−findIndices p (Stream step state) = Stream step' (state, 0)
1082− {-# INLINE_LATE step' #-}
1083− step' gst (st, i) = i `seq` do
1084− r <- step (adaptState gst) st
1086− Yield x s -> if p x then Yield i (s, i+1) else Skip (s, i+1)
1087− Skip s -> Skip (s, i)
1090−{-# INLINE toListRev #-}
1091−toListRev :: Monad m => Stream m a -> m [a]
1092−toListRev = foldl' (flip (:)) []
1094−-- We can implement reverse as:
1096−-- > reverse = foldlS (flip cons) nil
1098−-- However, this implementation is unusable because of the horrible performance
1099−-- of cons. So we just convert it to a list first and then stream from the
1102−-- XXX Maybe we can use an Array instead of a list here?
1103−{-# INLINE_NORMAL reverse #-}
1104−reverse :: Monad m => Stream m a -> Stream m a
1105−reverse m = Stream step Nothing
1107− {-# INLINE_LATE step #-}
1108− step _ Nothing = do
1110− return $ Skip (Just xs)
1111− step _ (Just (x:xs)) = return $ Yield x (Just xs)
1112− step _ (Just []) = return Stop
1114−-- Much faster reverse for Storables
1115−{-# INLINE_NORMAL reverse' #-}
1116−reverse' :: forall m a. (MonadIO m, Storable a) => Stream m a -> Stream m a
1118−-- This commented implementation copies the whole stream into one single array
1119−-- and then streams from that array, this is 3-4x faster than the chunked code
1120−-- that follows. Though this could be problematic due to unbounded large
1121−-- allocations. We need to figure out why the chunked code is slower and if we
1122−-- can optimize the chunked code to work as fast as this one. It may be a
1124−import Foreign.ForeignPtr (touchForeignPtr)
1125−import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
1126−import Foreign.Ptr (Ptr, plusPtr)
1127−reverse' m = Stream step Nothing
1129− {-# INLINE_LATE step #-}
1130− step _ Nothing = do
1131− arr <- A.fromStreamD m
1132− let p = aEnd arr `plusPtr` negate (sizeOf (undefined :: a))
1133− return $ Skip $ Just (aStart arr, p)
1135− step _ (Just (start, p)) | p < unsafeForeignPtrToPtr start = return Stop
1137− step _ (Just (start, p)) = do
1138− let !x = A.unsafeInlineIO $ do
1140− touchForeignPtr start
1142− next = p `plusPtr` negate (sizeOf (undefined :: a))
1143− return $ Yield x (Just (start, next))
1150− $ A.fromStreamDArraysOf A.defaultChunkSize m
1152------------------------------------------------------------------------------
525------------------------------------------------------------------------------
1153-- Substreams
526-- Substreams
1154------------------------------------------------------------------------------
527------------------------------------------------------------------------------
@@ -2671,168 +2044,6 @@ rollingMapM f (Stream step1 state1) = Stream step (RollingMapInit state1)
2671rollingMap :: Monad m => (a -> a -> b) -> Stream m a -> Stream m b
2044rollingMap :: Monad m => (a -> a -> b) -> Stream m a -> Stream m b
2672rollingMap f = rollingMapM (\x y -> return $ f x y)
2045rollingMap f = rollingMapM (\x y -> return $ f x y)
2674−------------------------------------------------------------------------------
2675−-- Tapping/Distributing
2676−------------------------------------------------------------------------------
2678−data TapState fs st a
2679− = TapInit | Tapping !fs st | TapDone st
2681−-- XXX Multiple yield points
2683−tap :: Monad m => Fold m a b -> Stream m a -> Stream m a
2684−tap (Fold fstep initial extract) (Stream step state) = Stream step' TapInit
2688− step' _ TapInit = do
2690− return $ Skip (Tapping r state)
2691− step' gst (Tapping acc st) = do
2699− FL.Partial fs -> Tapping fs s
2700− FL.Done _ -> TapDone s
2701− Skip s -> return $ Skip (Tapping acc s)
2705− step' gst (TapDone st) = do
2709− Yield x s -> Yield x (TapDone s)
2710− Skip s -> Skip (TapDone s)
2713−data TapOffState fs s a
2715− | TapOffTapping !fs s Int
2718−-- XXX Multiple yield points
2719−{-# INLINE_NORMAL tapOffsetEvery #-}
2720−tapOffsetEvery :: Monad m
2721− => Int -> Int -> Fold m a b -> Stream m a -> Stream m a
2722−tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
2723− Stream step' TapOffInit
2727− {-# INLINE_LATE step' #-}
2728− step' _ TapOffInit = do
2730− return $ Skip $ TapOffTapping r state (offset `mod` n)
2731− step' gst (TapOffTapping acc st count) = do
2742− TapOffTapping sres s (n - 1)
2743− FL.Done _ -> TapOffDone s
2744− else return $ TapOffTapping acc s (count - 1)
2745− return $ Yield x next
2746− Skip s -> return $ Skip (TapOffTapping acc s count)
2750− step' gst (TapOffDone st) = do
2754− Yield x s -> Yield x (TapOffDone s)
2755− Skip s -> Skip (TapOffDone s)
2758−{-# INLINE_NORMAL pollCounts #-}
2762− -> (Stream m Int -> Stream m Int)
2766−pollCounts predicate transf fld (Stream step state) = Stream step' Nothing
2769− {-# INLINE_LATE step' #-}
2770− step' _ Nothing = do
2771− -- As long as we are using an "Int" for counts lockfree reads from
2772− -- Var should work correctly on both 32-bit and 64-bit machines.
2773− -- However, an Int on a 32-bit machine may overflow quickly.
2774− countVar <- liftIO $ Prim.newIORef (0 :: Int)
2776− $ void $ foldOnce fld
2777− $ transf $ fromPrimIORef countVar
2778− return $ Skip (Just (countVar, tid, state))
2780− step' gst (Just (countVar, tid, st)) = do
2784− when (predicate x) $ liftIO $ Prim.modifyIORef' countVar (+ 1)
2785− return $ Yield x (Just (countVar, tid, s))
2786− Skip s -> return $ Skip (Just (countVar, tid, s))
2788− liftIO $ killThread tid
2791−{-# INLINE_NORMAL tapRate #-}
2793− (MonadAsync m, MonadCatch m)
2798−tapRate samplingRate action (Stream step state) = Stream step' Nothing
2800− {-# NOINLINE loop #-}
2801− loop countVar prev = do
2804− (do liftIO $ threadDelay (round $ samplingRate * 1000000)
2805− i <- liftIO $ Prim.readIORef countVar
2806− let !diff = i - prev
2809− (\(e :: AsyncException) -> do
2810− i <- liftIO $ Prim.readIORef countVar
2811− let !diff = i - prev
2813− throwM (MC.toException e))
2816− {-# INLINE_LATE step' #-}
2817− step' _ Nothing = do
2818− countVar <- liftIO $ Prim.newIORef 0
2819− tid <- fork $ loop countVar 0
2820− ref <- liftIO $ newIORef ()
2821− _ <- liftIO $ mkWeakIORef ref (killThread tid)
2822− return $ Skip (Just (countVar, tid, state, ref))
2824− step' gst (Just (countVar, tid, st, ref)) = do
2828− liftIO $ Prim.modifyIORef' countVar (+ 1)
2829− return $ Yield x (Just (countVar, tid, s, ref))
2830− Skip s -> return $ Skip (Just (countVar, tid, s, ref))
2832− liftIO $ killThread tid
2836-------------------------------------------------------------------------------
2047-------------------------------------------------------------------------------
2837-- Filtering
2048-- Filtering
2838-------------------------------------------------------------------------------
2049-------------------------------------------------------------------------------
@@ -3279,97 +2490,10 @@ the (Stream step state) = go state
3279 Skip s -> go' n s
2490 Skip s -> go' n s
3280 Stop -> return (Just n)
2491 Stop -> return (Just n)
3282−{-# INLINE_NORMAL foldOnce #-}
3283−foldOnce :: (Monad m) => Fold m a b -> Stream m a -> m b
3284−foldOnce (Fold fstep begin done) (Stream step state) =
3285− begin >>= \x -> go SPEC x state
3291− r <- step defState st
3296− FL.Done b -> return b
3297− FL.Partial fs1 -> go SPEC fs1 s
3298− Skip s -> go SPEC fs s
3301-------------------------------------------------------------------------------
2493-------------------------------------------------------------------------------
3302-- Concurrent application and fold
2494-- Concurrent application and fold
3303-------------------------------------------------------------------------------
2495-------------------------------------------------------------------------------
3305−-- XXX These functions should be moved to Stream/Parallel.hs
3307−-- Using StreamD the worker stream producing code can fuse with the code to
3308−-- queue output to the SVar giving some perf boost.
3310−-- Note that StreamD can only be used in limited situations, specifically, we
3311−-- cannot implement joinStreamVarPar using this.
3313−-- XXX make sure that the SVar passed is a Parallel style SVar.
3315−-- | Fold the supplied stream to the SVar asynchronously using Parallel
3316−-- concurrency style.
3317−-- {-# INLINE_NORMAL toSVarParallel #-}
3318−{-# INLINE toSVarParallel #-}
3319−toSVarParallel :: MonadAsync m
3320− => State t m a -> SVar t m a -> Stream m a -> m ()
3321−toSVarParallel st sv xs =
3322− if svarInspectMode sv
3326− case getYieldLimit st of
3327− Nothing -> doFork (work Nothing)
3329− (handleChildException sv)
3330− Just _ -> doFork (workLim Nothing)
3332− (handleChildException sv)
3333− modifyThread sv tid
3337− {-# NOINLINE work #-}
3338− work info = (foldOnce (FL.toParallelSVar sv info) xs)
3340− {-# NOINLINE workLim #-}
3341− workLim info = foldOnce (FL.toParallelSVarLimited sv info) xs
3343− {-# NOINLINE forkWithDiag #-}
3345− -- We do not use workerCount in case of ParallelVar but still there is
3346− -- no harm in maintaining it correctly.
3347− liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
3348− recordMaxWorkers sv
3349− -- This allocation matters when significant number of workers are being
3350− -- sent. We allocate it only when needed. The overhead increases by 4x.
3352− case yieldRateInfo sv of
3353− Nothing -> return Nothing
3354− Just _ -> liftIO $ do
3355− cntRef <- newIORef 0
3356− t <- getTime Monotonic
3357− lat <- newIORef (0, t)
3358− return $ Just WorkerInfo
3359− { workerYieldMax = 0
3360− , workerYieldCount = cntRef
3361− , workerLatencyStart = lat
3364− case getYieldLimit st of
3365− Nothing -> doFork (work winfo)
3367− (handleChildException sv)
3368− Just _ -> doFork (workLim winfo)
3370− (handleChildException sv)
3371− modifyThread sv tid
3373{-# INLINE_NORMAL mkParallelD #-}
2497{-# INLINE_NORMAL mkParallelD #-}
3374mkParallelD :: MonadAsync m => Stream m a -> Stream m a
2498mkParallelD :: MonadAsync m => Stream m a -> Stream m a
3375mkParallelD m = Stream step Nothing
2499mkParallelD m = Stream step Nothing
@@ -3429,75 +2553,6 @@ newCallbackStream = do
3429 -- SVar?
2553 -- SVar?
3430 return (callback, fromStreamD (fromSVar sv))
2554 return (callback, fromStreamD (fromSVar sv))
3432−-------------------------------------------------------------------------------
3434−-------------------------------------------------------------------------------
3436−-- | Create an SVar with a fold consumer that will fold any elements sent to it
3437−-- using the supplied fold function.
3438−{-# INLINE newFoldSVar #-}
3439−newFoldSVar :: MonadAsync m => State t m a -> Fold m a b -> m (SVar t m a)
3440−newFoldSVar stt f = do
3441− -- Buffer size for the SVar is derived from the current state
3442− sv <- newParallelVar StopAny (adaptState stt)
3443− -- Add the producer thread-id to the SVar.
3444− liftIO myThreadId >>= modifyThread sv
3445− void $ doFork (work sv) (svarMrun sv) (handleFoldException sv)
3450− {-# NOINLINE work #-}
3451− work sv = void $ foldOnce f $ fromProducer sv
3453−{-# INLINE_NORMAL tapAsync #-}
3454−tapAsync :: MonadAsync m => Fold m a b -> Stream m a -> Stream m a
3455−tapAsync f (Stream step1 state1) = Stream step TapInit
3459− -- In general, a Stop event would come equipped with the result
3460− -- of the fold. It is not used here but it would be useful in
3461− -- applicative and distribute.
3462− done <- fromConsumer svr
3463− when (not done) $ do
3464− liftIO $ withDiagMVar svr "teeToSVar: waiting to drain"
3465− $ takeMVar (outputDoorBellFromConsumer svr)
3469− liftIO $ sendStop svr Nothing
3470− -- drain/wait until a stop event arrives from the fold.
3473− {-# INLINE_LATE step #-}
3474− step gst TapInit = do
3475− sv <- newFoldSVar gst f
3476− return $ Skip (Tapping sv state1)
3478− step gst (Tapping sv st) = do
3482− done <- pushToFold sv a
3485− -- XXX we do not need to wait synchronously here
3487− return $ Yield a (TapDone s)
3488− else return $ Yield a (Tapping sv s)
3489− Skip s -> return $ Skip (Tapping sv s)
3494− step gst (TapDone st) = do
3497− Yield a s -> Yield a (TapDone s)
3498− Skip s -> Skip (TapDone s)
3501------------------------------------------------------------------------------
2556------------------------------------------------------------------------------
3502-- Time related
2557-- Time related
3503------------------------------------------------------------------------------
2558------------------------------------------------------------------------------