module Data.Disk.Swapper.Cache where
import Control.Concurrent.MVar
import Control.Monad
import Data.IORef
import Data.Typeable
class Cache a v | a -> v where
addValue :: a -> v -> IO (IO ())
addValueRef :: Cache a v => IORef a -> v -> IO (IO ())
addValueRef r x = flip addValue x =<< readIORef r
data SomeCache v = forall c. (Cache c v) => SomeCache !c
instance Cache (SomeCache v) v where
addValue (SomeCache c) = addValue c
data ClockCache a = ClockCache { ccSize :: Int, ccData :: MVar [(IORef a, IORef Bool)] }
deriving (Typeable)
mkClockCache :: Int -> IO (ClockCache a)
mkClockCache size = return . ClockCache size =<< newMVar . cycle =<<
mapM (const $ liftM2 (,) (newIORef undefined) (newIORef False)) [1..size]
instance Cache (ClockCache a) a where
addValue cache x = do
add =<< takeMVar (ccData cache)
where add ((ix, ikeep):rest) = do
keep <- readIORef ikeep
modifyIORef ikeep not
if keep then add rest
else do writeIORef ix x
putMVar (ccData cache) rest
return (writeIORef ikeep True)
add [] = error "ClockCache: we got to the end of infinite list"
data NullCache a = NullCache
nullCache :: SomeCache a
nullCache = SomeCache NullCache
instance Cache (NullCache a) a where
addValue _ _ = return (return ())