@@ -123,14 +123,21 @@ module Streamly.Internal.Data.Stream.Type
123123 , foldManyPost
124124 , groupsOf
125125 , refoldMany
126+ , refoldIterateM
126127
127128 -- * Fold Iterate
128129 , reduceIterateBfs
129130 , foldIterateBfs
130131
132+ -- * Splitting
133+ , indexOnSuffix
134+
131135 -- * Multi-stream folds
132136 , eqBy
133137 , cmpBy
138+
139+ -- * Deprecated
140+ , sliceOnSuffix
134141 )
135142where
136143
@@ -162,6 +169,7 @@ import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
162169import Streamly.Internal.Data.Refold.Type (Refold(..))
163170import Streamly.Internal.Data.Stream.Step (Step (..))
164171import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
172+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
165173import Streamly.Internal.Data.Unfold.Type (Unfold(..))
166174
167175import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
@@ -1974,6 +1982,90 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
19741982 step' _ (FoldManyYield b next) = return $ Yield b next
19751983 step' _ FoldManyDone = return Stop
19761984
1985+{-# ANN type CIterState Fuse #-}
1986+data CIterState s f fs b
1987+ = CIterInit s f
1988+ | CIterConsume s fs
1989+ | CIterYield b (CIterState s f fs b)
1990+ | CIterStop
1991+
1992+-- | Like 'foldIterateM' but using the 'Refold' type instead. This could be
1993+-- much more efficient due to stream fusion.
1994+--
1995+-- /Internal/
1996+{-# INLINE_NORMAL refoldIterateM #-}
1997+refoldIterateM ::
1998+ Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
1999+refoldIterateM (Refold fstep finject fextract) initial (Stream step state) =
2000+ Stream stepOuter (CIterInit state initial)
2001+
2002+ where
2003+
2004+ {-# INLINE iterStep #-}
2005+ iterStep st action = do
2006+ res <- action
2007+ return
2008+ $ Skip
2009+ $ case res of
2010+ FL.Partial fs -> CIterConsume st fs
2011+ FL.Done fb -> CIterYield fb $ CIterInit st (return fb)
2012+
2013+ {-# INLINE_LATE stepOuter #-}
2014+ stepOuter _ (CIterInit st action) = do
2015+ iterStep st (action >>= finject)
2016+ stepOuter gst (CIterConsume st fs) = do
2017+ r <- step (adaptState gst) st
2018+ case r of
2019+ Yield x s -> iterStep s (fstep fs x)
2020+ Skip s -> return $ Skip $ CIterConsume s fs
2021+ Stop -> do
2022+ b <- fextract fs
2023+ return $ Skip $ CIterYield b CIterStop
2024+ stepOuter _ (CIterYield a next) = return $ Yield a next
2025+ stepOuter _ CIterStop = return Stop
2026+
2027+-- | The refold @indexerBy f n@ takes an (index, len) tuple as initial input,
2028+-- and returns @(index + len + n, b)@ as output where @b@ is the output of the
2029+-- fold.
2030+{-# INLINE indexerBy #-}
2031+indexerBy :: Monad m =>
2032+ Fold m a Int -> Int -> Refold m (Int, Int) a (Int, Int)
2033+indexerBy (Fold step1 initial1 extract1 _final) n =
2034+ Refold step inject extract
2035+
2036+ where
2037+
2038+ inject (i, len) = do
2039+ r <- initial1
2040+ return $ case r of
2041+ FL.Partial s -> FL.Partial $ Tuple' (i + len + n) s
2042+ FL.Done l -> FL.Done (i, l)
2043+
2044+ step (Tuple' i s) x = do
2045+ r <- step1 s x
2046+ return $ case r of
2047+ FL.Partial s1 -> FL.Partial $ Tuple' i s1
2048+ FL.Done len -> FL.Done (i, len)
2049+
2050+ extract (Tuple' i s) = (i,) <$> extract1 s
2051+
2052+-- | Like 'splitOnSuffix' but generates a stream of (index, len) tuples marking
2053+-- the places where the predicate matches in the stream.
2054+--
2055+-- /Pre-release/
2056+{-# INLINE indexOnSuffix #-}
2057+indexOnSuffix :: Monad m =>
2058+ (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2059+indexOnSuffix predicate =
2060+ -- Scan the stream with the given refold
2061+ refoldIterateM
2062+ (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
2063+ (return (-1, 0))
2064+
2065+{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
2066+sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2067+sliceOnSuffix = indexOnSuffix
2068+
19772069------------------------------------------------------------------------------
19782070-- Stream with a cross product style monad instance
19792071------------------------------------------------------------------------------