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
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
listCount x = readRef (listSize x)
newList :: MonadRef m => Simulation m (DoubleLinkedList m a)
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 ()
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 ()
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 ()
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 ()
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
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
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
listRemove x v = fmap isJust $ listRemoveBy x (== v)
listRemoveBy :: MonadRef m => DoubleLinkedList m a -> (a -> Bool) -> Event m (Maybe a)
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
listContains x v = fmap isJust $ listContainsBy x (== v)
listContainsBy :: MonadRef m => DoubleLinkedList m a -> (a -> Bool) -> Event m (Maybe a)
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 ()
clearList q =
do writeRef (listHead q) Nothing
writeRef (listTail q) Nothing
writeRef (listSize q) 0
freezeList :: MonadRef m => DoubleLinkedList m a -> Event m [a]
freezeList x = readRef (listTail x) >>= loop []
where loop acc Nothing = return acc
loop acc (Just item) = readRef (itemPrev item) >>= loop (itemVal item : acc)