bff-0.1: Data/IntMapEq.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.IntMapEq
--
-- Maintainer : Janis Voigtlaender
-- Stability : experimental
--
-- A variant of the regular 'Data.IntMap', enforcing injectivity (up to '==').
--
-- As with 'Data.IntMap', many operations have a worst-case complexity of /O(min(n,W))/.
-- This means that the operation can become linear in the number of elements with a
-- maximum of W -- the number of bits in an Int (32 or 64).
-----------------------------------------------------------------------------
module Data.IntMapEq
( IntMapEq,
empty,
insert,
checkInsert,
lookup,
lookupR,
member,
memberR,
union,
toList ) where
import qualified Data.IntMap as IntMap
import Prelude hiding (lookup)
import qualified Prelude
newtype IntMapEq a = IntMapEq (IntMap.IntMap a)
instance Show a => Show (IntMapEq a) where
show (IntMapEq m) = show m
-- | /O(1)/. The empty map.
empty :: IntMapEq a
empty = IntMapEq IntMap.empty
-- | /O(min(n,W))/. Insert a new key\/value pair in the map.
-- If the key is already present in the map, the associated value is
-- replaced with the supplied value. The injectivity invarant is /not/ enforced.
insert :: Int -> a -> IntMapEq a -> IntMapEq a
insert k a (IntMapEq m) = IntMapEq (IntMap.insert k a m)
-- | /O(n * min(n,W))/. Insert a new key\/value pair in the map, if it is either
-- a new key, or agrees with the present value. If not, an error is signalled using
-- a 'Left' return value.
checkInsert :: Eq a => Int -> a -> IntMapEq a -> Either String (IntMapEq a)
checkInsert i b m = case lookup i m of
Nothing -> if memberR b m
then Left "Update violates differentness."
else Right (insert i b m)
Just c -> if b==c
then Right m
else Left "Update violates equality."
-- | /O(min(n,W))/. Is the key a member of the map?
member :: Int -> IntMapEq a -> Bool
member k (IntMapEq m) = IntMap.member k m
-- | /O(n * min(n,W))/. Is the value a member of the map?
memberR :: Eq a => a -> IntMapEq a -> Bool
memberR a (IntMapEq m) = elem a (IntMap.elems m)
-- | /O(min(n,W))/. Lookup the value at a key in the map.
lookup :: Int -> IntMapEq a -> Maybe a
lookup k (IntMapEq m) = IntMap.lookup k m
-- | /O(n * min(n,W))/. Lookup the key at a value in the map.
lookupR :: Eq a => a -> IntMapEq a -> Maybe Int
lookupR a (IntMapEq m) = Prelude.lookup a (map (\(k,a) -> (a,k)) (IntMap.toList m))
-- | /O(m * n * min(n,W))/. The union of two maps. It prefers the first map
-- when duplicate keys are encountered. If the injectivity invarant is violated,
-- an error is signaled with a 'Left' return value.
union :: Eq a => IntMapEq a -> IntMapEq a -> Either String (IntMapEq a)
union h (IntMapEq m) = IntMap.foldWithKey f (Right h) m
where f j a (Right h) = if member j h
then Right h
else if memberR a h
then Left "Update violates differentness."
else Right (insert j a h)
f j a l = l
-- | /O(n)/. Convert the map to a list of key\/value pairs.
toList :: IntMapEq a -> [(Int,a)]
toList (IntMapEq m) = IntMap.toList m