@@ -202,6 +202,7 @@ module Streamly.Internal.Prelude
202 -- ** Left scans
202 -- ** Left scans
204 , scanlM'
204 , scanlM'
205 , postscanl'
206 , postscanl'
206 , postscanlM'
207 , postscanlM'
207 , prescanl'
208 , prescanl'
@@ -2125,6 +2126,23 @@ scanx = P.scanlx'
2125scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2126scanlM' :: (IsStream t, Monad m) => (b -> a -> m b) -> b -> t m a -> t m b
2126scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2127scanlM' step begin m = fromStreamD $ D.scanlM' step begin $ toStreamD m
2129+-- | @scanlMAfter' accumulate initial done stream@ is like 'scanlM'' except
2130+-- that it provides an additional @done@ function to be applied on the
2131+-- accumulator when the stream stops. The result of @done@ is also emitted in
2134+-- This function can be used to allocate a resource in the beginning of the
2135+-- scan and release it when the stream ends or to flush the internal state of
2136+-- the scan at the end.
2140+{-# INLINE scanlMAfter' #-}
2141+scanlMAfter' :: (IsStream t, Monad m)
2142+ => (b -> a -> m b) -> m b -> (b -> m b) -> t m a -> t m b
2143+scanlMAfter' step initial done stream =
2144+ fromStreamD $ D.scanlMAfter' step initial done $ toStreamD stream
2128-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2146-- | Strict left scan. Like 'map', 'scanl'' too is a one to one transformation,
2129-- however it adds an extra element.
2147-- however it adds an extra element.
@@ -4507,8 +4525,8 @@ classifySessionsBy
4507 -> t m (k, b) -- ^ session key, fold result
4525 -> t m (k, b) -- ^ session key, fold result
4508classifySessionsBy tick tmout reset ejectPred
4526classifySessionsBy tick tmout reset ejectPred
4509 (Fold step initial extract) str =
4527 (Fold step initial extract) str =
4510− concatMap sessionOutputStream
4528+ concatMap sessionOutputStream $
4511− $ scanlM' sstep szero stream
4529+ scanlMAfter' sstep (return szero) flush stream
@@ -4613,6 +4631,21 @@ classifySessionsBy tick tmout reset ejectPred
4613 let curTime = addToAbsTime sessionCurTime tickMs
4631 let curTime = addToAbsTime sessionCurTime tickMs
4614 in ejectExpired sessionState curTime
4632 in ejectExpired sessionState curTime
4634+ flush session@SessionState{..} = do
4635+ (hp', mp', out, count) <-
4638+ , sessionKeyValueMap
4643+ { sessionCount = count
4644+ , sessionTimerHeap = hp'
4645+ , sessionKeyValueMap = mp'
4646+ , sessionOutputStream = out
4616 fromEither e =
4649 fromEither e =
4617 case e of
4650 case e of
4618 Left x -> x
4651 Left x -> x
@@ -4625,6 +4658,18 @@ classifySessionsBy tick tmout reset ejectPred
4625 let mp1 = Map.delete key mp
4658 let mp1 = Map.delete key mp
4626 return (hp, mp1, out1, cnt - 1)
4659 return (hp, mp1, out1, cnt - 1)
4661+ ejectAll (hp, mp, out, !cnt) = do
4662+ let hres = H.uncons hp
4664+ Just (Entry _ key, hp1) -> do
4665+ r <- case Map.lookup key mp of
4666+ Nothing -> return (hp1, mp, out, cnt)
4667+ Just (Tuple' _ acc) -> ejectEntry hp1 mp out cnt acc key
4670+ assert (Map.null mp) (return ())
4671+ return (hp, mp, out, cnt)
4628 ejectOne (hp, mp, out, !cnt) = do
4673 ejectOne (hp, mp, out, !cnt) = do
4629 let hres = H.uncons hp
4674 let hres = H.uncons hp
4630 case hres of
4675 case hres of