{-# LANGUAGE BangPatterns #-}

module Network.Wai.Handler.Warp.HashMap where

import Data.Hashable (hash)
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as I
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Prelude hiding (lookup)

----------------------------------------------------------------

-- | 'HashMap' is used for cache of file information.
--   Hash values of file pathes are used as outer keys.
--   Because negative entries are also contained,
--   a bad guy can intentionally cause the hash collison.
--   So, 'Map' is used internally to prevent
--   the hash collision attack.
newtype HashMap v = HashMap (IntMap (Map FilePath v))

----------------------------------------------------------------

empty :: HashMap v
empty = HashMap I.empty

isEmpty :: HashMap v -> Bool
isEmpty (HashMap hm) = I.null hm

----------------------------------------------------------------

insert :: FilePath -> v -> HashMap v -> HashMap v
insert path v (HashMap hm) = HashMap $ I.insertWith f h m hm
  where
    !h = hash path
    !m = M.singleton path v
    f = M.union -- fimxe

lookup :: FilePath -> HashMap v -> Maybe v
lookup path (HashMap hm) = I.lookup h hm >>= M.lookup path
  where
    !h = hash path