module ToySolver.Internal.Data.Vec
(
GenericVec
, Vec
, UVec
, Index
, new
, clone
, getSize
, read
, write
, unsafeRead
, unsafeWrite
, resize
, growTo
, push
, unsafePop
, clear
, getElems
, getArray
, getCapacity
, resizeCapacity
) where
import Prelude hiding (read)
import Control.Loop
import Control.Monad
import Data.Ix
import qualified Data.Array.Base as A
import qualified Data.Array.IO as A
import Data.IORef
import ToySolver.Internal.Data.IOURef
data GenericVec a e = GenericVec !(IOURef Int) !(IORef (a Index e))
deriving Eq
type Vec e = GenericVec A.IOArray e
type UVec e = GenericVec A.IOUArray e
type Index = Int
new :: A.MArray a e IO => IO (GenericVec a e)
new = do
sizeRef <- newIOURef 0
arrayRef <- newIORef =<< A.newArray_ (0,1)
return $ GenericVec sizeRef arrayRef
getSize :: A.MArray a e IO => GenericVec a e -> IO Int
getSize (GenericVec sizeRef _) = readIOURef sizeRef
read :: A.MArray a e IO => GenericVec a e -> Int -> IO e
read !v !i = do
a <- getArray v
s <- getSize v
if 0 <= i && i < s then
A.unsafeRead a i
else
error $ "ToySolver.Data.Vec.read: index " ++ show i ++ " out of bounds"
write :: A.MArray a e IO => GenericVec a e -> Int -> e -> IO ()
write !v !i e = do
a <- getArray v
s <- getSize v
if 0 <= i && i < s then
A.unsafeWrite a i e
else
error $ "ToySolver.Data.Vec.write: index " ++ show i ++ " out of bounds"
unsafeRead :: A.MArray a e IO => GenericVec a e -> Int -> IO e
unsafeRead !v !i = do
a <- getArray v
A.unsafeRead a i
unsafeWrite :: A.MArray a e IO => GenericVec a e -> Int -> e -> IO ()
unsafeWrite !v !i e = do
a <- getArray v
A.unsafeWrite a i e
resize :: A.MArray a e IO => GenericVec a e -> Int -> IO ()
resize v@(GenericVec sizeRef arrayRef) !n = do
a <- getArray v
capa <- getCapacity v
unless (n <= capa) $ do
let capa' = max 2 (capa * 3 `div` 2)
a' <- A.newArray_ (0, capa'1)
copyTo a a' (0,capa1)
writeIORef arrayRef a'
writeIOURef sizeRef n
growTo :: A.MArray a e IO => GenericVec a e -> Int -> IO ()
growTo v !n = do
m <- getSize v
when (m < n) $ resize v n
push :: A.MArray a e IO => GenericVec a e -> e -> IO ()
push v e = do
s <- getSize v
resize v (s+1)
unsafeWrite v s e
unsafePop :: A.MArray a e IO => GenericVec a e -> IO e
unsafePop v = do
s <- getSize v
e <- unsafeRead v (s1)
resize v (s1)
return e
clear :: A.MArray a e IO => GenericVec a e -> IO ()
clear v = resize v 0
getElems :: A.MArray a e IO => GenericVec a e -> IO [e]
getElems v = do
s <- getSize v
forM [0..s1] $ \i -> unsafeRead v i
clone :: A.MArray a e IO => GenericVec a e -> IO (GenericVec a e)
clone (GenericVec sizeRef arrayRef) = do
a <- readIORef arrayRef
arrayRef' <- newIORef =<< cloneArray a
sizeRef' <- newIOURef =<< readIOURef sizeRef
return $ GenericVec sizeRef' arrayRef'
getArray :: GenericVec a e -> IO (a Index e)
getArray (GenericVec _ arrayRef) = readIORef arrayRef
getCapacity :: A.MArray a e IO => GenericVec a e -> IO Int
getCapacity vec = liftM rangeSize $ A.getBounds =<< getArray vec
resizeCapacity :: A.MArray a e IO => GenericVec a e -> Int -> IO ()
resizeCapacity (GenericVec sizeRef arrayRef) capa = do
n <- readIOURef sizeRef
arr <- readIORef arrayRef
capa0 <- liftM rangeSize $ A.getBounds arr
when (capa0 < capa) $ do
arr' <- A.newArray_ (0, capa1)
copyTo arr arr' (0, n1)
writeIORef arrayRef arr'
cloneArray :: (A.MArray a e m) => a Index e -> m (a Index e)
cloneArray arr = do
b <- A.getBounds arr
arr' <- A.newArray_ b
copyTo arr arr' b
return arr'
copyTo :: (A.MArray a e m) => a Index e -> a Index e -> (Index,Index) -> m ()
copyTo fromArr toArr (!lb,!ub) = do
forLoop lb (<=ub) (+1) $ \i -> do
val_i <- A.unsafeRead fromArr i
A.unsafeWrite toArr i val_i