module StmContainers.Multimap
(
Multimap,
new,
newIO,
null,
focus,
lookup,
lookupByKey,
insert,
delete,
deleteByKey,
reset,
unfoldlM,
unfoldlMKeys,
unfoldlMByKey,
listT,
listTKeys,
listTByKey,
)
where
import StmContainers.Prelude hiding (insert, delete, lookup, alter, foldM, toList, empty, null)
import qualified StmContainers.Map as A
import qualified StmContainers.Set as B
import qualified Focus as C
newtype Multimap key value =
Multimap (A.Map key (B.Set value))
deriving (Typeable)
{-# INLINE new #-}
new :: STM (Multimap key value)
new =
Multimap <$> A.new
{-# INLINE newIO #-}
newIO :: IO (Multimap key value)
newIO =
Multimap <$> A.newIO
{-# INLINE null #-}
null :: Multimap key value -> STM Bool
null (Multimap map) =
A.null map
{-# INLINE focus #-}
focus :: (Eq key, Hashable key, Eq value, Hashable value) => C.Focus () STM result -> value -> key -> Multimap key value -> STM result
focus unitFocus@(Focus concealUnit revealUnit) value key (Multimap map) = A.focus setFocus key map where
setFocus = C.Focus conceal reveal where
conceal = do
(output, change) <- concealUnit
case change of
C.Set () ->
do
set <- B.new
B.insert value set
return (output, C.Set set)
_ ->
return (output, C.Leave)
reveal set = do
output <- B.focus unitFocus value set
change <- bool C.Leave C.Remove <$> B.null set
return (output, change)
{-# INLINE lookup #-}
lookup :: (Eq key, Hashable key, Eq value, Hashable value) => value -> key -> Multimap key value -> STM Bool
lookup value key (Multimap m) =
maybe (return False) (B.lookup value) =<< A.lookup key m
{-# INLINE lookupByKey #-}
lookupByKey :: (Eq key, Hashable key) => key -> Multimap key value -> STM (Maybe (B.Set value))
lookupByKey key (Multimap m) =
A.lookup key m
{-# INLINABLE insert #-}
insert :: (Eq key, Hashable key, Eq value, Hashable value) => value -> key -> Multimap key value -> STM ()
insert value key (Multimap map) = A.focus setFocus key map where
setFocus = Focus conceal reveal where
conceal = do
set <- B.new
B.insert value set
return ((), C.Set set)
reveal set = do
B.insert value set
return ((), C.Leave)
{-# INLINABLE delete #-}
delete :: (Eq key, Hashable key, Eq value, Hashable value) => value -> key -> Multimap key value -> STM ()
delete value key (Multimap map) = A.focus setFocus key map where
setFocus = Focus conceal reveal where
conceal = returnChange C.Leave
reveal set = do
B.delete value set
B.null set >>= returnChange . bool C.Leave C.Remove
returnChange c = return ((), c)
{-# INLINEABLE deleteByKey #-}
deleteByKey :: (Eq key, Hashable key) => key -> Multimap key value -> STM ()
deleteByKey key (Multimap map) =
A.delete key map
{-# INLINE reset #-}
reset :: Multimap key value -> STM ()
reset (Multimap map) =
A.reset map
unfoldlM :: Multimap key value -> UnfoldlM STM (key, value)
unfoldlM (Multimap m) =
A.unfoldlM m >>= \(key, s) -> (key,) <$> B.unfoldlM s
unfoldlMKeys :: Multimap key value -> UnfoldlM STM key
unfoldlMKeys (Multimap m) =
fmap fst (A.unfoldlM m)
unfoldlMByKey :: (Eq key, Hashable key) => key -> Multimap key value -> UnfoldlM STM value
unfoldlMByKey key (Multimap m) =
lift (A.lookup key m) >>= maybe mempty B.unfoldlM
listT :: Multimap key value -> ListT STM (key, value)
listT (Multimap m) =
A.listT m >>= \(key, s) -> (key,) <$> B.listT s
listTKeys :: Multimap key value -> ListT STM key
listTKeys (Multimap m) =
fmap fst (A.listT m)
listTByKey :: (Eq key, Hashable key) => key -> Multimap key value -> ListT STM value
listTByKey key (Multimap m) =
lift (A.lookup key m) >>= maybe mempty B.listT