module Control.Distributed.Process.Internal.BiMultiMap
( BiMultiMap
, empty
, singleton
, size
, insert
, lookupBy1st
, lookupBy2nd
, delete
, deleteAllBy1st
, deleteAllBy2nd
, partitionWithKeyBy1st
, partitionWithKeyBy2nd
, flip
) where
import Data.List (foldl')
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import qualified Data.Set as Set
import Prelude hiding (flip, lookup)
data BiMultiMap a b v = BiMultiMap !(Map a (Set (b, v))) !(Map b (Set (a, v)))
empty :: BiMultiMap a b v
empty = BiMultiMap Map.empty Map.empty
singleton :: (Ord a, Ord b, Ord v) => a -> b -> v -> BiMultiMap a b v
singleton a b v = insert a b v empty
size :: BiMultiMap a b v -> Int
size (BiMultiMap m _) = foldl' (+) 0 $ map Set.size $ Map.elems m
insert :: (Ord a, Ord b, Ord v)
=> a -> b -> v -> BiMultiMap a b v -> BiMultiMap a b v
insert a b v (BiMultiMap m r) =
BiMultiMap (Map.insertWith (\_new old -> Set.insert (b, v) old)
a
(Set.singleton (b, v))
m)
(Map.insertWith (\_new old -> Set.insert (a, v) old)
b
(Set.singleton (a, v))
r)
lookupBy1st :: Ord a => a -> BiMultiMap a b v -> Set (b, v)
lookupBy1st a (BiMultiMap m _) = maybe Set.empty id $ Map.lookup a m
lookupBy2nd :: Ord b => b -> BiMultiMap a b v -> Set (a, v)
lookupBy2nd b = lookupBy1st b . flip
delete :: (Ord a, Ord b, Ord v)
=> a -> b -> v -> BiMultiMap a b v -> BiMultiMap a b v
delete a b v (BiMultiMap m r) =
let m' = Map.update (nothingWhen Set.null . Set.delete (b, v)) a m
r' = Map.update (nothingWhen Set.null . Set.delete (a, v)) b r
in BiMultiMap m' r'
deleteAllBy1st :: (Ord a, Ord b, Ord v) => a -> BiMultiMap a b v -> BiMultiMap a b v
deleteAllBy1st a (BiMultiMap m r) =
let (mm, m') = Map.updateLookupWithKey (\_ _ -> Nothing) a m
r' = case mm of
Nothing -> r
Just mb -> reverseDelete a (Set.toList mb) r
in BiMultiMap m' r'
deleteAllBy2nd :: (Ord a, Ord b, Ord v)
=> b -> BiMultiMap a b v -> BiMultiMap a b v
deleteAllBy2nd b = flip . deleteAllBy1st b . flip
partitionWithKeyBy1st :: (Ord a, Ord b, Ord v)
=> (a -> Set (b, v) -> Bool) -> BiMultiMap a b v
-> (Map a (Set (b, v)), BiMultiMap a b v)
partitionWithKeyBy1st p (BiMultiMap m r) =
let (m0, m1) = Map.partitionWithKey p m
r1 = foldl' (\rr (a, mb) -> reverseDelete a (Set.toList mb) rr) r $
Map.toList m0
in (m0, BiMultiMap m1 r1)
partitionWithKeyBy2nd :: (Ord a, Ord b, Ord v)
=> (b -> Set (a, v) -> Bool) -> BiMultiMap a b v
-> (Map b (Set (a, v)), BiMultiMap a b v)
partitionWithKeyBy2nd p b = let (m, b') = partitionWithKeyBy1st p $ flip b
in (m, flip b')
flip :: BiMultiMap a b v -> BiMultiMap b a v
flip (BiMultiMap m r) = BiMultiMap r m
reverseDelete :: (Ord a, Ord b, Ord v)
=> a -> [(b, v)] -> Map b (Set (a, v)) -> Map b (Set (a, v))
reverseDelete a bs r = foldl' (\rr (b, v) -> Map.update (rmb v) b rr) r bs
where
rmb v = nothingWhen Set.null . Set.delete (a, v)
nothingWhen :: (a -> Bool) -> a -> Maybe a
nothingWhen p a = if p a then Nothing else Just a