module Data.StorableVector.Cursor where
import Control.Exception (assert, )
import Control.Monad.Trans.State (StateT(StateT), runStateT, )
import Data.IORef (IORef, newIORef, readIORef, writeIORef, )
import Foreign.Storable (Storable(peekElemOff, pokeElemOff))
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr, )
import Data.StorableVector.Memory (mallocForeignPtrArray, )
import Control.Monad (when)
import Data.Maybe (isNothing)
import System.IO.Unsafe (unsafePerformIO, unsafeInterleaveIO, )
import qualified Data.List.HT as ListHT
import Data.Tuple.HT (mapSnd, )
import Prelude hiding (length, foldr, zipWith, take, drop, )
data Generator a =
forall s.
Generator
!(StateT s Maybe a)
!(IORef (Maybe s))
data Buffer a =
Buffer {
memory :: !(ForeignPtr a),
size :: !Int,
gen :: !(Generator a),
cursor :: !(IORef Int)
}
data Vector a =
Vector {
buffer :: !(Buffer a),
start :: !Int,
maxLen :: !Int
}
create :: (Storable a) => Int -> Generator a -> Buffer a
create l g = unsafePerformIO (createIO l g)
createIO :: (Storable a) => Int -> Generator a -> IO (Buffer a)
createIO l g = do
fp <- mallocForeignPtrArray l
cur <- newIORef 0
return $! Buffer fp l g cur
unfoldrNTerm :: (Storable b) =>
Int -> (a -> Maybe (b, a)) -> a -> Vector b
unfoldrNTerm l f x0 =
unsafePerformIO (unfoldrNTermIO l f x0)
unfoldrNTermIO :: (Storable b) =>
Int -> (a -> Maybe (b, a)) -> a -> IO (Vector b)
unfoldrNTermIO l f x0 =
do ref <- newIORef (Just x0)
buf <- createIO l (Generator (StateT f) ref)
return (Vector buf 0 l)
unfoldrN :: (Storable b) =>
Int -> (a -> Maybe (b, a)) -> a -> (Vector b, Maybe a)
unfoldrN l f x0 =
unsafePerformIO (unfoldrNIO l f x0)
unfoldrNIO :: (Storable b) =>
Int -> (a -> Maybe (b, a)) -> a -> IO (Vector b, Maybe a)
unfoldrNIO l f x0 =
do ref <- newIORef (Just x0)
buf <- createIO l (Generator (StateT f) ref)
s <- unsafeInterleaveIO $
do evaluateToIO l buf
readIORef ref
return (Vector buf 0 l, s)
pack :: (Storable a) => Int -> [a] -> Vector a
pack n = unfoldrNTerm n ListHT.viewL
cons :: Storable a =>
a -> Vector a -> Vector a
cons x xs =
unfoldrNTerm (succ (maxLen xs))
(\(mx0,xs0) ->
fmap (mapSnd ((,) Nothing)) $
maybe
(viewL xs0)
(\x0 -> Just (x0, xs0))
mx0) $
(Just x, xs)
zipWith :: (Storable a, Storable b, Storable c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
zipWith f ps0 qs0 =
zipNWith (min (maxLen ps0) (maxLen qs0)) f ps0 qs0
zipNWith :: (Storable a, Storable b, Storable c) =>
Int -> (a -> b -> c) -> Vector a -> Vector b -> Vector c
zipNWith n f ps0 qs0 =
unfoldrNTerm n
(\(ps,qs) ->
do (ph,pt) <- viewL ps
(qh,qt) <- viewL qs
return (f ph qh, (pt,qt)))
(ps0,qs0)
advanceIO :: Storable a =>
Buffer a -> IO (Maybe a)
advanceIO (Buffer p sz (Generator n s) cr) =
do c <- readIORef cr
assert (c < sz) $
do writeIORef cr (succ c)
ms <- readIORef s
case ms of
Nothing -> return Nothing
Just s0 ->
case runStateT n s0 of
Nothing ->
writeIORef s Nothing >>
return Nothing
Just (a,s1) ->
writeIORef s (Just s1) >>
withForeignPtr p (\q -> pokeElemOff q c a) >>
return (Just a)
evaluateToIO :: Storable a =>
Int -> Buffer a -> IO ()
evaluateToIO l buf@(Buffer _p _sz _g cr) =
whileM
(fmap (<l) (readIORef cr))
(advanceIO buf)
whileM :: Monad m => m Bool -> m a -> m ()
whileM p f =
let recourse =
do b <- p
when b (f >> recourse)
in recourse
switchL :: Storable a => b -> (a -> Vector a -> b) -> Vector a -> b
switchL n j v = maybe n (uncurry j) (viewL v)
obviousNullIO :: Vector a -> IO Bool
obviousNullIO (Vector (Buffer _ _ (Generator _ s) _) _ ml) =
assert (ml >= 0) $
do b <- readIORef s
return (ml == 0 || isNothing b)
viewL :: Storable a => Vector a -> Maybe (a, Vector a)
viewL v = unsafePerformIO (viewLIO v)
viewLIO :: Storable a => Vector a -> IO (Maybe (a, Vector a))
viewLIO (Vector buf st ml) =
do c <- readIORef (cursor buf)
fmap (fmap (\a -> (a, Vector buf (succ st) (pred ml)))) $
assert (st <= c) $
if st == c
then advanceIO buf
else fmap Just $ withForeignPtr (memory buf) (\p -> peekElemOff p st)
foldr :: (Storable a) => (a -> b -> b) -> b -> Vector a -> b
foldr k z =
let recourse = switchL z (\h t -> k h (recourse t))
in recourse
unpack :: (Storable a) => Vector a -> [a]
unpack = foldr (:) []
instance (Show a, Storable a) => Show (Vector a) where
showsPrec p x = showsPrec p (unpack x)
null :: Storable a => Vector a -> Bool
null = switchL True (const (const False))
drop :: (Storable a) => Int -> Vector a -> Vector a
drop n v = unsafePerformIO $ dropIO n v
dropIO :: (Storable a) => Int -> Vector a -> IO (Vector a)
dropIO n v =
assert (n>=0) $
let pos = min (maxLen v) (start v + n)
in do evaluateToIO pos (buffer v)
return (Vector (buffer v) pos (max 0 (maxLen v n)))
take :: (Storable a) => Int -> Vector a -> Vector a
take n v =
assert (n>=0) $
v{maxLen = min n (maxLen v)}
filter :: (Storable a) => (a -> Bool) -> Vector a -> Vector a
filter p xs0 =
unfoldrNTerm (maxLen xs0)
(let recourse = switchL Nothing (\x xs -> if p x then Just (x,xs) else recourse xs)
in recourse)
xs0