module Network.Wreq.Cache.Store
(
Store
, empty
, insert
, delete
, lookup
, fromList
, toList
) where
import Data.Hashable (Hashable)
import Data.Int (Int64)
import Data.List (foldl')
import Prelude hiding (lookup, map)
import qualified Data.HashPSQ as HashPSQ
type Epoch = Int64
data Store k v = Store {
capacity :: !Int
, size :: !Int
, epoch :: !Epoch
, psq :: !(HashPSQ.HashPSQ k Epoch v)
}
instance (Show k, Show v, Ord k, Hashable k) => Show (Store k v) where
show st = "fromList " ++ show (toList st)
empty :: Ord k => Int -> Store k v
empty cap
| cap <= 0 = error "empty: invalid capacity"
| otherwise = Store cap 0 0 HashPSQ.empty
insert :: (Ord k, Hashable k) => k -> v -> Store k v -> Store k v
insert k v st@Store{..} = case HashPSQ.insertView k epoch v psq of
(Just (_, _), psq0) -> st {epoch = epoch + 1, psq = psq0}
(Nothing, psq0)
| size < capacity -> st {size = size + 1, epoch = epoch + 1, psq = psq0}
| otherwise -> st {epoch = epoch + 1, psq = HashPSQ.deleteMin psq0}
lookup :: (Ord k, Hashable k) => k -> Store k v -> Maybe (v, Store k v)
lookup k st@Store{..} = case HashPSQ.alter tick k psq of
(Nothing, _) -> Nothing
(Just v, psq0) -> Just (v, st { epoch = epoch + 1, psq = psq0 })
where tick Nothing = (Nothing, Nothing)
tick (Just (_, v)) = (Just v, Just (epoch, v))
delete :: (Ord k, Hashable k) => k -> Store k v -> Store k v
delete k st@Store{..} = case HashPSQ.deleteView k psq of
Nothing -> st
Just (_, _, psq0) -> st {size = size 1, psq = psq0}
fromList :: (Ord k, Hashable k) => Int -> [(k, v)] -> Store k v
fromList = foldl' (flip (uncurry insert)) . empty
toList :: (Ord k, Hashable k) => Store k v -> [(k, v)]
toList Store{..} = [(k,v) | (k, _, v) <- HashPSQ.toList psq]