module Network.HPACK.Context.ReferenceSet (
ReferenceSet
, emptyReferenceSet
, isMember
, addIndex
, removeIndex
, removeIndices
, getNotEmittedIndices
, adjustReferenceSet
, renewForEncoding
, renewForDecoding
, Sequence(..)
, lookupAndUpdate
, getCommon
) where
import Data.List (foldl')
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Network.HPACK.Table
data Status = Old
| NotEmitted
| Emitted
deriving (Eq,Show)
newtype ReferenceSet = ReferenceSet (Map Index Status) deriving Show
emptyReferenceSet :: ReferenceSet
emptyReferenceSet = ReferenceSet M.empty
isMember :: Index -> ReferenceSet -> Bool
isMember idx (ReferenceSet m) = idx `M.member` m
addIndex :: Index -> ReferenceSet -> ReferenceSet
addIndex idx (ReferenceSet m) = ReferenceSet $ M.insert idx Emitted m
removeIndex :: Index -> ReferenceSet -> ReferenceSet
removeIndex idx (ReferenceSet m) = ReferenceSet $ M.delete idx m
removeIndices :: [Index] -> ReferenceSet -> ReferenceSet
removeIndices idcs (ReferenceSet m) = ReferenceSet $ foldl' (flip M.delete) m idcs
getNotEmittedIndices :: ReferenceSet -> [Index]
getNotEmittedIndices (ReferenceSet m) = M.keys $ M.filter (== NotEmitted) m
renewForEncoding :: ReferenceSet -> ([Index],ReferenceSet)
renewForEncoding (ReferenceSet m) = (removedIndces, ReferenceSet m')
where
(oldm,newm) = M.partition (== Old) m
removedIndces = M.keys oldm
m' = M.map (const Old) newm
renewForDecoding :: ReferenceSet -> ReferenceSet
renewForDecoding (ReferenceSet m) = ReferenceSet m'
where
m' = M.map (const NotEmitted) m
adjustReferenceSet :: ReferenceSet -> ReferenceSet
adjustReferenceSet (ReferenceSet m) = ReferenceSet $ M.mapKeysMonotonic (+1) m
data Sequence = Z | E0 | E2 | E4
lookupAndUpdate :: Index -> ReferenceSet -> (Sequence,ReferenceSet)
lookupAndUpdate idx rs@(ReferenceSet m) = case M.lookup idx m of
Nothing -> (Z, rs)
Just Old -> (E0, ReferenceSet $ M.adjust (const NotEmitted) idx m)
Just NotEmitted -> (E4, ReferenceSet $ M.adjust (const Emitted) idx m)
Just Emitted -> (E2, rs)
getCommon :: [Index] -> ReferenceSet -> [Index]
getCommon is (ReferenceSet m) = go is []
where
go [] ret = ret
go (n:ns) ret = case M.lookup n m of
Just NotEmitted -> go ns (n:ret)
_ -> go ns ret