on master help sign in
Move pollCounts from streamly-core to streamly
commit3e074ef94b1b9b6ebd009190207ceb6b0e9c299e authorHarendra Kumar <harendra@composewell.com> dateSun 23 Oct 2022, 03:58 (4 years ago) parent135c55e
3 files changed+74−44
core/src/Streamly/Internal/Data/Stream/StreamD/Transform.hs+1−40 src/Streamly/Internal/Data/Stream/Concurrent.hs+70−2 src/Streamly/Internal/Data/Stream/IsStream/Transform.hs+3−2
core/src/Streamly/Internal/Data/Stream/StreamD/Transform.hs+1−40
@@ -27,7 +27,6 @@ module Streamly.Internal.Data.Stream.StreamD.Transform
2727 -- * Mapping Effects
2828 , tap
2929 , tapOffsetEvery
30− , pollCounts
3130
3231 -- * Folding
3332 , foldrS
@@ -124,23 +123,18 @@ where
124123
125124#include "inline.hs"
126125
127−import Control.Concurrent (killThread)
128−import Control.Monad (void, when)
129−import Control.Monad.IO.Class (MonadIO(..))
126+import Control.Monad (void)
130127import Control.Monad.Trans.Class (MonadTrans(lift))
131128import Data.Maybe (fromJust, isJust)
132129import Fusion.Plugin.Types (Fuse(..))
133130import GHC.Types (SPEC(..))
134131
135−import Streamly.Internal.Control.Concurrent (MonadAsync)
136−import Streamly.Internal.Control.ForkLifted (forkManaged)
137132import Streamly.Internal.Data.Fold.Type (Fold(..))
138133import Streamly.Internal.Data.Pipe.Type (Pipe(..), PipeState(..))
139134import Streamly.Internal.Data.SVar.Type (defState, adaptState)
140135
141136import qualified Data.Set as Set
142137import qualified Streamly.Internal.Data.Fold.Type as FL
143−import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
144138import qualified Streamly.Internal.Data.Pipe.Type as Pipe
145139
146140import Prelude hiding
@@ -325,39 +319,6 @@ tapOffsetEvery offset n (Fold fstep initial extract) (Stream step state) =
325319 Skip s -> Skip (TapOffDone s)
326320 Stop -> Stop
327321
328−{-# INLINE_NORMAL pollCounts #-}
329−pollCounts
330− :: MonadAsync m
331− => (a -> Bool)
332− -> (Stream m Int -> m b)
333− -> Stream m a
334− -> Stream m a
335−pollCounts predicate fld (Stream step state) = Stream step' Nothing
336− where
337−
338− {-# INLINE_LATE step' #-}
339− step' _ Nothing = do
340− -- As long as we are using an "Int" for counts lockfree reads from
341− -- Var should work correctly on both 32-bit and 64-bit machines.
342− -- However, an Int on a 32-bit machine may overflow quickly.
343− countVar <- liftIO $ Unboxed.newIORef (0 :: Int)
344− tid <- forkManaged
345− $ void $ fld
346− $ Unboxed.toStreamD countVar
347− return $ Skip (Just (countVar, tid, state))
348−
349− step' gst (Just (countVar, tid, st)) = do
350− r <- step gst st
351− case r of
352− Yield x s -> do
353− when (predicate x)
354− $ liftIO $ Unboxed.modifyIORef' countVar (+ 1)
355− return $ Yield x (Just (countVar, tid, s))
356− Skip s -> return $ Skip (Just (countVar, tid, s))
357− Stop -> do
358− liftIO $ killThread tid
359− return Stop
360−
361322------------------------------------------------------------------------------
362323-- Scanning with a Fold
363324------------------------------------------------------------------------------
src/Streamly/Internal/Data/Stream/Concurrent.hs+70−2
@@ -98,15 +98,18 @@ module Streamly.Internal.Data.Stream.Concurrent
9898
9999 -- ** Reactive
100100 , fromCallback
101+ , pollCountsD
102+ , pollCounts
101103 )
102104where
103105
104106#include "inline.hs"
105107
106−import Control.Concurrent (myThreadId)
107−import Control.Monad (void)
108+import Control.Concurrent (myThreadId, killThread)
109+import Control.Monad (void, when)
108110import Control.Monad.IO.Class (MonadIO(liftIO))
109111import Streamly.Internal.Control.Concurrent (MonadAsync, askRunInIO)
112+import Streamly.Internal.Control.ForkLifted (forkManaged)
110113import Streamly.Internal.Data.Stream.Channel.Dispatcher (modifyThread)
111114import Streamly.Internal.Data.Stream.Channel.Types
112115 ( ChildEvent(..)
@@ -114,8 +117,11 @@ import Streamly.Internal.Data.Stream.Channel.Types
114117 )
115118import Streamly.Internal.Data.Stream.Channel.Worker (sendWithDoorBell)
116119import Streamly.Internal.Data.Stream.Type (Stream)
120+import Streamly.Internal.Data.Stream.StreamD (Step(..))
117121
122+import qualified Streamly.Internal.Data.IORef.Unboxed as Unboxed
118123import qualified Streamly.Internal.Data.Stream as Stream
124+import qualified Streamly.Internal.Data.Stream.StreamD as D
119125import qualified Streamly.Internal.Data.Stream.StreamK as K
120126import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
121127
@@ -695,3 +701,65 @@ fromCallback setCallback = Stream.concatM $ do
695701 (callback, stream) <- newCallbackStream
696702 setCallback callback
697703 return stream
704+
705+{-# INLINE_NORMAL pollCountsD #-}
706+pollCountsD
707+ :: MonadAsync m
708+ => (a -> Bool)
709+ -> (D.Stream m Int -> m b)
710+ -> D.Stream m a
711+ -> D.Stream m a
712+pollCountsD predicate fld (D.Stream step state) = D.Stream step' Nothing
713+ where
714+
715+ {-# INLINE_LATE step' #-}
716+ step' _ Nothing = do
717+ -- As long as we are using an "Int" for counts lockfree reads from
718+ -- Var should work correctly on both 32-bit and 64-bit machines.
719+ -- However, an Int on a 32-bit machine may overflow quickly.
720+ countVar <- liftIO $ Unboxed.newIORef (0 :: Int)
721+ tid <- forkManaged
722+ $ void $ fld
723+ $ Unboxed.toStreamD countVar
724+ return $ Skip (Just (countVar, tid, state))
725+
726+ step' gst (Just (countVar, tid, st)) = do
727+ r <- step gst st
728+ case r of
729+ Yield x s -> do
730+ when (predicate x)
731+ $ liftIO $ Unboxed.modifyIORef' countVar (+ 1)
732+ return $ Yield x (Just (countVar, tid, s))
733+ Skip s -> return $ Skip (Just (countVar, tid, s))
734+ Stop -> do
735+ liftIO $ killThread tid
736+ return Stop
737+
738+-- | @pollCounts predicate transform fold stream@ counts those elements in the
739+-- stream that pass the @predicate@. The resulting count stream is sent to
740+-- another thread which transforms it using @transform@ and then folds it using
741+-- @fold@. The thread is automatically cleaned up if the stream stops or
742+-- aborts due to exception.
743+--
744+-- For example, to print the count of elements processed every second:
745+--
746+-- @
747+-- > Stream.drain $ Concur.pollCounts (const True) (Stream.rollingMap (-) . Stream.delayPost 1) (Fold.drainBy print)
748+-- $ Stream.enumerateFrom 0
749+-- @
750+--
751+-- Note: This may not work correctly on 32-bit machines.
752+--
753+-- /Pre-release/
754+--
755+{-# INLINE pollCounts #-}
756+pollCounts ::
757+ (MonadAsync m)
758+ => (a -> Bool)
759+ -> (Stream m Int -> m b)
760+ -> Stream m a
761+ -> Stream m a
762+pollCounts predicate f xs =
763+ Stream.fromStreamD
764+ $ pollCountsD predicate (f . Stream.fromStreamD)
765+ $ Stream.toStreamD xs
src/Streamly/Internal/Data/Stream/IsStream/Transform.hs+3−2
@@ -253,10 +253,11 @@ import Streamly.Internal.Data.SVar (Rate(..))
253253import Streamly.Internal.Data.Time.Units (AbsTime, RelTime64)
254254
255255import qualified Streamly.Data.Fold as FL
256+import qualified Streamly.Internal.Data.Stream.Concurrent as Concur
256257import qualified Streamly.Internal.Data.Stream.Parallel as Par
257258import qualified Streamly.Internal.Data.Stream.Serial as Serial
258259import qualified Streamly.Internal.Data.Stream.StreamD as D
259− (transform, foldrT, tap, tapOffsetEvery, pollCounts, mapM, scanOnce
260+ (transform, foldrT, tap, tapOffsetEvery, mapM, scanOnce
260261 , scanMany, postscanOnce, scanlx', scanlM', scanl', postscanl', prescanl'
261262 , prescanlM', scanl1M', scanl1', filter, filterM, uniq, deleteBy, takeWhileM
262263 , dropWhile, dropWhileM, insertBy, intersperse
@@ -582,7 +583,7 @@ pollCounts ::
582583 -> t m a
583584pollCounts predicate f xs =
584585 fromStreamD
585− $ D.pollCounts predicate (f . fromStreamD)
586+ $ Concur.pollCountsD predicate (f . fromStreamD)
586587 $ toStreamD xs
587588
588589-- | Apply a monadic function to each element flowing through the stream and