module Data.IterLinkedList.Internal
( LinkedList(..)
, IterLinkedList(..)
, LinkedListContainer(..)
, firstIter
, lastIter
) where
import qualified Data.IntMap.Strict as IM
import qualified Data.Map.Strict as M
data LinkedList iter value = LinkedList
{ newKey :: iter
, firstKey :: iter
, lastKey :: iter
, container :: LinkedListContainer iter value
}
instance Show value => Show (LinkedList Int value) where
show ls = "fromList " ++ show (toList ls)
instance Show value => Show (LinkedList Integer value) where
show ls = "fromList " ++ show (toList ls)
type family LinkedListContainer iter value
type instance LinkedListContainer Int value = IM.IntMap (Int, value, Int)
type instance LinkedListContainer Integer value = M.Map Integer (Integer, value, Integer)
class IterLinkedList iter where
null :: LinkedList iter value -> Bool
get :: iter -> LinkedList iter value -> Maybe value
get' :: iter -> LinkedList iter value -> value
get' iter list = case get iter list of
Just value -> value
Nothing -> undefined
set :: iter -> value -> LinkedList iter value -> LinkedList iter value
set iter value list = modify iter (const value) list
modify :: iter -> (value -> value) -> LinkedList iter value -> LinkedList iter value
modify iter f list = case get iter list of
Just value -> set iter (f value) list
Nothing -> list
next :: LinkedList iter value -> iter -> iter
prev :: LinkedList iter value -> iter -> iter
empty :: LinkedList iter value
singleton :: value -> LinkedList iter value
insertBefore :: iter -> value -> LinkedList iter value -> LinkedList iter value
insertAfter :: iter -> value -> LinkedList iter value -> LinkedList iter value
delete :: iter -> LinkedList iter value -> LinkedList iter value
fromList :: [value] -> LinkedList iter value
fromList [] = empty
fromList (a:as) = go (singleton a) as where
go list (a:as) = go (insertAfter (lastIter list) a list) as
go list _ = list
toList :: LinkedList iter value -> [value]
firstIter :: LinkedList iter value -> iter
firstIter LinkedList{firstKey} = firstKey
lastIter :: LinkedList iter value -> iter
lastIter LinkedList{lastKey} = lastKey
instance IterLinkedList Int where
null (LinkedList {container = cntr}) = IM.null cntr
get iter (LinkedList {..}) =
fmap (\(prev, value, next) -> value) (IM.lookup iter container)
get' iter (LinkedList {..}) = case IM.lookup iter container of
Just (prev, value, next) -> value
_ -> undefined
set iter value list@(LinkedList {..}) = list{container = IM.adjust f iter container}
where
f (prevKey, _, nextKey) = (prevKey, value, nextKey)
modify iter f list@(LinkedList {..}) = list{container = IM.adjust g iter container}
where
g (prevKey, value, nextKey) = (prevKey, f value, nextKey)
next (LinkedList {..}) iter = case IM.lookup iter container of
Just (prev, value, next) -> next
_ -> iter
prev (LinkedList {..}) iter = case IM.lookup iter container of
Just (prev, value, next) -> prev
_ -> iter
empty = LinkedList
{ newKey = minBound
, firstKey = minBound
, lastKey = minBound
, container = IM.empty
}
singleton value = LinkedList
{ newKey = minBound + 1
, firstKey = minBound
, lastKey = minBound
, container = IM.singleton minBound (minBound, value, minBound)
}
insertBefore iter value (LinkedList {..}) = LinkedList
{ newKey = newKey + 1
, firstKey = if isPrepend then newKey else firstKey
, lastKey = lastKey
, container
= IM.insert newKey (prevKey, value, nextKey)
$ IM.adjust
(\(prevPrevKey, prevValue, prevNextKey) -> (prevPrevKey, prevValue, newKey))
prevKey
$ IM.adjust
(\(nextPrevKey, nextValue, nextNextKey) -> (newKey, nextValue, nextNextKey))
nextKey
$ container
}
where
(isPrepend, prevKey, nextKey) = case IM.lookup iter container of
Nothing -> (True, newKey, firstKey)
Just (iterPrevKey, iterValue, iterNextKey)
| iterPrevKey == iter -> (True, newKey, iter)
| otherwise -> (False, iterPrevKey, iter)
insertAfter iter value (LinkedList {..}) = LinkedList
{ newKey = newKey + 1
, firstKey = firstKey
, lastKey = if isAppend then newKey else lastKey
, container
= IM.insert newKey (prevKey, value, nextKey)
$ IM.adjust
(\(prevPrevKey, prevValue, prevNextKey) -> (prevPrevKey, prevValue, newKey))
prevKey
$ IM.adjust
(\(nextPrevKey, nextValue, nextNextKey) -> (newKey, nextValue, nextNextKey))
nextKey
$ container
}
where
(isAppend, prevKey, nextKey) = case IM.lookup iter container of
Nothing -> (True, lastKey, newKey)
Just (iterPrevKey, iterValue, iterNextKey)
| iterNextKey == iter -> (True, iter, newKey)
| otherwise -> (False, iter, iterNextKey)
delete iter list@(LinkedList {..}) = case IM.lookup iter container of
Nothing -> list
Just (iterPrevKey, iterValue, iterNextKey) -> LinkedList
{ newKey = newKey
, firstKey = if firstKey == iter then iterNextKey else firstKey
, lastKey = if lastKey == iter then iterPrevKey else lastKey
, container
= IM.adjust (\(prevPrevKey, prevValue, prevNextKey) ->
(prevPrevKey, prevValue, if iterNextKey == iter then iterPrevKey else iterNextKey)
) iterPrevKey
$ IM.adjust (\(nextPrevKey, nextValue, nextNextKey) ->
(if iterPrevKey == iter then iterNextKey else iterPrevKey, nextValue, nextNextKey)
) iterNextKey
$ IM.delete iter container
}
fromList [] = empty
fromList as = LinkedList
{ newKey = minBound + len
, firstKey = minBound
, lastKey = lastKey
, container = IM.fromList $ zip [minBound..] $ zip3 (minBound : [minBound..]) as ([minBound + 1 .. lastKey] ++ [lastKey])
}
where
lastKey = minBound + len 1
len = length as
toList (LinkedList {..})
| IM.null container = []
| otherwise = go firstKey where
go key = case IM.lookup key container of
Just (_, value, nextKey) ->
value : (if nextKey == key then [] else go nextKey)
_ ->
[]
instance IterLinkedList Integer where
null (LinkedList {container = cntr}) = M.null cntr
get iter (LinkedList {..}) =
fmap (\(prev, value, next) -> value) (M.lookup iter container)
get' iter (LinkedList {..}) = case M.lookup iter container of
Just (prev, value, next) -> value
_ -> undefined
set iter value list@(LinkedList {..}) = list{container = M.adjust f iter container}
where
f (prevKey, _, nextKey) = (prevKey, value, nextKey)
modify iter f list@(LinkedList {..}) = list{container = M.adjust g iter container}
where
g (prevKey, value, nextKey) = (prevKey, f value, nextKey)
next (LinkedList {..}) iter = case M.lookup iter container of
Just (prev, value, next) -> next
_ -> iter
prev (LinkedList {..}) iter = case M.lookup iter container of
Just (prev, value, next) -> prev
_ -> iter
empty = LinkedList
{ newKey = 0
, firstKey = 0
, lastKey = 0
, container = M.empty
}
singleton value = LinkedList
{ newKey = 1
, firstKey = 0
, lastKey = 0
, container = M.singleton 0 (0, value, 0)
}
insertBefore iter value (LinkedList {..}) = LinkedList
{ newKey = newKey + 1
, firstKey = if isPrepend then newKey else firstKey
, lastKey = lastKey
, container
= M.insert newKey (prevKey, value, nextKey)
$ M.adjust
(\(prevPrevKey, prevValue, prevNextKey) -> (prevPrevKey, prevValue, newKey))
prevKey
$ M.adjust
(\(nextPrevKey, nextValue, nextNextKey) -> (newKey, nextValue, nextNextKey))
nextKey
$ container
}
where
(isPrepend, prevKey, nextKey) = case M.lookup iter container of
Nothing -> (True, newKey, firstKey)
Just (iterPrevKey, iterValue, iterNextKey)
| iterPrevKey == iter -> (True, newKey, iter)
| otherwise -> (False, iterPrevKey, iter)
insertAfter iter value (LinkedList {..}) = LinkedList
{ newKey = newKey + 1
, firstKey = firstKey
, lastKey = if isAppend then newKey else lastKey
, container
= M.insert newKey (prevKey, value, nextKey)
$ M.adjust
(\(prevPrevKey, prevValue, prevNextKey) -> (prevPrevKey, prevValue, newKey))
prevKey
$ M.adjust
(\(nextPrevKey, nextValue, nextNextKey) -> (newKey, nextValue, nextNextKey))
nextKey
$ container
}
where
(isAppend, prevKey, nextKey) = case M.lookup iter container of
Nothing -> (True, lastKey, newKey)
Just (iterPrevKey, iterValue, iterNextKey)
| iterNextKey == iter -> (True, iter, newKey)
| otherwise -> (False, iter, iterNextKey)
delete iter list@(LinkedList {..}) = case M.lookup iter container of
Nothing -> list
Just (iterPrevKey, iterValue, iterNextKey) -> LinkedList
{ newKey = newKey
, firstKey = if firstKey == iter then iterNextKey else firstKey
, lastKey = if lastKey == iter then iterPrevKey else lastKey
, container
= M.adjust (\(prevPrevKey, prevValue, prevNextKey) ->
(prevPrevKey, prevValue, if iterNextKey == iter then iterPrevKey else iterNextKey)
) iterPrevKey
$ M.adjust (\(nextPrevKey, nextValue, nextNextKey) ->
(if iterPrevKey == iter then iterNextKey else iterPrevKey, nextValue, nextNextKey)
) iterNextKey
$ M.delete iter container
}
fromList [] = empty
fromList as = LinkedList
{ newKey = len
, firstKey = 0
, lastKey = lastKey
, container = M.fromList $ zip [0..] $ zip3 (0 : [0..]) as ([1 .. lastKey] ++ [lastKey])
}
where
lastKey = len 1
len = fromIntegral $ length as
toList (LinkedList {..})
| M.null container = []
| otherwise = go firstKey where
go key = case M.lookup key container of
Just (_, value, nextKey) ->
value : (if nextKey == key then [] else go nextKey)
_ ->
[]