module Simulation.Aivika.Trans.DoubleLinkedList
(DoubleLinkedList,
listNull,
listCount,
newList,
listInsertFirst,
listAddLast,
listRemoveFirst,
listRemoveLast,
listRemove,
listRemoveBy,
listContains,
listContainsBy,
listFirst,
listLast,
clearList,
freezeList) where
import Data.Maybe
import Data.Functor
import Control.Monad
import Simulation.Aivika.Trans.Ref.Base
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Event
data DoubleLinkedItem m a =
DoubleLinkedItem { itemVal :: a,
itemPrev :: Ref m (Maybe (DoubleLinkedItem m a)),
itemNext :: Ref m (Maybe (DoubleLinkedItem m a)) }
data DoubleLinkedList m a =
DoubleLinkedList { listHead :: Ref m (Maybe (DoubleLinkedItem m a)),
listTail :: Ref m (Maybe (DoubleLinkedItem m a)),
listSize :: Ref m Int }
listNull :: MonadRef m => DoubleLinkedList m a -> Event m Bool
{-# INLINABLE listNull #-}
listNull x =
do head <- readRef (listHead x)
case head of
Nothing -> return True
Just _ -> return False
listCount :: MonadRef m => DoubleLinkedList m a -> Event m Int
{-# INLINABLE listCount #-}
listCount x = readRef (listSize x)
newList :: MonadRef m => Simulation m (DoubleLinkedList m a)
{-# INLINABLE newList #-}
newList =
do head <- newRef Nothing
tail <- newRef Nothing
size <- newRef 0
return DoubleLinkedList { listHead = head,
listTail = tail,
listSize = size }
listInsertFirst :: MonadRef m => DoubleLinkedList m a -> a -> Event m ()
{-# INLINABLE listInsertFirst #-}
listInsertFirst x v =
do size <- readRef (listSize x)
writeRef (listSize x) (size + 1)
head <- readRef (listHead x)
case head of
Nothing ->
do prev <- liftSimulation $ newRef Nothing
next <- liftSimulation $ newRef Nothing
let item = Just DoubleLinkedItem { itemVal = v,
itemPrev = prev,
itemNext = next }
writeRef (listHead x) item
writeRef (listTail x) item
Just h ->
do prev <- liftSimulation $ newRef Nothing
next <- liftSimulation $ newRef head
let item = Just DoubleLinkedItem { itemVal = v,
itemPrev = prev,
itemNext = next }
writeRef (itemPrev h) item
writeRef (listHead x) item
listAddLast :: MonadRef m => DoubleLinkedList m a -> a -> Event m ()
{-# INLINABLE listAddLast #-}
listAddLast x v =
do size <- readRef (listSize x)
writeRef (listSize x) (size + 1)
tail <- readRef (listTail x)
case tail of
Nothing ->
do prev <- liftSimulation $ newRef Nothing
next <- liftSimulation $ newRef Nothing
let item = Just DoubleLinkedItem { itemVal = v,
itemPrev = prev,
itemNext = next }
writeRef (listHead x) item
writeRef (listTail x) item
Just t ->
do prev <- liftSimulation $ newRef tail
next <- liftSimulation $ newRef Nothing
let item = Just DoubleLinkedItem { itemVal = v,
itemPrev = prev,
itemNext = next }
writeRef (itemNext t) item
writeRef (listTail x) item
listRemoveFirst :: MonadRef m => DoubleLinkedList m a -> Event m ()
{-# INLINABLE listRemoveFirst #-}
listRemoveFirst x =
do head <- readRef (listHead x)
case head of
Nothing ->
error "Empty list: listRemoveFirst"
Just h ->
do size <- readRef (listSize x)
writeRef (listSize x) (size - 1)
head' <- readRef (itemNext h)
case head' of
Nothing ->
do writeRef (listHead x) Nothing
writeRef (listTail x) Nothing
Just h' ->
do writeRef (itemPrev h') Nothing
writeRef (listHead x) head'
listRemoveLast :: MonadRef m => DoubleLinkedList m a -> Event m ()
{-# INLINABLE listRemoveLast #-}
listRemoveLast x =
do tail <- readRef (listTail x)
case tail of
Nothing ->
error "Empty list: listRemoveLast"
Just t ->
do size <- readRef (listSize x)
writeRef (listSize x) (size - 1)
tail' <- readRef (itemPrev t)
case tail' of
Nothing ->
do writeRef (listHead x) Nothing
writeRef (listTail x) Nothing
Just t' ->
do writeRef (itemNext t') Nothing
writeRef (listTail x) tail'
listFirst :: MonadRef m => DoubleLinkedList m a -> Event m a
{-# INLINABLE listFirst #-}
listFirst x =
do head <- readRef (listHead x)
case head of
Nothing ->
error "Empty list: listFirst"
Just h ->
return $ itemVal h
listLast :: MonadRef m => DoubleLinkedList m a -> Event m a
{-# INLINABLE listLast #-}
listLast x =
do tail <- readRef (listTail x)
case tail of
Nothing ->
error "Empty list: listLast"
Just t ->
return $ itemVal t
listRemove :: (Eq a, Functor m, MonadRef m) => DoubleLinkedList m a -> a -> Event m Bool
{-# INLINABLE listRemove #-}
listRemove x v = fmap isJust $ listRemoveBy x (== v)
listRemoveBy :: MonadRef m => DoubleLinkedList m a -> (a -> Bool) -> Event m (Maybe a)
{-# INLINABLE listRemoveBy #-}
listRemoveBy x p = readRef (listHead x) >>= loop
where loop item =
case item of
Nothing -> return Nothing
Just item ->
do let f = p (itemVal item)
if not f
then readRef (itemNext item) >>= loop
else do size <- readRef (listSize x)
prev <- readRef (itemPrev item)
next <- readRef (itemNext item)
writeRef (listSize x) (size - 1)
case (prev, next) of
(Nothing, Nothing) ->
do writeRef (listHead x) Nothing
writeRef (listTail x) Nothing
(Nothing, head' @ (Just item')) ->
do writeRef (itemPrev item') Nothing
writeRef (listHead x) head'
(tail' @ (Just item'), Nothing) ->
do writeRef (itemNext item') Nothing
writeRef (listTail x) tail'
(Just prev', Just next') ->
do writeRef (itemNext prev') (Just next')
writeRef (itemPrev next') (Just prev')
return (Just $ itemVal item)
listContains :: (Eq a, Functor m, MonadRef m) => DoubleLinkedList m a -> a -> Event m Bool
{-# INLINABLE listContains #-}
listContains x v = fmap isJust $ listContainsBy x (== v)
listContainsBy :: MonadRef m => DoubleLinkedList m a -> (a -> Bool) -> Event m (Maybe a)
{-# INLINABLE listContainsBy #-}
listContainsBy x p = readRef (listHead x) >>= loop
where loop item =
case item of
Nothing -> return Nothing
Just item ->
do let f = p (itemVal item)
if not f
then readRef (itemNext item) >>= loop
else return $ Just (itemVal item)
clearList :: MonadRef m => DoubleLinkedList m a -> Event m ()
{-# INLINABLE clearList #-}
clearList q =
do writeRef (listHead q) Nothing
writeRef (listTail q) Nothing
writeRef (listSize q) 0
freezeList :: MonadRef m => DoubleLinkedList m a -> Event m [a]
{-# INLINABLE freezeList #-}
freezeList x = readRef (listTail x) >>= loop []
where loop acc Nothing = return acc
loop acc (Just item) = readRef (itemPrev item) >>= loop (itemVal item : acc)