content: {-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
  -- | Wrapper around Data.Map that guarantees elements are evaluated when
  -- the Map is. containers-0.5 provides this out of the box, but alas ghc 7.4
  -- is built against containers-0.4.
  module IdeSession.Strict.Map (
      toList
    , fromList
    , map
    , mapWithKey
    , mapKeys
    , empty
    , insert
    , union
    , unions
    , filterWithKey
    , lookup
    , findWithDefault
    , keysSet
    , (\\)
    , alter
    , adjust
    , member
    , (!)
    , keys
    , elems
    , delete
    , accessor
    , accessorDefault
    ) where
  
  import Prelude hiding (map, lookup)
  import Data.Set (Set)
  import qualified Data.Map as Map
  import Data.Accessor (Accessor)
  import qualified Data.Accessor as Acc
  import qualified Data.List as List
  
  import IdeSession.Strict.Container
  
  toList :: Strict (Map k) v -> [(k, v)]
  toList = Map.toList . toLazyMap
  
  fromList :: Ord k => [(k, v)] -> Strict (Map k) v
  fromList = force . Map.fromList
  
  map :: (a -> b) -> Strict (Map k) a  -> Strict (Map k) b
  map f = force . Map.map f . toLazyMap
  
  mapWithKey :: (k -> a -> b) -> Strict (Map k) a  -> Strict (Map k) b
  mapWithKey f = force . Map.mapWithKey f . toLazyMap
  
  mapKeys :: Ord k' => (k -> k') -> Strict (Map k) v -> Strict (Map k') v
  -- Maps are already strict in keys
  mapKeys f = StrictMap . Map.mapKeys f . toLazyMap
  
  empty :: Strict (Map k) v
  empty = StrictMap Map.empty
  
  insert :: Ord k => k -> v -> Strict (Map k) v -> Strict (Map k) v
  insert k v = StrictMap . Map.insertWith' const k v . toLazyMap
  
  -- | Left biased union
  union :: Ord k => Strict (Map k) v -> Strict (Map k) v -> Strict (Map k) v
  union a b = StrictMap $ Map.union (toLazyMap a) (toLazyMap b)
  
  unions :: Ord k => [Strict (Map k) v] -> Strict (Map k) v
  unions = StrictMap . Map.unions . List.map toLazyMap
  
  filterWithKey :: Ord k => (k -> v -> Bool) -> Strict (Map k) v -> Strict (Map k) v
  filterWithKey p = StrictMap . Map.filterWithKey p . toLazyMap
  
  keysSet :: Strict (Map k) v -> Set k
  keysSet = Map.keysSet . toLazyMap
  
  lookup :: Ord k => k -> Strict (Map k) v -> Maybe v
  lookup k = Map.lookup k . toLazyMap
  
  findWithDefault :: Ord k => v -> k -> Strict (Map k) v -> v
  findWithDefault d k = Map.findWithDefault d k . toLazyMap
  
  (\\) :: Ord k => Strict (Map k) a -> Strict (Map k) b -> Strict (Map k) a
  (\\) a b = StrictMap $ (Map.\\) (toLazyMap a) (toLazyMap b)
  
  alter :: forall k a. Ord k
        => (Maybe a -> Maybe a) -> k -> Strict (Map k) a -> Strict (Map k) a
  alter f k = StrictMap . Map.alter aux k . toLazyMap
    where
      aux :: Maybe a -> Maybe a
      aux ma = case f ma of
                 Nothing -> Nothing
                 Just a  -> a `seq` Just a
  
  -- We use alter because it gives us something to anchor a seq to
  adjust :: forall k v. Ord k => (v -> v) -> k -> Strict (Map k) v -> Strict (Map k) v
  adjust f i = StrictMap . Map.alter aux i . toLazyMap
    where
      aux :: Maybe v -> Maybe v
      aux Nothing  = Nothing
      aux (Just v) = let v' = f v in v' `seq` Just v'
  
  member :: Ord k => k -> Strict (Map k) v -> Bool
  member k = Map.member k . toLazyMap
  
  (!) :: Ord k => Strict (Map k) v -> k -> v
  (!) = (Map.!) . toLazyMap
  
  keys :: Strict (Map k) a -> [k]
  keys = Map.keys . toLazyMap
  
  elems :: Strict (Map k) a -> [a]
  elems = Map.elems . toLazyMap
  
  delete :: Ord k => k -> Strict (Map k) a -> Strict (Map k) a
  delete k = StrictMap . Map.delete k . toLazyMap
  
  accessor :: Ord k => k -> Accessor (Strict (Map k) a) (Maybe a)
  accessor key = Acc.accessor (lookup key) (\mval mp -> case mval of
                                              Just val -> insert key val mp
                                              Nothing  -> delete key mp)
  
  accessorDefault :: Ord k => v -> k -> Accessor (Strict (Map k) v) v
  accessorDefault d k = Acc.accessor (findWithDefault d k) (insert k)
  