@@ -76,10 +76,14 @@ module Streamly.Internal.Data.Unfold
76 , singleton
76 , singleton
77 , identity
77 , identity
80 , fromList
81 , fromList
81 , fromListM
82 , fromListM
83 -- ** Specialized Generation
87 -- ** Specialized Generation
84 -- | Generate a monadic stream from a seed.
88 -- | Generate a monadic stream from a seed.
85 , replicateM
89 , replicateM
@@ -92,6 +96,10 @@ module Streamly.Internal.Data.Unfold
92 , enumerateFromToIntegral
96 , enumerateFromToIntegral
93 , enumerateFromIntegral
97 , enumerateFromIntegral
99+ , enumerateFromStepNum
101+ , enumerateFromToFractional
95 -- * Transformations
103 -- * Transformations
@@ -136,22 +144,21 @@ module Streamly.Internal.Data.Unfold
139−import Control.Exception (Exception, mask_)
147+import Control.Exception (Exception, fromException, mask_)
140−import Control.Monad ((>=>))
148+import Control.Monad ((>=>), when)
149+import Control.Monad.Catch (MonadCatch)
141import Control.Monad.IO.Class (MonadIO(..))
150import Control.Monad.IO.Class (MonadIO(..))
142import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
151import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
152+import Data.Maybe (isNothing)
143import Data.Void (Void)
153import Data.Void (Void)
154+import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
144import GHC.Types (SPEC(..))
155import GHC.Types (SPEC(..))
146− hiding (concat, map, mapM, takeWhile, take, filter, const, zipWith
149import Fusion.Plugin.Types (Fuse(..))
156import Fusion.Plugin.Types (Fuse(..))
150import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
157import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
151import Streamly.Internal.Data.Unfold.Types (Unfold(..))
158import Streamly.Internal.Data.Unfold.Types (Unfold(..))
152import Streamly.Internal.Data.Fold.Types (Fold(..))
159import Streamly.Internal.Data.Fold.Types (Fold(..))
153−import Streamly.Internal.Data.SVar (defState, MonadAsync)
160+import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
154−import Control.Monad.Catch (MonadCatch)
161+import System.Mem (performMajorGC)
156import qualified Prelude
163import qualified Prelude
157import qualified Control.Monad.Catch as MC
164import qualified Control.Monad.Catch as MC
@@ -159,6 +166,11 @@ import qualified Data.Tuple as Tuple
159import qualified Streamly.Internal.Data.Stream.StreamK as K
166import qualified Streamly.Internal.Data.Stream.StreamK as K
160import qualified Streamly.Internal.Data.Stream.StreamD as D
167import qualified Streamly.Internal.Data.Stream.StreamD as D
169+import Streamly.Internal.Data.SVar
171+ hiding (concat, map, mapM, takeWhile, take, filter, const, zipWith
162-------------------------------------------------------------------------------
174-------------------------------------------------------------------------------
163-- Input operations
175-- Input operations
164-------------------------------------------------------------------------------
176-------------------------------------------------------------------------------
@@ -457,6 +469,17 @@ fromListM = Unfold step inject
457 step (x:xs) = x >>= \r -> return $ Yield r xs
469 step (x:xs) = x >>= \r -> return $ Yield r xs
458 step [] = return Stop
470 step [] = return Stop
472+{-# INLINE unfoldrM #-}
473+unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> Unfold m a b
474+unfoldrM next = Unfold step return
476+ {-# INLINE_LATE step #-}
480+ Just (x, s) -> Yield x s
460------------------------------------------------------------------------------
483------------------------------------------------------------------------------
461-- Specialized Generation
484-- Specialized Generation
462------------------------------------------------------------------------------
485------------------------------------------------------------------------------
@@ -638,6 +661,146 @@ enumerateFromToIntegral to =
638enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
661enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
639enumerateFromIntegral = enumerateFromToIntegral maxBound
662enumerateFromIntegral = enumerateFromToIntegral maxBound
664+{-# INLINE enumerateFromStepNum #-}
665+enumerateFromStepNum :: (Monad m, Num a) => a -> Unfold m a a
666+enumerateFromStepNum stride = Unfold step return
668+ {-# INLINE_LATE step #-}
669+ step !s = return $ (Yield $! s) $! (s + stride)
671+{-# INLINE_NORMAL numFrom #-}
672+numFrom :: (Monad m, Num a) => Unfold m a a
673+numFrom = enumerateFromStepNum 1
675+{-# INLINE_NORMAL enumerateFromToFractional #-}
676+enumerateFromToFractional :: (Monad m, Fractional a, Ord a) => a -> Unfold m a a
677+enumerateFromToFractional to =
678+ takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
680+-------------------------------------------------------------------------------
681+-- Generation from SVar
682+-------------------------------------------------------------------------------
684+data FromSVarState t m a =
685+ FromSVarInit (SVar t m a)
686+ | FromSVarRead (SVar t m a)
687+ | FromSVarLoop (SVar t m a) [ChildEvent a]
688+ | FromSVarDone (SVar t m a)
690+{-# INLINE_NORMAL fromSVar #-}
691+fromSVar :: MonadAsync m => Unfold m (SVar t m a) a
692+fromSVar = Unfold step (return . FromSVarInit)
695+ {-# INLINE_LATE step #-}
696+ step (FromSVarInit svar) = do
697+ ref <- liftIO $ newIORef ()
698+ _ <- liftIO $ mkWeakIORef ref hook
699+ -- when this copy of svar gets garbage collected "ref" will get
700+ -- garbage collected and our GC hook will be called.
701+ let sv = svar{svarRef = Just ref}
702+ return $ Skip (FromSVarRead sv)
706+ {-# NOINLINE hook #-}
708+ when (svarInspectMode svar) $ do
709+ r <- liftIO $ readIORef (svarStopTime (svarStats svar))
710+ when (isNothing r) $
711+ printSVar svar "SVar Garbage Collected"
713+ -- If there are any SVars referenced by this SVar a GC will prompt
714+ -- them to be cleaned up quickly.
715+ when (svarInspectMode svar) performMajorGC
717+ step (FromSVarRead sv) = do
718+ list <- readOutputQ sv
719+ -- Reversing the output is important to guarantee that we process the
720+ -- outputs in the same order as they were generated by the constituent
722+ return $ Skip $ FromSVarLoop sv (Prelude.reverse list)
724+ step (FromSVarLoop sv []) = do
725+ done <- postProcess sv
726+ return $ Skip $ if done
727+ then FromSVarDone sv
728+ else FromSVarRead sv
730+ step (FromSVarLoop sv (ev : es)) = do
732+ ChildYield a -> return $ Yield a (FromSVarLoop sv es)
733+ ChildStop tid e -> do
734+ accountThread sv tid
737+ stop <- shouldStop tid
740+ liftIO (cleanupSVar sv)
741+ return $ Skip (FromSVarDone sv)
742+ else return $ Skip (FromSVarLoop sv es)
744+ case fromException ex of
746+ return $ Skip (FromSVarLoop sv es)
747+ Nothing -> liftIO (cleanupSVar sv) >> MC.throwM ex
751+ case svarStopStyle sv of
752+ StopNone -> return False
753+ StopAny -> return True
755+ sid <- liftIO $ readIORef (svarStopBy sv)
758+ step (FromSVarDone sv) = do
759+ when (svarInspectMode sv) $ do
760+ t <- liftIO $ getTime Monotonic
761+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
762+ liftIO $ printSVar sv "SVar Done"
765+-------------------------------------------------------------------------------
766+-- Process events received by a fold consumer from a stream producer
767+-------------------------------------------------------------------------------
769+-- XXX Why don't we do the same thing for "FromSVarInit" that we did in "fromSVar"?
770+{-# INLINE_NORMAL fromProducer #-}
771+fromProducer :: MonadAsync m => Unfold m (SVar t m a) a
772+fromProducer = Unfold step (return . FromSVarRead)
775+ {-# INLINE_LATE step #-}
776+ step (FromSVarRead sv) = do
777+ list <- readOutputQ sv
778+ -- Reversing the output is important to guarantee that we process the
779+ -- outputs in the same order as they were generated by the constituent
781+ return $ Skip $ FromSVarLoop sv (Prelude.reverse list)
783+ step (FromSVarLoop sv []) = return $ Skip $ FromSVarRead sv
784+ step (FromSVarLoop sv (ev : es)) = do
786+ ChildYield a -> return $ Yield a (FromSVarLoop sv es)
787+ ChildStop tid e -> do
788+ accountThread sv tid
791+ sendStopToProducer sv
792+ return $ Skip (FromSVarDone sv)
793+ Just _ -> error "Bug: fromProducer: received exception"
795+ step (FromSVarDone sv) = do
796+ when (svarInspectMode sv) $ do
797+ t <- liftIO $ getTime Monotonic
798+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
799+ liftIO $ printSVar sv "SVar Done"
802+ step (FromSVarInit _) = undefined
641-------------------------------------------------------------------------------
804-------------------------------------------------------------------------------
642-- Zipping
805-- Zipping
643-------------------------------------------------------------------------------
806-------------------------------------------------------------------------------