module GLL.Combinators.Memoisation where

import              Data.IORef
import qualified    Data.IntMap     as IM
import System.IO.Unsafe

-- | 
-- A 'MemoTable' maps left-extent /l/ to right-extent /r/ to some results /a/
-- indicating the the substring ranging from /l/ to /r/ is derived with parse result /a/.
type MemoTable a = IM.IntMap (IM.IntMap a)

-- | An impure reference to a 'MemoTable'.
type MemoRef a   = IORef (MemoTable a)

memLookup :: (Int, Int) -> MemoTable a -> Maybe a
memLookup (l,r) = maybe Nothing look' . IM.lookup l
 where  look' = maybe Nothing Just . IM.lookup r

memInsert :: (Int, Int) -> a -> MemoTable a -> MemoTable a
memInsert (l,r) as = IM.alter add' l
 where  add' mm = case mm of
                    Nothing -> Just $ IM.singleton r as
                    Just m  -> Just $ IM.insert r as m

-- |
-- Clears the 'MemoTable' to which the given reference refers.
memClear :: MemoRef a -> IO ()
memClear ref = modifyIORef ref (const IM.empty)

-- | 
-- Create a reference to a fresh 'MemoTable'.
newMemoTable :: MemoRef a
newMemoTable = unsafePerformIO $ newIORef IM.empty