{-# LANGUAGE FlexibleContexts #-} -- | -- Module : Simulation.Aivika.Trans.Vector -- Copyright : Copyright (c) 2009-2017, David Sorokin -- License : BSD3 -- Maintainer : David Sorokin -- Stability : experimental -- Tested with: GHC 8.0.1 -- -- An imperative vector. -- module Simulation.Aivika.Trans.Vector (Vector, newVector, copyVector, vectorCount, appendVector, readVector, writeVector, vectorBinarySearch, vectorInsert, vectorDeleteAt, vectorDeleteRange, vectorDelete, vectorDeleteBy, vectorIndex, vectorIndexBy, vectorContains, vectorContainsBy, freezeVector) where import Data.Array import Control.Monad import Simulation.Aivika.Trans.Simulation import Simulation.Aivika.Trans.Event import Simulation.Aivika.Trans.Ref.Base.Lazy -- | Represents a resizable vector. data Vector m a = Vector { vectorArrayRef :: Ref m (Array Int (Ref m a)), vectorCountRef :: Ref m Int, vectorCapacityRef :: Ref m Int } -- | Create a new vector. newVector :: MonadRef m => Simulation m (Vector m a) {-# INLINABLE newVector #-} newVector = do xs <- forM [0 .. 4 - 1] $ \i -> newRef undefined let arr = array (0, 4 - 1) $ zip [0..] xs arrRef <- newRef $! arr countRef <- newRef $! 0 capacityRef <- newRef $! 4 return Vector { vectorArrayRef = arrRef, vectorCountRef = countRef, vectorCapacityRef = capacityRef } -- | Copy the vector. copyVector :: MonadRef m => Vector m a -> Event m (Vector m a) {-# INLINABLE copyVector #-} copyVector vector = do arr <- readRef (vectorArrayRef vector) count <- readRef (vectorCountRef vector) xs' <- forM [0 .. count - 1] $ \i -> do x <- readRef (arr ! i) liftSimulation $ newRef x let arr' = array (0, count - 1) $ zip [0..] xs' arrRef' <- liftSimulation $ newRef $! arr' countRef' <- liftSimulation $ newRef $! count capacityRef' <- liftSimulation $ newRef $! count return Vector { vectorArrayRef = arrRef', vectorCountRef = countRef', vectorCapacityRef = capacityRef' } -- | Ensure that the vector has the specified capacity. vectorEnsureCapacity :: MonadRef m => Vector m a -> Int -> Event m () {-# INLINABLE vectorEnsureCapacity #-} vectorEnsureCapacity vector capacity = do capacity' <- readRef (vectorCapacityRef vector) when (capacity' < capacity) $ do arr' <- readRef (vectorArrayRef vector) count' <- readRef (vectorCountRef vector) let capacity'' = max (2 * capacity') capacity xs'' <- forM [0 .. capacity'' - 1] $ \i -> liftSimulation $ newRef undefined let arr'' = array (0, capacity'' - 1) $ zip [0..] xs'' forM_ [0 .. count' - 1] $ \i -> do x <- readRef (arr' ! i) writeRef (arr'' ! i) x writeRef (vectorArrayRef vector) $! arr'' writeRef (vectorCapacityRef vector) $! capacity'' -- | Return the element count. vectorCount :: MonadRef m => Vector m a -> Event m Int {-# INLINABLE vectorCount #-} vectorCount vector = readRef (vectorCountRef vector) -- | Add the specified element to the end of the vector. appendVector :: MonadRef m => Vector m a -> a -> Event m () {-# INLINABLE appendVector #-} appendVector vector item = do count <- readRef (vectorCountRef vector) vectorEnsureCapacity vector (count + 1) arr <- readRef (vectorArrayRef vector) writeRef (arr ! count) $! item writeRef (vectorCountRef vector) $! (count + 1) -- | Read a value from the vector, where indices are started from 0. readVector :: MonadRef m => Vector m a -> Int -> Event m a {-# INLINABLE readVector #-} readVector vector index = do arr <- readRef (vectorArrayRef vector) readRef (arr ! index) -- | Set an array item at the specified index which is started from 0. writeVector :: MonadRef m => Vector m a -> Int -> a -> Event m () {-# INLINABLE writeVector #-} writeVector vector index item = do arr <- readRef (vectorArrayRef vector) writeRef (arr ! index) $! item vectorBinarySearch' :: (MonadRef m, Ord a) => Array Int (Ref m a) -> a -> Int -> Int -> Event m Int {-# INLINABLE vectorBinarySearch' #-} vectorBinarySearch' arr item left right = if left > right then return $ - (right + 1) - 1 else do let index = (left + right) `div` 2 curr <- readRef (arr ! index) if item < curr then vectorBinarySearch' arr item left (index - 1) else if item == curr then return index else vectorBinarySearch' arr item (index + 1) right -- | Return the index of the specified element using binary search; otherwise, -- a negated insertion index minus one: 0 -> -0 - 1, ..., i -> -i - 1, .... vectorBinarySearch :: (MonadRef m, Ord a) => Vector m a -> a -> Event m Int {-# INLINABLE vectorBinarySearch #-} vectorBinarySearch vector item = do arr <- readRef (vectorArrayRef vector) count <- readRef (vectorCountRef vector) vectorBinarySearch' arr item 0 (count - 1) -- | Return the elements of the vector in an immutable array. freezeVector :: MonadRef m => Vector m a -> Event m (Array Int a) {-# INLINABLE freezeVector #-} freezeVector vector = do arr <- readRef (vectorArrayRef vector) count <- readRef (vectorCountRef vector) xs' <- forM [0 .. count - 1] $ \i -> readRef (arr ! i) let arr' = array (0, count - 1) $ zip [0..] xs' return arr' -- | Insert the element in the vector at the specified index. vectorInsert :: MonadRef m => Vector m a -> Int -> a -> Event m () {-# INLINABLE vectorInsert #-} vectorInsert vector index item = do count <- readRef (vectorCountRef vector) when (index < 0) $ error $ "Index cannot be " ++ "negative: vectorInsert." when (index > count) $ error $ "Index cannot be greater " ++ "than the count: vectorInsert." vectorEnsureCapacity vector (count + 1) arr <- readRef (vectorArrayRef vector) forM_ [count, count - 1 .. index + 1] $ \i -> do x <- readRef (arr ! (i - 1)) writeRef (arr ! i) x writeRef (arr ! index) $! item writeRef (vectorCountRef vector) $! (count + 1) -- | Delete the element at the specified index. vectorDeleteAt :: MonadRef m => Vector m a -> Int -> Event m () {-# INLINABLE vectorDeleteAt #-} vectorDeleteAt vector index = do count <- readRef (vectorCountRef vector) when (index < 0) $ error $ "Index cannot be " ++ "negative: vectorDeleteAt." when (index >= count) $ error $ "Index must be less " ++ "than the count: vectorDeleteAt." arr <- readRef (vectorArrayRef vector) forM_ [index, index + 1 .. count - 2] $ \i -> do x <- readRef (arr ! (i + 1)) writeRef (arr ! i) x writeRef (arr ! (count - 1)) undefined writeRef (vectorCountRef vector) $! (count - 1) -- | Delete the specified range of elements. vectorDeleteRange :: MonadRef m => Vector m a -- ^ the vector -> Int -- ^ the start index -> Int -- ^ the count of items to be removed -> Event m () {-# INLINABLE vectorDeleteRange #-} vectorDeleteRange vector index len = do count <- readRef (vectorCountRef vector) when (index < 0) $ error $ "The first index cannot be " ++ "negative: vectorDeleteRange." when (index + len - 1 >= count) $ error $ "The last index must be less " ++ "than the count: vectorDeleteRange." when (len < 0) $ error "Negative range length: vectorDeleteRange." arr <- readRef (vectorArrayRef vector) forM_ [index, index + 1 .. (count - len) - 1] $ \i -> do x <- readRef (arr ! (i + len)) writeRef (arr ! i) x forM_ [(count - len) .. count - 1] $ \i -> writeRef (arr ! i) undefined writeRef (vectorCountRef vector) $! (count - len) -- | Return the index of the item or -1. vectorIndex :: (MonadRef m, Eq a) => Vector m a -> a -> Event m Int {-# INLINABLE vectorIndex #-} vectorIndex vector item = do count <- readRef (vectorCountRef vector) arr <- readRef (vectorArrayRef vector) let loop index = if index >= count then return $ -1 else do x <- readRef (arr ! index) if item == x then return index else loop $ index + 1 loop 0 -- | Return an index of the item satisfying the predicate or -1. vectorIndexBy :: MonadRef m => Vector m a -> (a -> Bool) -> Event m Int {-# INLINABLE vectorIndexBy #-} vectorIndexBy vector pred = do count <- readRef (vectorCountRef vector) arr <- readRef (vectorArrayRef vector) let loop index = if index >= count then return $ -1 else do x <- readRef (arr ! index) if pred x then return index else loop $ index + 1 loop 0 -- | Remove the specified element and return a flag indicating -- whether the element was found and removed. vectorDelete :: (MonadRef m, Eq a) => Vector m a -> a -> Event m Bool {-# INLINABLE vectorDelete #-} vectorDelete vector item = do index <- vectorIndex vector item if index >= 0 then do vectorDeleteAt vector index return True else return False -- | Remove an element by the specified predicate and return the element if found. vectorDeleteBy :: MonadRef m => Vector m a -> (a -> Bool) -> Event m (Maybe a) {-# INLINABLE vectorDeleteBy #-} vectorDeleteBy vector pred = do index <- vectorIndexBy vector pred if index >= 0 then do a <- readVector vector index vectorDeleteAt vector index return (Just a) else return Nothing -- | Detect whether the specified element is contained in the vector. vectorContains :: (MonadRef m, Eq a) => Vector m a -> a -> Event m Bool {-# INLINABLE vectorContains #-} vectorContains vector item = do index <- vectorIndex vector item return (index >= 0) -- | Detect whether an element satisfying the specified predicate is contained in the vector. vectorContainsBy :: MonadRef m => Vector m a -> (a -> Bool) -> Event m (Maybe a) {-# INLINABLE vectorContainsBy #-} vectorContainsBy vector pred = do index <- vectorIndexBy vector pred if index >= 0 then do a <- readVector vector index return (Just a) else return Nothing