module Data.VectorBuilder.Storable
(VectorBuilder, new, indexFromEnd, insert, push, pop, updateStackElt, getCount, getStackCount, finalize, unsafeToMVector, peek
) where
import Control.Exception (assert)
import Control.Monad
import Control.Monad.ST.Unsafe
import Control.Monad.Primitive
import Data.Int
import Data.Primitive.MutVar
import qualified Data.Vector.Storable as S
import qualified Data.Vector.Storable.Mutable as SM
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector.Unboxed.Mutable as U
import Foreign (Storable(sizeOf), Ptr, plusPtr)
import Foreign.ForeignPtr
import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
import Config
import Text.Printf
default (Int, Double)
data VectorBuilder s a =
VectorBuilder
{
next :: !(U.MVector s Int32)
, store :: !(MutVar s (S.MVector s a))
}
readU :: (Config, _) => _
writeU :: (Config, _) => _
writeM :: (Config, _) => _
readM :: (Config, _) => _
copyM :: (Config, _) => _
sliceM :: (Config, _) => _
getCount, getStackCount :: Config => PrimMonad m => VectorBuilder(PrimState m) a -> m Int32
#ifdef ENABLE_VECTOR_CHECKS
readU a = U.read a
writeU a = U.write a
writeM a ix = M.write a (fromIntegral ix)
readM a ix = M.read a (fromIntegral ix)
copyM a = M.copy a
sliceM a b = M.slice (fromIntegral a) (fromIntegral b)
#else
readU a = U.unsafeRead a
writeU a = U.unsafeWrite a
writeM a !ix = M.unsafeWrite a (fromIntegral ix)
readM a !ix = M.unsafeRead a (fromIntegral ix)
copyM a = M.unsafeCopy a
sliceM a b = M.unsafeSlice (fromIntegral a) (fromIntegral b)
#endif
getCount l = readU (next l) 0
getStackCount l = readU (next l) 1
request :: (Config, Storable a, PrimMonad m) => Int32 -> VectorBuilder (PrimState m) a -> m ()
request !n VectorBuilder{next,store} = do
frontCount <- readU (next) 0
backCount <- readU (next) 1
assert (frontCount >= 0) $ return ()
assert (backCount >= 0) $ return ()
a <- readMutVar (store)
let !len = M.length a
unless (frontCount + backCount + n < fromIntegral len) $ do
return ()
a' <- newVectorAllocatedExternally(len*2)
copyM (sliceM 0 frontCount a') (sliceM 0 frontCount a)
copyM (sliceM (2 * fromIntegral len backCount) backCount a') (sliceM (fromIntegral len backCount) backCount a)
writeMutVar (store ) a'
insert :: (Config, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> a -> m ()
insert l@VectorBuilder{next,store} v = do
request 1 l
nextI <- readU (next ) 0
writeU (next ) 0 (nextI + 1)
a <- readMutVar (store )
writeM a nextI v
push :: (Config, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> a -> m Int32
push l@VectorBuilder{next,store} !v = do
request 1 l
stackCount <- readU (next) 1
writeU (next) 1 (stackCount + 1)
assert (stackCount >= 0) $ return ()
a <- readMutVar (store)
let ix = (fromIntegral $ M.length a) stackCount 1
writeM a ix v
return stackCount
peek :: Config => (Storable a, PrimMonad m, Storable a, Num n, Integral n, Ord n) => VectorBuilder (PrimState m) a -> n -> m a
peek VectorBuilder{next, store} n = do
backCount <- readU next 1
assert(fromIntegral backCount > n) $ return ()
a <- readMutVar store
readM a (M.length a fromIntegral backCount 1 + fromIntegral n)
updateStackElt :: Config => (Storable a, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> Int32 -> (a -> a) -> m ()
updateStackElt VectorBuilder{store} i f = do
arr <- readMutVar store
let ix = (M.length arr fromIntegral i 1)
a <- readM arr ix
writeM arr ix (f a)
indexFromEnd :: forall a m . Config => (Storable a, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> Int32 -> m (Ptr a)
indexFromEnd VectorBuilder{store} i = do
a <- readMutVar store
let (fptr, _) = SM.unsafeToForeignPtr0 a
let ptr = unsafeForeignPtrToPtr fptr
let s = sizeOf(undefined :: a)
return $ plusPtr ptr ((M.length a fromIntegral i 1) * s)
unsafeToMVector l = readMutVar (store l)
pop :: Config => (Storable a, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> Int32 -> m ()
pop l@VectorBuilder{next, store} n = do
request n l
backCount <- readU next 1
frontCount <- readU next 0
assert(backCount >= n) $ return ()
writeU next 0 (frontCount + n)
writeU next 1 (backCount n)
a <- readMutVar store
let !l = M.length a
let !first = fromIntegral l backCount
forM_ [1..n] $ \i ->
let from = frontCount 1 + i
to = first+ni
in when (from /= to) $
copyM (sliceM from 1 a) (sliceM to 1 a)
finalize :: (Config, PrimMonad m, Storable a) => VectorBuilder (PrimState m) a -> m (S.Vector a)
finalize l = trace "VectorBuilder.finalize" $ do
v <- readMutVar (store l)
frontCount <- readU (next l) 0
S.unsafeFreeze (sliceM 0 frontCount v)
new :: (Config, PrimMonad m, Storable a) => Int -> m (VectorBuilder (PrimState m) a)
new initialSize = do
next <- U.unsafeNew 2
writeU next 0 0
writeU next 1 0
store <- newVectorAllocatedExternally initialSize
storeRef <- newMutVar store
return (VectorBuilder next storeRef)
newVectorAllocatedExternally size = (`SM.unsafeFromForeignPtr0` size) <$> primToPrim (unsafeIOToST $ mallocForeignPtrArray size)