aivika-transformers-5.1: Simulation/Aivika/Trans/Vector.hs
{-# LANGUAGE FlexibleContexts #-}
-- |
-- Module : Simulation.Aivika.Trans.Vector
-- Copyright : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- 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