module ToySolver.Data.Vec
(
GenericVec
, Vec
, UVec
, Index
, new
, clone
, getSize
, read
, write
, unsafeRead
, unsafeWrite
, resize
, growTo
, push
, 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
newtype GenericVec a e = GenericVec (IORef (Int, 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
a <- A.newArray_ (0,1)
ref <- newIORef (0,a)
return $ GenericVec ref
getSize :: A.MArray a e IO => GenericVec a e -> IO Int
getSize (GenericVec ref) = liftM fst $ readIORef ref
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 ref) !n = do
a <- getArray v
capa <- getCapacity v
if n <= capa then do
writeIORef ref (n,a)
else do
let capa' = max 2 (capa * 3 `div` 2)
a' <- A.newArray_ (0, capa'1)
copyTo a a' (0,capa1)
writeIORef ref (n,a')
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
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 ref) = do
(n,a) <- readIORef ref
a' <- cloneArray a
liftM GenericVec $ newIORef (n,a')
getArray :: GenericVec a e -> IO (a Index e)
getArray (GenericVec ref) = liftM snd $ readIORef ref
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 ref) capa = do
(n,arr) <- readIORef ref
capa0 <- liftM rangeSize $ A.getBounds arr
when (capa0 < capa) $ do
arr' <- A.newArray_ (0, capa1)
copyTo arr arr' (0, n1)
writeIORef ref (n,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