bff-0.1: Data/IntMapOrd.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.IntMapOrd
--
-- Maintainer : Janis Voigtlaender
-- Stability : experimental
--
-- A variant of the regular 'Data.IntMap', enforcing that the map is monotonous
-- with regard to 'Ord'.
--
-----------------------------------------------------------------------------
module Data.IntMapOrd
( IntMapOrd,
empty,
checkInsert,
lookup,
lookupR,
member,
memberR,
union,
fromAscPairList,
toList ) where
import qualified Data.Map as Map
import qualified Data.Bimap as Bimap
import Prelude hiding (lookup)
newtype IntMapOrd a = IntMapOrd (Bimap.Bimap Int a)
instance Show a => Show (IntMapOrd a) where
show (IntMapOrd m) = show m
-- | /O(log n)/. Lookup the key for a value in the map.
lookupR :: Ord a => a -> IntMapOrd a -> Maybe Int
lookupR a (IntMapOrd m) = Bimap.lookupR a m
-- | /O(log n)/. Is the key a member of the map?
member :: Ord a => Int -> IntMapOrd a -> Bool
member k (IntMapOrd m) = Bimap.member k m
-- | /O(log n)/. Is the value a member of the map?
memberR :: Ord a => a -> IntMapOrd a -> Bool
memberR a (IntMapOrd m) = Bimap.memberR a m
-- | /O(n)/. Build a map from a list of pairs, where
-- both the fst and snd parts of the list are in strictly ascending order.
--
-- This precondition is not checked; an invalid list will produce a malformed map.
fromAscPairList :: Ord a => [(Int,a)] -> IntMapOrd a
fromAscPairList l = IntMapOrd (Bimap.fromAscPairListUnchecked l)
-- | /O(1)/. The empty map.
empty :: IntMapOrd a
empty = IntMapOrd Bimap.empty
-- | /O(log n)/. Lookup the value at a key in the map.
lookup :: Ord a => Int -> IntMapOrd a -> Maybe a
lookup k (IntMapOrd m) = Bimap.lookup k m
insert :: Ord a => Int -> a -> IntMapOrd a -> Either String (IntMapOrd a)
insert k a (IntMapOrd m) = let (m1,m2) = Map.split k (Bimap.toMap m)
in if (Map.null m1 || snd (Map.findMax m1) < a)
&& (Map.null m2 || snd (Map.findMin m2) > a)
then Right (IntMapOrd (Bimap.insert k a m))
else Left "Update violates relative order."
-- | /O(log n)/. Insert a new key\/value pair in the map. Errors are:
--
-- * Inserting an existing key with a different value.
--
-- * Inserting a key with a value that already exists for another key.
--
-- * Inserting a key\/value pair that breaks the monotonicity invariant.
checkInsert :: Ord a => Int -> a -> IntMapOrd a -> Either String (IntMapOrd a)
checkInsert i b m = case lookup i m of
Nothing -> if memberR b m
then Left "Update violates differentness."
else insert i b m
Just c -> if b==c
then Right m
else Left "Update violates equality."
-- | /O(n * log n)/. The union of two maps. It prefers the first map
-- when duplicate keys are encountered. If the monotonicity invariant is violated,
-- an error is signalled with a 'Left' return value.
union :: Ord a => IntMapOrd a -> IntMapOrd a -> Either String (IntMapOrd a)
union h (IntMapOrd m) = Bimap.fold f (Right h) m
where f k a (Right h) = if member k h
then Right h
else if memberR a h
then Left "Update violates differentness."
else insert k a h
f k a l = l
-- | /O(n)/. Convert the map to a list of key\/value pairs.
toList :: IntMapOrd a -> [(Int,a)]
toList (IntMapOrd a) = Bimap.toList a