module Data.Cache (
Cache,
newCache,
EvictionStrategy(..),
SeqLRU,
newSeqLRU,
LRU,
newLRU,
MRU,
newMRU,
RR,
newRR,
LFU,
newLFU
) where
import Data.Cache.Eviction (EvictionStrategy(..))
import Data.Cache.Eviction.LRU
import Data.Cache.Eviction.MRU
import Data.Cache.Eviction.RR
import Data.Cache.Eviction.LFU
import qualified Data.HashMap.Strict as HM
import Control.DeepSeq (NFData)
import Data.Hashable (Hashable)
data Cache k v s =
Cache {
cacheData :: HM.HashMap k v,
evictionStrategy :: s,
maxSize :: Int,
currentSize :: Int
}
newCache :: (Hashable k, NFData v, EvictionStrategy s, Eq k, Ord k) =>
Int
-> s k
-> Cache k v (s k)
newCache maxSize evictionStrategy =
Cache {
cacheData = HM.empty,
evictionStrategy,
maxSize,
currentSize = 0
}
readThrough :: (Hashable k, NFData v, EvictionStrategy s, Eq k, Ord k, Monad m) =>
Cache k v (s k)
-> k
-> (k -> m v)
-> m (v , Cache k v (s k))
readThrough cache@(Cache {maxSize, evictionStrategy, cacheData, currentSize}) key onMiss =
case HM.lookup key cacheData of
Just v -> do
let strat' = recordLookup key evictionStrategy
pure (v, cache {evictionStrategy = strat'} )
Nothing | maxSize == currentSize -> do
v <- onMiss key
let (strat', evicted) = evict evictionStrategy
strat'' = recordLookup key strat'
cacheData' = HM.insert key v $ maybe cacheData (`HM.delete` cacheData) evicted
pure (v, cache {cacheData = cacheData', evictionStrategy = strat''})
Nothing -> do
v <- onMiss key
let strat' = recordLookup key evictionStrategy
cacheData' = HM.insert key v cacheData
pure (v, cache {cacheData = cacheData', evictionStrategy = strat'})