multimap-1.2.1: src/Data/SetMap.hs
{-# LANGUAGE Haskell2010
, DeriveDataTypeable
#-}
{-# OPTIONS
-Wall
-fno-warn-name-shadowing
#-}
-- Module : Data.SetMap
-- Copyright : (c) Julian Fleischer 2013
-- License : MIT (See LICENSE file in cabal package)
--
-- Maintainer : julian.fleischer@fu-berlin.de
-- Portability : non-portable (DeriveDataTypeable)
--
-- A SetMap allows the association of multiple values with a single key,
-- but there are no duplicates per key.
module Data.SetMap (
-- * SetMap type
SetMap,
-- * Query
null,
size,
numKeys,
numValues,
member,
notMember,
lookup,
-- * Operators
(!),
-- * Construction
empty,
-- ** Insertion
insert,
-- ** Deletion
delete,
-- * Traversal
map,
-- * Conversion
elems,
keys,
toMap,
) where
import Prelude hiding (lookup, map, null, foldr, foldl)
import qualified Prelude as P
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.Map as Map
import Data.Map (Map)
import Data.Word
import Data.Data
-- | A SetMap with keys @k@ and values @v@.
newtype SetMap k v = SetMap (Word32, Word32, Map k (Set v))
deriving (Data, Typeable)
null :: SetMap k a -> Bool
-- ^ /O(1)./ Check whether the multimap is empty or not.
null (SetMap (_, _, m)) = Map.null m
size :: SetMap k a -> Int
-- ^ /O(1)./ The number of elements in the multimap.
size (SetMap (_, size, _)) = fromIntegral size
numKeys :: SetMap k a -> Word32
-- ^ /O(1)./ The number of keys in the multimap.
--
-- As this is a multimap, the number of keys is not
-- necessarily equal to the number of values.
numKeys (SetMap (nk, _, _)) = nk
numValues :: SetMap k a -> Word32
-- ^ /O(1)./ The number of values in the multimap.
--
-- As this is a multimap, the number of keys is not
-- necessarily equal to the number of values.
numValues (SetMap (_, nv, _)) = nv
notMember, member :: Ord k => SetMap k a -> k -> Bool
-- | /O(log n)./ Is the key a member of the multimap?
member (SetMap (_, _, map)) key = Map.member key map
-- | /O(log n)./ Is the key not a member of the multimap?
notMember key = not . member key
(!) :: Ord k => SetMap k a -> k -> Set a
-- ^ As @flip lookup@
(!) = flip lookup
lookup :: Ord k => k -> SetMap k a -> Set a
-- ^ /O(log n)./ Lookup the value at a key in the map.
--
-- The function will return the corrsponding values as a List, or the
-- empty list if no values are associated witht the given key.
lookup key (SetMap (_, _, map)) = maybe Set.empty id (Map.lookup key map)
empty :: SetMap k a
-- ^ /O(1)./ The empty multimap.
empty = SetMap (0, 0, Map.empty)
insert :: (Ord k, Ord a) => k -> a -> SetMap k a -> SetMap k a
-- ^ Insert a new key and value in the map.
insert k v (SetMap (nk, nv, map))
| Map.member k map =
let oldSet = map Map.! k
(nv', newSet) = if v `Set.member` oldSet
then (nv, oldSet) else (succ nv, v `Set.insert` oldSet)
in SetMap (nk, nv', Map.insert k newSet map)
| otherwise = SetMap (succ nk, succ nv, Map.insert k (Set.singleton v) map)
delete :: Ord k => k -> SetMap k a -> SetMap k a
-- ^ Delete a key and all its values from the map.
delete k m@(SetMap (nk, nv, map)) = case Map.lookup k map of
Just v -> SetMap (pred nk, nv - fromIntegral (Set.size v), Map.delete k map)
_ -> m
map :: (Ord a, Ord b) => (a -> b) -> SetMap k a -> SetMap k b
-- ^ Map a function over all values in the map.
map f (SetMap (nk, nv, map)) = SetMap (nk, nv, Map.map (Set.map f) map)
elems :: SetMap k a -> [[a]]
-- ^ Return all elements of the multimap in the
-- ascending order of their keys.
--
-- A list of lists is returned since a key can have
-- multiple values. Use 'concat' to flatten.
elems (SetMap (_, _, map)) = P.map (Set.elems) $ Map.elems map
keys :: SetMap k a -> [k]
-- ^ /O(n)./ Return all keys of the multimap in ascending order.
keys (SetMap (_, _, map)) = Map.keys map
toMap :: SetMap k a -> Map k (Set a)
-- ^ /O(1)./ Return the map of sets.
toMap (SetMap (_, _, theUnderlyingMap)) = theUnderlyingMap