module Data.Repa.Stream.Extract
        (extractS)
where
import Data.Vector.Fusion.Stream.Monadic         (Stream(..), Step(..))
import qualified Data.Vector.Fusion.Stream.Size  as S
#include "repa-stream.h"


-- | Extract segments from some source array and concatenate them.
extractS
        :: Monad m
        => (Int -> a)           -- ^ Function to get elements from the source.
        -> Stream m (Int, Int)  -- ^ Segment start positions and lengths.
        -> Stream m a           -- ^ Result elements.

extractS get (Stream istep si0 _)
 = Stream ostep (si0, Nothing) S.Unknown
 where
        -- Start a new segment.
        ostep (si, Nothing)
         =  istep si >>= \m
         -> case m of
                Yield (iStart, iLen) si' 
                          -> return $ Skip (si', Just (iStart, iStart + iLen))
                Skip  si' -> return $ Skip (si', Nothing)
                Done      -> return $ Done

        -- Emit data from a segment.
        ostep (si, Just (iPos, iTop))
         | iPos >= iTop   =  return $ Skip  (si, Nothing)
         | otherwise      =  return $ Yield (get iPos) 
                                            (si, Just (iPos + 1, iTop))
        {-# INLINE_INNER ostep #-}
{-# INLINE_STREAM extractS #-}