module Control.Distributed.Process.Extras.Internal.Containers.MultiMap
( MultiMap
, Insertable
, empty
, insert
, member
, lookup
, filter
, filterWithKey
, toList
) where
import qualified Data.Foldable as Foldable
import Data.Foldable (Foldable)
import Data.Hashable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as Map
import Data.HashSet (HashSet)
import qualified Data.HashSet as Set
import Data.Foldable (Foldable(foldr))
import Prelude hiding (lookup, filter, pred)
class (Eq a, Hashable a) => Insertable a
instance (Eq a, Hashable a) => Insertable a
data MultiMap k v = M { hmap :: !(HashMap k (HashSet v)) }
instance Foldable (MultiMap k) where
foldr f = foldrWithKey (const f)
empty :: MultiMap k v
empty = M $ Map.empty
insert :: forall k v. (Insertable k, Insertable v)
=> k -> v -> MultiMap k v -> MultiMap k v
insert k' v' M{..} =
case Map.lookup k' hmap of
Nothing -> M $ Map.insert k' (Set.singleton v') hmap
Just s -> M $ Map.insert k' (Set.insert v' s) hmap
member :: (Insertable k) => k -> MultiMap k a -> Bool
member k = Map.member k . hmap
lookup :: (Insertable k) => k -> MultiMap k v -> Maybe [v]
lookup k M{..} = maybe Nothing (Just . Foldable.toList) $ Map.lookup k hmap
filter :: forall k v. (Insertable k)
=> (v -> Bool)
-> MultiMap k v
-> MultiMap k v
filter p M{..} = M $ Map.foldlWithKey' (matchOn p) hmap hmap
where
matchOn pred acc key valueSet =
Map.insert key (Set.filter pred valueSet) acc
filterWithKey :: forall k v. (Insertable k)
=> (k -> v -> Bool)
-> MultiMap k v
-> MultiMap k v
filterWithKey p M{..} = M $ Map.foldlWithKey' (matchOn p) hmap hmap
where
matchOn pred acc key valueSet =
Map.insert key (Set.filter (pred key) valueSet) acc
foldrWithKey :: (k -> v -> a -> a) -> a -> MultiMap k v -> a
foldrWithKey f a M{..} =
let wrap = \k' v' acc' -> f k' v' acc'
in Map.foldrWithKey (\k v acc -> Set.foldr (wrap k) acc v) a hmap
toList :: MultiMap k v -> [(k, v)]
toList M{..} = Map.foldlWithKey' explode [] hmap
where
explode xs k vs = Set.foldl' (\ys v -> ((k, v):ys)) xs vs