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