|
Packit |
368400 |
{-# LANGUAGE BangPatterns #-}
|
|
Packit |
368400 |
{-# LANGUAGE ExistentialQuantification #-}
|
|
Packit |
368400 |
{-# LANGUAGE FlexibleContexts #-}
|
|
Packit |
368400 |
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
Packit |
368400 |
{-# LANGUAGE TupleSections #-}
|
|
Packit |
368400 |
{-# LANGUAGE RankNTypes #-}
|
|
Packit |
368400 |
-- Collection of three benchmarks: a simple integral sum, monte carlo analysis,
|
|
Packit |
368400 |
-- and sliding vector.
|
|
Packit |
368400 |
import Control.DeepSeq
|
|
Packit |
368400 |
import Control.Monad (foldM)
|
|
Packit |
368400 |
import Control.Monad (when, liftM)
|
|
Packit |
368400 |
import Control.Monad.Codensity (lowerCodensity)
|
|
Packit |
368400 |
import Control.Monad.IO.Class (MonadIO, liftIO)
|
|
Packit |
368400 |
import Control.Monad.Trans.Class (lift)
|
|
Packit |
368400 |
import Criterion.Main
|
|
Packit |
368400 |
import Data.Conduit
|
|
Packit |
368400 |
import Data.Conduit.Internal (ConduitM (..), Pipe (..))
|
|
Packit |
368400 |
import qualified Data.Conduit.Internal as CI
|
|
Packit |
368400 |
import qualified Data.Conduit.List as CL
|
|
Packit |
368400 |
import qualified Data.Foldable as F
|
|
Packit |
368400 |
import Data.Functor.Identity (runIdentity)
|
|
Packit |
368400 |
import Data.IORef
|
|
Packit |
368400 |
import Data.List (foldl')
|
|
Packit |
368400 |
import Data.Monoid (mempty)
|
|
Packit |
368400 |
import qualified Data.Sequence as Seq
|
|
Packit |
368400 |
import qualified Data.Vector as VB
|
|
Packit |
368400 |
import qualified Data.Vector.Generic as V
|
|
Packit |
368400 |
import qualified Data.Vector.Generic.Mutable as VM
|
|
Packit |
368400 |
import qualified Data.Vector.Unboxed as VU
|
|
Packit |
368400 |
import System.Environment (withArgs)
|
|
Packit |
368400 |
import qualified System.Random.MWC as MWC
|
|
Packit |
368400 |
import Test.Hspec
|
|
Packit |
368400 |
|
|
Packit |
368400 |
data TestBench = TBGroup String [TestBench]
|
|
Packit |
368400 |
| TBBench Benchmark
|
|
Packit |
368400 |
| forall a b. (Eq b, Show b) => TBPure String a b (a -> b)
|
|
Packit |
368400 |
| forall a. (Eq a, Show a) => TBIO String a (IO a)
|
|
Packit |
368400 |
| forall a. (Eq a, Show a) => TBIOTest String (a -> IO ()) (IO a)
|
|
Packit |
368400 |
| forall a. (Eq a, Show a) => TBIOBench String a (IO a) (IO ())
|
|
Packit |
368400 |
|
|
Packit |
368400 |
toSpec :: TestBench -> Spec
|
|
Packit |
368400 |
toSpec (TBGroup name tbs) = describe name $ mapM_ toSpec tbs
|
|
Packit |
368400 |
toSpec (TBBench _) = return ()
|
|
Packit |
368400 |
toSpec (TBPure name a b f) = it name $ f a `shouldBe` b
|
|
Packit |
368400 |
toSpec (TBIO name a f) = it name $ f >>= (`shouldBe` a)
|
|
Packit |
368400 |
toSpec (TBIOTest name spec f) = it name $ f >>= spec
|
|
Packit |
368400 |
toSpec (TBIOBench name a f _) = it name $ f >>= (`shouldBe` a)
|
|
Packit |
368400 |
|
|
Packit |
368400 |
toBench :: TestBench -> Benchmark
|
|
Packit |
368400 |
toBench (TBGroup name tbs) = bgroup name $ map toBench tbs
|
|
Packit |
368400 |
toBench (TBBench b) = b
|
|
Packit |
368400 |
toBench (TBPure name a _ f) = bench name $ whnf f a
|
|
Packit |
368400 |
toBench (TBIO name _ f) = bench name $ whnfIO f
|
|
Packit |
368400 |
toBench (TBIOTest name _ f) = bench name $ whnfIO f
|
|
Packit |
368400 |
toBench (TBIOBench name _ _ f) = bench name $ whnfIO f
|
|
Packit |
368400 |
|
|
Packit |
368400 |
runTestBench :: [TestBench] -> IO ()
|
|
Packit |
368400 |
runTestBench tbs = do
|
|
Packit |
368400 |
withArgs [] $ hspec $ mapM_ toSpec tbs
|
|
Packit |
368400 |
defaultMain $ map toBench tbs
|
|
Packit |
368400 |
|
|
Packit |
368400 |
main :: IO ()
|
|
Packit |
368400 |
main = runTestBench =<< sequence
|
|
Packit |
368400 |
[ sumTB
|
|
Packit |
368400 |
, mapSumTB
|
|
Packit |
368400 |
, monteCarloTB
|
|
Packit |
368400 |
, fmap (TBGroup "sliding window") $ sequence
|
|
Packit |
368400 |
[ slidingWindow 10
|
|
Packit |
368400 |
, slidingWindow 30
|
|
Packit |
368400 |
, slidingWindow 100
|
|
Packit |
368400 |
, slidingWindow 1000
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
|
|
Packit |
368400 |
-----------------------------------------------------------------------
|
|
Packit |
368400 |
|
|
Packit |
368400 |
sumTB :: IO TestBench
|
|
Packit |
368400 |
sumTB = do
|
|
Packit |
368400 |
upperRef <- newIORef upper0
|
|
Packit |
368400 |
return $ TBGroup "sum"
|
|
Packit |
368400 |
[ TBPure "Data.List.foldl'" upper0 expected
|
|
Packit |
368400 |
$ \upper -> foldl' (+) 0 [1..upper]
|
|
Packit |
368400 |
, TBIO "Control.Monad.foldM" expected $ do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
foldM plusM 0 [1..upper]
|
|
Packit |
368400 |
, TBPure "low level" upper0 expected $ \upper ->
|
|
Packit |
368400 |
let go x !t
|
|
Packit |
368400 |
| x > upper = t
|
|
Packit |
368400 |
| otherwise = go (x + 1) (t + x)
|
|
Packit |
368400 |
in go 1 0
|
|
Packit |
368400 |
, TBIO "boxed vectors, I/O" expected $ do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
VB.foldM' plusM 0 $ VB.enumFromTo 1 upper
|
|
Packit |
368400 |
, TBPure "boxed vectors" upper0 expected
|
|
Packit |
368400 |
$ \upper -> VB.foldl' (+) 0 (VB.enumFromTo 1 upper)
|
|
Packit |
368400 |
, TBPure "unboxed vectors" upper0 expected
|
|
Packit |
368400 |
$ \upper -> VU.foldl' (+) 0 (VU.enumFromTo 1 upper)
|
|
Packit |
368400 |
, TBPure "conduit, pure, fold" upper0 expected
|
|
Packit |
368400 |
$ \upper -> runIdentity $ CL.enumFromTo 1 upper $$ CL.fold (+) 0
|
|
Packit |
368400 |
, TBPure "conduit, pure, foldM" upper0 expected
|
|
Packit |
368400 |
$ \upper -> runIdentity $ CL.enumFromTo 1 upper $$ CL.foldM plusM 0
|
|
Packit |
368400 |
, TBIO "conduit, IO, fold" expected $ do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
CL.enumFromTo 1 upper $$ CL.fold (+) 0
|
|
Packit |
368400 |
, TBIO "conduit, IO, foldM" expected $ do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
CL.enumFromTo 1 upper $$ CL.foldM plusM 0
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
upper0 = 10000 :: Int
|
|
Packit |
368400 |
expected = sum [1..upper0]
|
|
Packit |
368400 |
|
|
Packit |
368400 |
plusM x y = return $! x + y
|
|
Packit |
368400 |
|
|
Packit |
368400 |
-----------------------------------------------------------------------
|
|
Packit |
368400 |
|
|
Packit |
368400 |
mapSumTB :: IO TestBench
|
|
Packit |
368400 |
mapSumTB = return $ TBGroup "map + sum"
|
|
Packit |
368400 |
[ TBPure "boxed vectors" upper0 expected
|
|
Packit |
368400 |
$ \upper -> VB.foldl' (+) 0
|
|
Packit |
368400 |
$ VB.map (+ 1)
|
|
Packit |
368400 |
$ VB.map (* 2)
|
|
Packit |
368400 |
$ VB.enumFromTo 1 upper
|
|
Packit |
368400 |
, TBPure "unboxed vectors" upper0 expected
|
|
Packit |
368400 |
$ \upper -> VU.foldl' (+) 0
|
|
Packit |
368400 |
$ VU.map (+ 1)
|
|
Packit |
368400 |
$ VU.map (* 2)
|
|
Packit |
368400 |
$ VU.enumFromTo 1 upper
|
|
Packit |
368400 |
, TBPure "conduit, connect1" upper0 expected $ \upper -> runIdentity
|
|
Packit |
368400 |
$ CL.enumFromTo 1 upper
|
|
Packit |
368400 |
$$ CL.map (* 2)
|
|
Packit |
368400 |
=$= CL.map (+ 1)
|
|
Packit |
368400 |
=$= CL.fold (+) 0
|
|
Packit |
368400 |
, TBPure "conduit, connect2" upper0 expected $ \upper -> runIdentity
|
|
Packit |
368400 |
$ CL.enumFromTo 1 upper
|
|
Packit |
368400 |
=$= CL.map (* 2)
|
|
Packit |
368400 |
$$ CL.map (+ 1)
|
|
Packit |
368400 |
=$= CL.fold (+) 0
|
|
Packit |
368400 |
, TBPure "conduit, connect3" upper0 expected $ \upper -> runIdentity
|
|
Packit |
368400 |
$ CL.enumFromTo 1 upper
|
|
Packit |
368400 |
=$= CL.map (* 2)
|
|
Packit |
368400 |
=$= CL.map (+ 1)
|
|
Packit |
368400 |
$$ CL.fold (+) 0
|
|
Packit |
368400 |
, TBPure "conduit, inner fuse" upper0 expected $ \upper -> runIdentity
|
|
Packit |
368400 |
$ CL.enumFromTo 1 upper
|
|
Packit |
368400 |
=$= (CL.map (* 2)
|
|
Packit |
368400 |
=$= CL.map (+ 1))
|
|
Packit |
368400 |
$$ CL.fold (+) 0
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
upper0 = 10000 :: Int
|
|
Packit |
368400 |
expected = sum $ map (+ 1) $ map (* 2) [1..upper0]
|
|
Packit |
368400 |
|
|
Packit |
368400 |
-----------------------------------------------------------------------
|
|
Packit |
368400 |
|
|
Packit |
368400 |
monteCarloTB :: IO TestBench
|
|
Packit |
368400 |
monteCarloTB = return $ TBGroup "monte carlo"
|
|
Packit |
368400 |
[ TBIOTest "conduit" closeEnough $ do
|
|
Packit |
368400 |
gen <- MWC.createSystemRandom
|
|
Packit |
368400 |
successes <- CL.replicateM count (MWC.uniform gen)
|
|
Packit |
368400 |
$$ CL.fold (\t (x, y) ->
|
|
Packit |
368400 |
if (x*x + y*(y :: Double) < 1)
|
|
Packit |
368400 |
then t + 1
|
|
Packit |
368400 |
else t)
|
|
Packit |
368400 |
(0 :: Int)
|
|
Packit |
368400 |
return $ fromIntegral successes / fromIntegral count * 4
|
|
Packit |
368400 |
, TBIOTest "low level" closeEnough $ do
|
|
Packit |
368400 |
gen <- MWC.createSystemRandom
|
|
Packit |
368400 |
let go :: Int -> Int -> IO Double
|
|
Packit |
368400 |
go 0 !t = return $! fromIntegral t / fromIntegral count * 4
|
|
Packit |
368400 |
go i !t = do
|
|
Packit |
368400 |
(x, y) <- MWC.uniform gen
|
|
Packit |
368400 |
let t'
|
|
Packit |
368400 |
| x*x + y*(y :: Double) < 1 = t + 1
|
|
Packit |
368400 |
| otherwise = t
|
|
Packit |
368400 |
go (i - 1) t'
|
|
Packit |
368400 |
go count (0 :: Int)
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
count = 100000 :: Int
|
|
Packit |
368400 |
|
|
Packit |
368400 |
closeEnough x
|
|
Packit |
368400 |
| abs (x - 3.14159 :: Double) < 0.2 = return ()
|
|
Packit |
368400 |
| otherwise = error $ "Monte carlo analysis too inaccurate: " ++ show x
|
|
Packit |
368400 |
|
|
Packit |
368400 |
-----------------------------------------------------------------------
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingWindow :: Int -> IO TestBench
|
|
Packit |
368400 |
slidingWindow window = do
|
|
Packit |
368400 |
upperRef <- newIORef upper0
|
|
Packit |
368400 |
return $ TBGroup (show window)
|
|
Packit |
368400 |
[ TBIOBench "low level, Seq" expected
|
|
Packit |
368400 |
(swLowLevelSeq window upperRef id (\x y -> x . (F.toList y:)) ($ []))
|
|
Packit |
368400 |
(swLowLevelSeq window upperRef () (\() y -> rnf y) id)
|
|
Packit |
368400 |
, TBIOBench "conduit, Seq" expected
|
|
Packit |
368400 |
(swConduitSeq window upperRef id (\x y -> x . (F.toList y:)) ($ []))
|
|
Packit |
368400 |
(swConduitSeq window upperRef () (\() y -> rnf y) id)
|
|
Packit |
368400 |
{- https://ghc.haskell.org/trac/ghc/ticket/9446
|
|
Packit |
368400 |
, TBIOBench "low level, boxed Vector" expected
|
|
Packit |
368400 |
(swLowLevelVector window upperRef id (\x y -> x . (VB.toList y:)) ($ []))
|
|
Packit |
368400 |
(swLowLevelVector window upperRef () (\() y -> rnf (y :: VB.Vector Int)) id)
|
|
Packit |
368400 |
-}
|
|
Packit |
368400 |
, TBBench $ bench "low level, boxed Vector" $ whnfIO $
|
|
Packit |
368400 |
swLowLevelVector window upperRef () (\() y -> rnf (y :: VB.Vector Int)) id
|
|
Packit |
368400 |
|
|
Packit |
368400 |
{- https://ghc.haskell.org/trac/ghc/ticket/9446
|
|
Packit |
368400 |
, TBIOBench "conduit, boxed Vector" expected
|
|
Packit |
368400 |
(swConduitVector window upperRef id (\x y -> x . (VB.toList y:)) ($ []))
|
|
Packit |
368400 |
(swConduitVector window upperRef () (\() y -> rnf (y :: VB.Vector Int)) id)
|
|
Packit |
368400 |
-}
|
|
Packit |
368400 |
|
|
Packit |
368400 |
, TBBench $ bench "conduit, boxed Vector" $ whnfIO $
|
|
Packit |
368400 |
swConduitVector window upperRef () (\() y -> rnf (y :: VB.Vector Int)) id
|
|
Packit |
368400 |
|
|
Packit |
368400 |
|
|
Packit |
368400 |
, TBIOBench "low level, unboxed Vector" expected
|
|
Packit |
368400 |
(swLowLevelVector window upperRef id (\x y -> x . (VU.toList y:)) ($ []))
|
|
Packit |
368400 |
(swLowLevelVector window upperRef () (\() y -> rnf (y :: VU.Vector Int)) id)
|
|
Packit |
368400 |
, TBIOBench "conduit, unboxed Vector" expected
|
|
Packit |
368400 |
(swConduitVector window upperRef id (\x y -> x . (VU.toList y:)) ($ []))
|
|
Packit |
368400 |
(swConduitVector window upperRef () (\() y -> rnf (y :: VU.Vector Int)) id)
|
|
Packit |
368400 |
]
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
upper0 = 10000
|
|
Packit |
368400 |
expected =
|
|
Packit |
368400 |
loop [1..upper0]
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
loop input
|
|
Packit |
368400 |
| length x == window = x : loop y
|
|
Packit |
368400 |
| otherwise = []
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
x = take window input
|
|
Packit |
368400 |
y = drop 1 input
|
|
Packit |
368400 |
|
|
Packit |
368400 |
swLowLevelSeq :: Int -> IORef Int -> t -> (t -> Seq.Seq Int -> t) -> (t -> t') -> IO t'
|
|
Packit |
368400 |
swLowLevelSeq window upperRef t0 f final = do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
|
|
Packit |
368400 |
let phase1 i !s
|
|
Packit |
368400 |
| i > window = phase2 i s t0
|
|
Packit |
368400 |
| otherwise = phase1 (i + 1) (s Seq.|> i)
|
|
Packit |
368400 |
|
|
Packit |
368400 |
phase2 i !s !t
|
|
Packit |
368400 |
| i > upper = t'
|
|
Packit |
368400 |
| otherwise = phase2 (i + 1) s' t'
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
t' = f t s
|
|
Packit |
368400 |
s' = Seq.drop 1 s Seq.|> i
|
|
Packit |
368400 |
|
|
Packit |
368400 |
return $! final $! phase1 1 mempty
|
|
Packit |
368400 |
|
|
Packit |
368400 |
swLowLevelVector :: V.Vector v Int
|
|
Packit |
368400 |
=> Int
|
|
Packit |
368400 |
-> IORef Int
|
|
Packit |
368400 |
-> t
|
|
Packit |
368400 |
-> (t -> v Int -> t)
|
|
Packit |
368400 |
-> (t -> t')
|
|
Packit |
368400 |
-> IO t'
|
|
Packit |
368400 |
swLowLevelVector window upperRef t0 f final = do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
|
|
Packit |
368400 |
let go !i !t _ _ _ | i > upper = return $! final $! t
|
|
Packit |
368400 |
go !i !t !end _mv mv2 | end == bufSz = newBuf >>= go i t sz mv2
|
|
Packit |
368400 |
go !i !t !end mv mv2 = do
|
|
Packit |
368400 |
VM.unsafeWrite mv end i
|
|
Packit |
368400 |
when (end > sz) $ VM.unsafeWrite mv2 (end - sz) i
|
|
Packit |
368400 |
let end' = end + 1
|
|
Packit |
368400 |
t' <-
|
|
Packit |
368400 |
if end' < sz
|
|
Packit |
368400 |
then return t
|
|
Packit |
368400 |
else do
|
|
Packit |
368400 |
v <- V.unsafeFreeze $ VM.unsafeSlice (end' - sz) sz mv
|
|
Packit |
368400 |
return $! f t v
|
|
Packit |
368400 |
go (i + 1) t' end' mv mv2
|
|
Packit |
368400 |
|
|
Packit |
368400 |
mv <- newBuf
|
|
Packit |
368400 |
mv2 <- newBuf
|
|
Packit |
368400 |
go 1 t0 0 mv mv2
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
sz = window
|
|
Packit |
368400 |
bufSz = 2 * window
|
|
Packit |
368400 |
newBuf = VM.new bufSz
|
|
Packit |
368400 |
|
|
Packit |
368400 |
swConduitSeq :: Int
|
|
Packit |
368400 |
-> IORef Int
|
|
Packit |
368400 |
-> t
|
|
Packit |
368400 |
-> (t -> Seq.Seq Int -> t)
|
|
Packit |
368400 |
-> (t -> t')
|
|
Packit |
368400 |
-> IO t'
|
|
Packit |
368400 |
swConduitSeq window upperRef t0 f final = do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
|
|
Packit |
368400 |
t <- CL.enumFromTo 1 upper
|
|
Packit |
368400 |
$= slidingWindowC window
|
|
Packit |
368400 |
$$ CL.fold f t0
|
|
Packit |
368400 |
return $! final t
|
|
Packit |
368400 |
|
|
Packit |
368400 |
swConduitVector :: V.Vector v Int
|
|
Packit |
368400 |
=> Int
|
|
Packit |
368400 |
-> IORef Int
|
|
Packit |
368400 |
-> t
|
|
Packit |
368400 |
-> (t -> v Int -> t)
|
|
Packit |
368400 |
-> (t -> t')
|
|
Packit |
368400 |
-> IO t'
|
|
Packit |
368400 |
swConduitVector window upperRef t0 f final = do
|
|
Packit |
368400 |
upper <- readIORef upperRef
|
|
Packit |
368400 |
|
|
Packit |
368400 |
t <- CL.enumFromTo 1 upper
|
|
Packit |
368400 |
$= slidingVectorC window
|
|
Packit |
368400 |
$$ CL.fold f t0
|
|
Packit |
368400 |
return $! final t
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingWindowC :: Monad m => Int -> Conduit a m (Seq.Seq a)
|
|
Packit |
368400 |
slidingWindowC = slidingWindowCC
|
|
Packit |
368400 |
{-# INLINE [0] slidingWindowC #-}
|
|
Packit |
368400 |
{-# RULES "unstream slidingWindowC"
|
|
Packit |
368400 |
forall i. slidingWindowC i = CI.unstream (CI.streamConduit (slidingWindowCC i) (slidingWindowS i))
|
|
Packit |
368400 |
#-}
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingWindowCC :: Monad m => Int -> Conduit a m (Seq.Seq a)
|
|
Packit |
368400 |
slidingWindowCC sz =
|
|
Packit |
368400 |
go sz mempty
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
goContinue st = await >>=
|
|
Packit |
368400 |
maybe (return ())
|
|
Packit |
368400 |
(\x -> do
|
|
Packit |
368400 |
let st' = st Seq.|> x
|
|
Packit |
368400 |
yield st' >> goContinue (Seq.drop 1 st')
|
|
Packit |
368400 |
)
|
|
Packit |
368400 |
go 0 st = yield st >> goContinue (Seq.drop 1 st)
|
|
Packit |
368400 |
go !n st = CL.head >>= \m ->
|
|
Packit |
368400 |
case m of
|
|
Packit |
368400 |
Nothing | n < sz -> yield st
|
|
Packit |
368400 |
| otherwise -> return ()
|
|
Packit |
368400 |
Just x -> go (n-1) (st Seq.|> x)
|
|
Packit |
368400 |
{-# INLINE slidingWindowCC #-}
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingWindowS :: Monad m => Int -> CI.Stream m a () -> CI.Stream m (Seq.Seq a) ()
|
|
Packit |
368400 |
slidingWindowS sz (CI.Stream step ms0) =
|
|
Packit |
368400 |
CI.Stream step' $ liftM (\s -> Left (s, sz, mempty)) ms0
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
step' (Left (s, 0, st)) = return $ CI.Emit (Right (s, st)) st
|
|
Packit |
368400 |
step' (Left (s, i, st)) = do
|
|
Packit |
368400 |
res <- step s
|
|
Packit |
368400 |
return $ case res of
|
|
Packit |
368400 |
CI.Stop () -> CI.Stop ()
|
|
Packit |
368400 |
CI.Skip s' -> CI.Skip $ Left (s', i, st)
|
|
Packit |
368400 |
CI.Emit s' a -> CI.Skip $ Left (s', i - 1, st Seq.|> a)
|
|
Packit |
368400 |
step' (Right (s, st)) = do
|
|
Packit |
368400 |
res <- step s
|
|
Packit |
368400 |
return $ case res of
|
|
Packit |
368400 |
CI.Stop () -> CI.Stop ()
|
|
Packit |
368400 |
CI.Skip s' -> CI.Skip $ Right (s', st)
|
|
Packit |
368400 |
CI.Emit s' a ->
|
|
Packit |
368400 |
let st' = Seq.drop 1 st Seq.|> a
|
|
Packit |
368400 |
in CI.Emit (Right (s', st')) st'
|
|
Packit |
368400 |
{-# INLINE slidingWindowS #-}
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingVectorC :: V.Vector v a => Int -> Conduit a IO (v a)
|
|
Packit |
368400 |
slidingVectorC = slidingVectorCC
|
|
Packit |
368400 |
{-# INLINE [0] slidingVectorC #-}
|
|
Packit |
368400 |
{-# RULES "unstream slidingVectorC"
|
|
Packit |
368400 |
forall i. slidingVectorC i = CI.unstream (CI.streamConduit (slidingVectorCC i) (slidingVectorS i))
|
|
Packit |
368400 |
#-}
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingVectorCC :: V.Vector v a => Int -> Conduit a IO (v a)
|
|
Packit |
368400 |
slidingVectorCC sz = do
|
|
Packit |
368400 |
mv <- newBuf
|
|
Packit |
368400 |
mv2 <- newBuf
|
|
Packit |
368400 |
go 0 mv mv2
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
bufSz = 2 * sz
|
|
Packit |
368400 |
newBuf = liftIO (VM.new bufSz)
|
|
Packit |
368400 |
|
|
Packit |
368400 |
go !end _mv mv2 | end == bufSz = newBuf >>= go sz mv2
|
|
Packit |
368400 |
go !end mv mv2 = do
|
|
Packit |
368400 |
mx <- await
|
|
Packit |
368400 |
case mx of
|
|
Packit |
368400 |
Nothing -> when (end > 0 && end < sz) $ do
|
|
Packit |
368400 |
v <- liftIO $ V.unsafeFreeze $ VM.take end mv
|
|
Packit |
368400 |
yield v
|
|
Packit |
368400 |
Just x -> do
|
|
Packit |
368400 |
liftIO $ do
|
|
Packit |
368400 |
VM.unsafeWrite mv end x
|
|
Packit |
368400 |
when (end > sz) $ VM.unsafeWrite mv2 (end - sz) x
|
|
Packit |
368400 |
let end' = end + 1
|
|
Packit |
368400 |
when (end' >= sz) $ do
|
|
Packit |
368400 |
v <- liftIO $ V.unsafeFreeze $ VM.unsafeSlice (end' - sz) sz mv
|
|
Packit |
368400 |
yield v
|
|
Packit |
368400 |
go end' mv mv2
|
|
Packit |
368400 |
|
|
Packit |
368400 |
slidingVectorS :: V.Vector v a => Int -> CI.Stream IO a () -> CI.Stream IO (v a) ()
|
|
Packit |
368400 |
slidingVectorS sz (CI.Stream step ms0) =
|
|
Packit |
368400 |
CI.Stream step' ms1
|
|
Packit |
368400 |
where
|
|
Packit |
368400 |
bufSz = 2 * sz
|
|
Packit |
368400 |
newBuf = liftIO (VM.new bufSz)
|
|
Packit |
368400 |
|
|
Packit |
368400 |
ms1 = do
|
|
Packit |
368400 |
s <- ms0
|
|
Packit |
368400 |
mv <- newBuf
|
|
Packit |
368400 |
mv2 <- newBuf
|
|
Packit |
368400 |
return (s, 0, mv, mv2)
|
|
Packit |
368400 |
|
|
Packit |
368400 |
step' (_, -1, _, _) = return $ CI.Stop ()
|
|
Packit |
368400 |
step' (s, end, _mv, mv2) | end == bufSz = do
|
|
Packit |
368400 |
mv3 <- newBuf
|
|
Packit |
368400 |
return $ CI.Skip (s, sz, mv2, mv3)
|
|
Packit |
368400 |
step' (s, end, mv, mv2) = do
|
|
Packit |
368400 |
res <- step s
|
|
Packit |
368400 |
case res of
|
|
Packit |
368400 |
CI.Stop ()
|
|
Packit |
368400 |
| end > 0 && end < sz -> do
|
|
Packit |
368400 |
v <- liftIO $ V.unsafeFreeze $ VM.take end mv
|
|
Packit |
368400 |
return $ CI.Emit (s, -1, mv, mv2) v
|
|
Packit |
368400 |
| otherwise -> return $ CI.Stop ()
|
|
Packit |
368400 |
CI.Skip s' -> return $ CI.Skip (s', end, mv, mv2)
|
|
Packit |
368400 |
CI.Emit s' x -> liftIO $ do
|
|
Packit |
368400 |
VM.unsafeWrite mv end x
|
|
Packit |
368400 |
when (end > sz) $ VM.unsafeWrite mv2 (end - sz) x
|
|
Packit |
368400 |
let end' = end + 1
|
|
Packit |
368400 |
state = (s', end', mv, mv2)
|
|
Packit |
368400 |
if end' >= sz
|
|
Packit |
368400 |
then do
|
|
Packit |
368400 |
v <- V.unsafeFreeze $ VM.unsafeSlice (end' - sz) sz mv
|
|
Packit |
368400 |
return $ CI.Emit state v
|
|
Packit |
368400 |
else return $ CI.Skip state
|
|
Packit |
368400 |
{-# INLINE slidingVectorS #-}
|