{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
module System.IO.Streams.Vector
(
fromVector
, toVector
, toVectorSized
, outputToVector
, outputToVectorSized
, toMutableVector
, toMutableVectorSized
, outputToMutableVector
, outputToMutableVectorSized
, writeVector
, chunkVector
, vectorOutputStream
, vectorOutputStreamSized
, mutableVectorOutputStream
, mutableVectorOutputStreamSized
) where
import Control.Concurrent.MVar (modifyMVar, modifyMVar_, newMVar)
import Control.Monad (liftM, (>=>))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Primitive (PrimState (..))
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Vector.Generic (Vector (..))
import qualified Data.Vector.Generic as V
import Data.Vector.Generic.Mutable (MVector)
import qualified Data.Vector.Generic.Mutable as VM
import System.IO.Streams.Internal (InputStream, OutputStream, fromGenerator, yield)
import qualified System.IO.Streams.Internal as S
fromVector :: Vector v a => v a -> IO (InputStream a)
fromVector = fromGenerator . V.mapM_ yield
{-# INLINE fromVector #-}
toVector :: Vector v a => InputStream a -> IO (v a)
toVector = toVectorSized dEFAULT_BUFSIZ
{-# INLINE toVector #-}
toVectorSized :: Vector v a => Int -> InputStream a -> IO (v a)
toVectorSized n = toMutableVectorSized n >=> V.basicUnsafeFreeze
{-# INLINE toVectorSized #-}
toMutableVector :: VM.MVector v a => InputStream a -> IO (v (PrimState IO) a)
toMutableVector = toMutableVectorSized dEFAULT_BUFSIZ
toMutableVectorSized :: VM.MVector v a =>
Int
-> InputStream a
-> IO (v (PrimState IO) a)
toMutableVectorSized initialSize input = vfNew initialSize >>= go
where
go vfi = S.read input >>= maybe (vfFinish vfi) (vfAppend vfi >=> go)
{-# INLINE toMutableVectorSized #-}
vectorOutputStream :: Vector v c => IO (OutputStream c, IO (v c))
vectorOutputStream = vectorOutputStreamSized dEFAULT_BUFSIZ
{-# INLINE vectorOutputStream #-}
vectorOutputStreamSized :: Vector v c => Int -> IO (OutputStream c, IO (v c))
vectorOutputStreamSized n = do
(os, flush) <- mutableVectorOutputStreamSized n
return $! (os, flush >>= V.basicUnsafeFreeze)
data VectorFillInfo v c = VectorFillInfo {
_vec :: !(v (PrimState IO) c)
, _idx :: {-# UNPACK #-} !(IORef Int)
, _sz :: {-# UNPACK #-} !(IORef Int)
}
vfNew :: MVector v a => Int -> IO (VectorFillInfo v a)
vfNew initialSize = do
v <- VM.unsafeNew initialSize
i <- newIORef 0
sz <- newIORef initialSize
return $! VectorFillInfo v i sz
vfFinish :: MVector v a =>
VectorFillInfo v a
-> IO (v (PrimState IO) a)
vfFinish vfi = liftM (flip VM.unsafeTake v) $ readIORef i
where
v = _vec vfi
i = _idx vfi
vfAppend :: MVector v a =>
VectorFillInfo v a
-> a
-> IO (VectorFillInfo v a)
vfAppend vfi !x = do
i <- readIORef iRef
sz <- readIORef szRef
if i < sz then add i else grow sz
where
v = _vec vfi
iRef = _idx vfi
szRef = _sz vfi
add i = do
VM.unsafeWrite v i x
writeIORef iRef $! i + 1
return vfi
grow sz = do
let !sz' = sz * 2
v' <- VM.unsafeGrow v sz
writeIORef szRef sz'
vfAppend (vfi { _vec = v' }) x
mutableVectorOutputStream :: VM.MVector v c =>
IO (OutputStream c, IO (v (PrimState IO) c))
mutableVectorOutputStream = mutableVectorOutputStreamSized dEFAULT_BUFSIZ
mutableVectorOutputStreamSized :: VM.MVector v c =>
Int
-> IO (OutputStream c, IO (v (PrimState IO) c))
mutableVectorOutputStreamSized initialSize = do
r <- vfNew initialSize >>= newMVar
c <- S.fromConsumer $ consumer r
return (c, flush r)
where
consumer r = go
where
go = S.await >>=
(maybe (return $! ()) $ \c -> do
liftIO $ modifyMVar_ r $ flip vfAppend c
go)
flush r = modifyMVar r $ \vfi -> do
!v <- vfFinish vfi
vfi' <- vfNew initialSize
return $! (vfi', v)
{-# INLINE mutableVectorOutputStreamSized #-}
outputToMutableVector :: MVector v a =>
(OutputStream a -> IO b)
-> IO (v (PrimState IO) a)
outputToMutableVector = outputToMutableVectorSized dEFAULT_BUFSIZ
{-# INLINE outputToMutableVector #-}
outputToMutableVectorSized :: MVector v a =>
Int
-> (OutputStream a -> IO b)
-> IO (v (PrimState IO) a)
outputToMutableVectorSized n f = do
(os, getVec) <- mutableVectorOutputStreamSized n
_ <- f os
getVec
{-# INLINE outputToMutableVectorSized #-}
outputToVector :: Vector v a => (OutputStream a -> IO b) -> IO (v a)
outputToVector = outputToVectorSized dEFAULT_BUFSIZ
{-# INLINE outputToVector #-}
outputToVectorSized :: Vector v a =>
Int
-> (OutputStream a -> IO b)
-> IO (v a)
outputToVectorSized n = outputToMutableVectorSized n >=> V.basicUnsafeFreeze
{-# INLINE outputToVectorSized #-}
chunkVector :: Vector v a => Int -> InputStream a -> IO (InputStream (v a))
chunkVector n input = if n <= 0
then error $ "chunkVector: bad size: " ++ show n
else vfNew n >>= fromGenerator . go n
where
doneChunk !vfi = do
liftIO (vfFinish vfi >>= V.unsafeFreeze) >>= yield
!vfi' <- liftIO $ vfNew n
go n vfi'
go !k !vfi | k <= 0 = doneChunk vfi
| otherwise = liftIO (S.read input) >>= maybe finish chunk
where
finish = do
v <- liftIO (vfFinish vfi >>= V.unsafeFreeze)
if V.null v then return $! () else yield v
chunk x = do
!vfi' <- liftIO $ vfAppend vfi x
go (k - 1) vfi'
{-# INLINE chunkVector #-}
writeVector :: Vector v a => v a -> OutputStream a -> IO ()
writeVector v out = V.mapM_ (flip S.write out . Just) v
{-# INLINE writeVector #-}
dEFAULT_BUFSIZ :: Int
dEFAULT_BUFSIZ = 64