@@ -141,6 +141,7 @@ module Streamly.Internal.Data.Unfold
141 , iterateM
141 , iterateM
143 -- ** Enumerations
143 -- ** Enumerations
144 -- *** Enumerate Num
145 -- *** Enumerate Num
145 , enumerateFromStepNum
146 , enumerateFromStepNum
146 , numFrom
147 , numFrom
@@ -229,12 +230,14 @@ module Streamly.Internal.Data.Unfold
232−import Control.Exception (Exception, mask_)
233+import Control.Exception (Exception, fromException, mask_)
233−import Control.Monad ((>=>))
234+import Control.Monad ((>=>), when)
234import Control.Monad.Catch (MonadCatch)
235import Control.Monad.Catch (MonadCatch)
235import Control.Monad.IO.Class (MonadIO(..))
236import Control.Monad.IO.Class (MonadIO(..))
236import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
237import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
237−import Data.Void (Void)
238+import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
240+import Data.Maybe (isNothing)
238import GHC.Types (SPEC(..))
241import GHC.Types (SPEC(..))
239import Streamly.Internal.Control.Concurrent (MonadAsync)
242import Streamly.Internal.Control.Concurrent (MonadAsync)
240import Streamly.Internal.Data.Fold.Type (Fold(..))
243import Streamly.Internal.Data.Fold.Type (Fold(..))
@@ -243,7 +246,6 @@ import Streamly.Internal.Data.IOFinalizer
243import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
246import Streamly.Internal.Data.Stream.StreamD.Type (Stream(..), Step(..))
244import Streamly.Internal.Data.SVar.Type (defState)
247import Streamly.Internal.Data.SVar.Type (defState)
246−import qualified Prelude
247import qualified Control.Monad.Catch as MC
249import qualified Control.Monad.Catch as MC
248import qualified Data.Tuple as Tuple
250import qualified Data.Tuple as Tuple
249import qualified Streamly.Internal.Data.Fold.Type as FL
251import qualified Streamly.Internal.Data.Fold.Type as FL
@@ -252,6 +254,7 @@ import qualified Streamly.Internal.Data.Stream.StreamK as K (uncons)
252import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
254import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
254import Streamly.Internal.Data.Unfold.Type
256import Streamly.Internal.Data.Unfold.Type
257+import Streamly.Internal.Data.Unfold.Enumeration
255import Prelude
258import Prelude
256 hiding (map, mapM, takeWhile, take, filter, const, zipWith
259 hiding (map, mapM, takeWhile, take, filter, const, zipWith
257 , drop, dropWhile, either)
260 , drop, dropWhile, either)
@@ -261,60 +264,6 @@ import Prelude
261-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
264-- >>> import qualified Streamly.Internal.Data.Unfold as Unfold
262-- >>> import qualified Streamly.Prelude as Stream
265-- >>> import qualified Streamly.Prelude as Stream
264−-------------------------------------------------------------------------------
266−-------------------------------------------------------------------------------
268−-- | Map an action on the input argument of the 'Unfold'.
271−-- lmapM f = Unfold.many (Unfold.functionM f)
275−{-# INLINE_NORMAL lmapM #-}
276−lmapM :: Monad m => (a -> m c) -> Unfold m c b -> Unfold m a b
277−lmapM f (Unfold ustep uinject) = Unfold ustep (f >=> uinject)
279−-- | Supply the seed to an unfold closing the input end of the unfold.
282−-- supply a = Unfold.lmap (Prelude.const a)
287−{-# INLINE_NORMAL supply #-}
288−supply :: a -> Unfold m a b -> Unfold m Void b
289−supply a = lmap (Prelude.const a)
291−-- | Supply the first component of the tuple to an unfold that accepts a tuple
292−-- as a seed resulting in a fold that accepts the second component of the tuple
296−-- supplyFirst a = Unfold.lmap (a, )
301−{-# INLINE_NORMAL supplyFirst #-}
302−supplyFirst :: a -> Unfold m (a, b) c -> Unfold m b c
303−supplyFirst a = lmap (a, )
305−-- | Supply the second component of the tuple to an unfold that accepts a tuple
306−-- as a seed resulting in a fold that accepts the first component of the tuple
310−-- supplySecond b = Unfold.lmap (, b)
315−{-# INLINE_NORMAL supplySecond #-}
316−supplySecond :: b -> Unfold m (a, b) c -> Unfold m a c
317−supplySecond b = lmap (, b)
319-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
268-- | Convert an 'Unfold' into an unfold accepting a tuple as an argument,
320-- using the argument of the original fold as the second element of tuple and
269-- using the argument of the original fold as the second element of tuple and
@@ -683,33 +632,6 @@ take n (Unfold step1 inject1) = Unfold step inject
683 Stop -> Stop
632 Stop -> Stop
684 step (_, _) = return Stop
633 step (_, _) = return Stop
686−-- | Same as 'takeWhile' but with a monadic predicate.
690−{-# INLINE_NORMAL takeWhileM #-}
691−takeWhileM :: Monad m => (b -> m Bool) -> Unfold m a b -> Unfold m a b
692−takeWhileM f (Unfold step1 inject1) = Unfold step inject1
694− {-# INLINE_LATE step #-}
700− return $ if b then Yield x s else Stop
701− Skip s -> return $ Skip s
704−-- | End the stream generated by the 'Unfold' as soon as the predicate fails
709−{-# INLINE takeWhile #-}
710−takeWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
711−takeWhile f = takeWhileM (return . f)
713-- | Same as 'filter' but with a monadic predicate.
635-- | Same as 'filter' but with a monadic predicate.
715-- /Since: 0.8.0/
637-- /Since: 0.8.0/
@@ -810,74 +732,134 @@ dropWhileM f (Unfold step inject) = Unfold step' inject'
810dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
732dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
811dropWhile f = dropWhileM (return . f)
733dropWhile f = dropWhileM (return . f)
813−------------------------------------------------------------------------------
735+-------------------------------------------------------------------------------
814−-- Enumeration of Num
736+-- Generation from SVar
815−------------------------------------------------------------------------------
737+-------------------------------------------------------------------------------
817−-- | Generate an infinite stream starting from a starting value with increments
818−-- of the given stride. The implementation is numerically stable for floating
821−-- Note 'enumerateFromStepIntegral' is faster for integrals.
825−{-# INLINE enumerateFromStepNum #-}
826−enumerateFromStepNum :: (Monad m, Num a) => a -> Unfold m a a
827−enumerateFromStepNum stride = Unfold step inject
831− inject !from = return (from, 0)
833− {-# INLINE_LATE step #-}
739+data FromSVarState t m a =
834− step (from, !i) = return $ (Yield $! (from + i * stride)) $! (from, i + 1)
740+ FromSVarInit (SVar t m a)
741+ | FromSVarRead (SVar t m a)
742+ | FromSVarLoop (SVar t m a) [ChildEvent a]
743+ | FromSVarDone (SVar t m a)
836−-- | @numFrom = enumerateFromStepNum 1@
745+-- | /Internal/
840−{-# INLINE_NORMAL numFrom #-}
747+{-# INLINE_NORMAL fromSVar #-}
841−numFrom :: (Monad m, Num a) => Unfold m a a
748+fromSVar :: MonadAsync m => Unfold m (SVar t m a) a
842−numFrom = enumerateFromStepNum 1
749+fromSVar = Unfold step (return . FromSVarInit)
844−------------------------------------------------------------------------------
845−-- Enumeration of Integrals
846−------------------------------------------------------------------------------
848−-- | Can be used to enumerate unbounded integrals. This does not check for
849−-- overflow or underflow for bounded integrals.
850−{-# INLINE_NORMAL enumerateFromStepIntegral #-}
851−enumerateFromStepIntegral :: (Integral a, Monad m) => Unfold m (a, a) a
852−enumerateFromStepIntegral = Unfold step inject
854− inject (from, stride) = from `seq` stride `seq` return (from, stride)
855− {-# INLINE_LATE step #-}
856− step (x, stride) = return $ Yield x $! (x + stride, stride)
858−-- We are assuming that "to" is constrained by the type to be within
860−{-# INLINE enumerateFromToIntegral #-}
861−enumerateFromToIntegral :: (Monad m, Integral a) => a -> Unfold m a a
862−enumerateFromToIntegral to =
863− takeWhile (<= to) $ supplySecond 1 enumerateFromStepIntegral
865−{-# INLINE enumerateFromIntegral #-}
752+ {-# INLINE_LATE step #-}
866−enumerateFromIntegral :: (Monad m, Integral a, Bounded a) => Unfold m a a
753+ step (FromSVarInit svar) = do
867−enumerateFromIntegral = enumerateFromToIntegral maxBound
754+ ref <- liftIO $ newIORef ()
755+ _ <- liftIO $ mkWeakIORef ref hook
756+ -- when this copy of svar gets garbage collected "ref" will get
757+ -- garbage collected and our GC hook will be called.
758+ let sv = svar{svarRef = Just ref}
759+ return $ Skip (FromSVarRead sv)
763+ {-# NOINLINE hook #-}
765+ when (svarInspectMode svar) $ do
766+ r <- liftIO $ readIORef (svarStopTime (svarStats svar))
767+ when (isNothing r) $
768+ printSVar svar "SVar Garbage Collected"
770+ -- If there are any SVars referenced by this SVar a GC will prompt
771+ -- them to be cleaned up quickly.
772+ when (svarInspectMode svar) performMajorGC
774+ step (FromSVarRead sv) = do
775+ list <- readOutputQ sv
776+ -- Reversing the output is important to guarantee that we process the
777+ -- outputs in the same order as they were generated by the constituent
779+ return $ Skip $ FromSVarLoop sv (Prelude.reverse list)
781+ step (FromSVarLoop sv []) = do
782+ done <- postProcess sv
783+ return $ Skip $ if done
784+ then FromSVarDone sv
785+ else FromSVarRead sv
787+ step (FromSVarLoop sv (ev : es)) = do
789+ ChildYield a -> return $ Yield a (FromSVarLoop sv es)
790+ ChildStop tid e -> do
791+ accountThread sv tid
794+ stop <- shouldStop tid
797+ liftIO (cleanupSVar sv)
798+ return $ Skip (FromSVarDone sv)
799+ else return $ Skip (FromSVarLoop sv es)
801+ case fromException ex of
803+ return $ Skip (FromSVarLoop sv es)
804+ Nothing -> liftIO (cleanupSVar sv) >> MC.throwM ex
808+ case svarStopStyle sv of
809+ StopNone -> return False
810+ StopAny -> return True
812+ sid <- liftIO $ readIORef (svarStopBy sv)
815+ step (FromSVarDone sv) = do
816+ when (svarInspectMode sv) $ do
817+ t <- liftIO $ getTime Monotonic
818+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
819+ liftIO $ printSVar sv "SVar Done"
869−------------------------------------------------------------------------------
822+-------------------------------------------------------------------------------
870−-- Enumeration of Fractionals
823+-- Process events received by a fold consumer from a stream producer
871−------------------------------------------------------------------------------
824+-------------------------------------------------------------------------------
826+-- XXX Have an error for "FromSVarInit" instead of undefined. The error can
827+-- redirect the user to report the failure to the developers.
873-- | /Internal/
828-- | /Internal/
875−-- > enumerateFromToFractional to = takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
877−{-# INLINE_NORMAL enumerateFromToFractional #-}
830+{-# INLINE_NORMAL fromProducer #-}
878−enumerateFromToFractional :: (Monad m, Fractional a, Ord a) => a -> Unfold m a a
831+fromProducer :: MonadAsync m => Unfold m (SVar t m a) a
879−enumerateFromToFractional to =
832+fromProducer = Unfold step (return . FromSVarRead)
880− takeWhile (<= to + 1 / 2) $ enumerateFromStepNum 1
833+ where
835+ {-# INLINE_LATE step #-}
836+ step (FromSVarRead sv) = do
837+ list <- readOutputQ sv
838+ -- Reversing the output is important to guarantee that we process the
839+ -- outputs in the same order as they were generated by the constituent
841+ return $ Skip $ FromSVarLoop sv (Prelude.reverse list)
843+ step (FromSVarLoop sv []) = return $ Skip $ FromSVarRead sv
844+ step (FromSVarLoop sv (ev : es)) = do
846+ ChildYield a -> return $ Yield a (FromSVarLoop sv es)
847+ ChildStop tid e -> do
848+ accountThread sv tid
851+ sendStopToProducer sv
852+ return $ Skip (FromSVarDone sv)
853+ Just _ -> error "Bug: fromProducer: received exception"
855+ step (FromSVarDone sv) = do
856+ when (svarInspectMode sv) $ do
857+ t <- liftIO $ getTime Monotonic
858+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
859+ liftIO $ printSVar sv "SVar Done"
862+ step (FromSVarInit _) = undefined
882------------------------------------------------------------------------------
864------------------------------------------------------------------------------
883-- Exceptions
865-- Exceptions