packages feed

gloss-relative-0.1.1.0: src/Graphics/Gloss/Relative/Internal/Cache.hs

module Graphics.Gloss.Relative.Internal.Cache where

import Graphics.Gloss.Relative.Internal.Window
import Graphics.Gloss.Relative.Internal.Dimension
import Graphics.Gloss.Relative.Internal.Data
import Data.Map.Strict (Map(..))
import qualified Data.Map.Strict as Map
import Data.IORef
import System.Mem.StableName
import Control.Monad.Trans

type CacheKey = (ScreenSize,String,Int)
type CacheVal = (WindowOutput,Int)
type CacheTable = IORef (Map CacheKey CacheVal)

newCacheTable :: IO CacheTable
newCacheTable = newIORef Map.empty

insertCacheTable :: Int -> CacheTable -> CacheKey -> WindowOutput -> IO ()
insertCacheTable i cache key val = do
    atomicModifyIORef' cache $ \m -> (Map.insert key (val,i) m, ())
    
lookupCacheTable :: Int -> CacheTable -> CacheKey -> IO (Maybe WindowOutput)
lookupCacheTable i cache key = do
    table <- readIORef cache
    case Map.lookup key table of
        Nothing -> return Nothing
        Just (v,_) -> do
            writeIORef cache $! Map.insert key (v,i) table
            return $ Just v

cachedRenderFrame :: Int -> CacheTable -> (String -> Frame -> Window IO ()) -> String -> Frame -> Window IO ()
cachedRenderFrame i cache render label f = do
    dim <- askDimension
    let screen = dimensionToScreenSize dim
    sn  <- liftIO $ makeStableName f
    let key = (screen,label,hashStableName sn)
    mb <- liftIO $ lookupCacheTable i cache key
    case mb of
      Just wo -> tellWindowOutput wo
      Nothing  -> do
          wo <- lift $ execWindow dim (render label f)
          liftIO $ insertCacheTable i cache key wo
          tellWindowOutput wo

evictOldCacheTable :: Int -> Int -> CacheTable -> IO ()
evictOldCacheTable frame maxAge cache = atomicModifyIORef' cache $ \m -> (Map.filter (\ce -> frame - snd ce <= maxAge) m,())