Fungi-1.0.6: src/Data/History.hs
module Data.History (
History (getSize)
, empty
, fromHistory
, fromList
, toList
, push
, pop
, popN
, lookup
) where
import Prelude hiding (lookup)
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Maybe (fromMaybe, mapMaybe)
import Text.PrettyShow
-----------------------------------------------------------
data History a = History {
getSize :: Int
, getReplacePos :: Int
, getMap :: IntMap a
}
deriving
(Show)
instance (PrettyShow a) => PrettyShow (History a) where
pshow = ("History " ++) . pshow . toList
empty :: Int -> History a
empty n = fromList (Just n) []
fromHistory :: Maybe Int -> History a -> History a
fromHistory Nothing h = h
fromHistory (Just newSize) h
| newSize >= getSize h = h { getSize = newSize }
| otherwise = fromList (Just newSize) $ take newSize $ toList h -- TODO : Make this more efficient if needed
fromList :: Maybe Int -> [a] -> History a
fromList mSize xs = foldr push History {
getSize = size
, getReplacePos = 0
, getMap = IntMap.empty
} xs
where
size = fromMaybe (length xs) mSize
getHeadPos :: History a -> Int
getHeadPos h = if rpos - 1 < 0
then getSize h - 1
else rpos - 1
where
rpos = getReplacePos h
fromLogicalPos :: History a -> Int -> Int
fromLogicalPos h pos = if pos <= hpos
then hpos - pos
else size + hpos - pos
where
size = getSize h
hpos = getHeadPos h
push :: a -> History a -> History a
push x h = h {
getMap = IntMap.insert rpos x $ getMap h
, getReplacePos = if rpos + 1 < getSize h
then rpos + 1
else 0
}
where
rpos = getReplacePos h
pop :: History a -> History a
pop h = h {
getMap = IntMap.delete (getHeadPos h) $ getMap h
, getReplacePos = if rpos - 1 < 0
then getSize h - 1
else rpos - 1
}
where
rpos = getReplacePos h
popN :: Int -> History a -> History a
popN n = head . drop n . iterate pop
lookup :: Int -> History a -> Maybe a
lookup pos h
| 0 <= pos && pos < size = IntMap.lookup (fromLogicalPos h pos) $ getMap h
| otherwise = Nothing
where
size = getSize h
toList :: History a -> [a]
toList h = mapMaybe (`lookup` h) [0 .. getSize h - 1]