IntMap.hs

-- Copyright (c) 1982-1999 Lennart Augustsson, Thomas Johnsson
-- See LICENSE for the full license.
--
module IntMap (
	IntMap, 
	empty, singleton, union, unionMany, add, (//), addKeep,
	-- union_C, unionMany_C, addMany_C,
	add_C,
	-- intersect, 
	delete, deleteMany, 
	--minus, 
	foldr, imap, filter,
	-- partition, foldl,
	toList, fromList,
	length,
	null, isSingleton,
	-- intersecting, subset
	elems, indices,
	(!),
	lookup, lookupWithDefault --, lookupWithContinuation
	) where

-- @@ Mapping from Int to any type.  Similar to an array with Int index, but
-- @@ without any bounds on the index.

import Prelude hiding (foldr,length,lookup,filter,null)
import qualified Prelude

data IntMap a = Nil | Leaf !Int a | Fork !(IntMap a) !(IntMap a)
instance (Show a) => Show (IntMap a) where
	--showsType _ = showString "IntMap a"
	showsPrec _ Nil = showString "{}"
	showsPrec _ s = showString "{" . f (toList s) . showString "}"
		where f [x] = g x
		      f (x:xs) = g x . showString ", " . f xs
		      g (i, r) = shows i . showString "->" . shows r

instance (Eq a) => Eq (IntMap a) where
	Nil == Nil = True
	Leaf x y == Leaf x' y' = x == x' && y == y'
	Fork l r == Fork l' r' = l == l' && r == r'
	_ == _ = False

empty :: IntMap a
empty = Nil

singleton :: (Int, a) -> IntMap a
singleton (x, y) = Leaf x y

null :: IntMap a -> Bool
null Nil = True
null (Leaf _ _) = False
null (Fork _ _) = False

add :: (Int, a) -> IntMap a -> IntMap a
add (x, y) t = add' x y t
add' :: Int -> a -> IntMap a -> IntMap a
add' x y Nil = Leaf x y
add' x y (Leaf x' y') =
	if x == x' then
	    Leaf x y
	else
	    add' x y (add' x' y' (Fork Nil Nil))
add' x y (Fork l r) =
	if odd x then
	    Fork l (add' (x `div` 2) y r)
	else
	    Fork (add' (x `div` 2) y l) r

-- similar to add, but does not overwrite the old contents
addKeep :: (Int, a) -> IntMap a -> IntMap a
addKeep (x, y) t = addKeep' x y t
addKeep' :: Int -> a -> IntMap a -> IntMap a
addKeep' x y Nil = Leaf x y
addKeep' x y t@(Leaf x' y') =
	if x == x' then
	    t
	else
	    addKeep' x y (addKeep' x' y' (Fork Nil Nil))
addKeep' x y (Fork l r) =
	if odd x then
	    Fork l (addKeep' (x `div` 2) y r)
	else
	    Fork (addKeep' (x `div` 2) y l) r

lookupWithDefault :: IntMap a -> a -> Int -> a
lookupWithDefault Nil d x = if x==x then d else d			-- force it to be strict in x
lookupWithDefault (Leaf x' y) d x = if x == x' then y else d
lookupWithDefault (Fork l r) d x =
	if odd x then
	    lookupWithDefault r d (x `div` 2)
	else
	    lookupWithDefault l d (x `div` 2)

lookup :: Int -> IntMap a -> Maybe a
lookup x Nil = Nothing
lookup x (Leaf x' y) = if x == x' then Just y else Nothing
lookup x (Fork l r) =
	if odd x then
	    lookup (x `div` 2) r
	else
	    lookup (x `div` 2) l

(!) :: IntMap a -> Int -> a
t ! x = case lookup x t of Nothing -> error "IntMap.!: index not found"; Just y -> y


union :: IntMap a -> IntMap a -> IntMap a
union Nil t = t
union (Leaf x y) t = add' x y t
union t Nil = t
union t (Leaf x y) = addKeep' x y t
union (Fork l r) (Fork l' r') = Fork (union l l') (union r r')

unionMany :: [IntMap a] -> IntMap a
unionMany = Prelude.foldr union empty

fromList :: [(Int, a)] -> IntMap a
fromList xs = Prelude.foldr (\ (x,y) -> \ m -> add' x y m) empty xs

toList :: IntMap a -> [(Int, a)]
toList t = foldr (:) [] t
{-
toList :: IntMap a -> [(Int, a)]
toList Nil = []
toList (Leaf x y) = [(x, y)]
toList (Fork l r) = [(2*x, y) | (x, y) <- toList l] ++ [ (2*x+1, y) | (x, y) <- toList r]
-}

elems :: IntMap a -> [a]
elems = Prelude.map snd . toList

indices :: IntMap a -> [Int]
indices = Prelude.map fst . toList

length :: IntMap a -> Int
length Nil = 0
length (Leaf _ _) = 1
length (Fork l r) = length l + length r

isSingleton :: IntMap a -> Bool
isSingleton t = length t == 1

add_C :: (a->a->a) -> (Int, a) -> IntMap a -> IntMap a
add_C comb (x, y) t = add_C' comb x y t
add_C' :: (a->a->a) -> Int -> a -> IntMap a -> IntMap a
add_C' comb x y Nil = Leaf x y
add_C' comb x y (Leaf x' y') =
	if x == x' then
	    Leaf x (comb y y')
	else
	    add_C' comb x y (add_C' comb x' y' (Fork Nil Nil))
add_C' comb x y (Fork l r) =
	if odd x then
	    Fork l (add_C' comb (x `div` 2) y r)
	else
	    Fork (add_C' comb (x `div` 2) y l) r

(//) :: IntMap a -> [(Int, a)] -> IntMap a
t // [] = t
t // ((x,y):xys) = add' x y t // xys

instance Functor IntMap where
    fmap f Nil = Nil
    fmap f (Leaf x y) = Leaf x (f y)
    fmap f (Fork l r) = Fork (fmap f l) (fmap f r)

delete :: Int -> IntMap a -> IntMap a
delete x Nil           = Nil
delete x t@(Leaf x' y) = if x == x' then Nil else t
delete x (Fork l r)    = if odd x then
                             fork l (delete (x `div` 2) r)
			 else
			     fork (delete (x `div` 2) l) r

deleteMany :: [Int] -> IntMap a -> IntMap a
deleteMany is s = Prelude.foldr delete s is

fork Nil        Nil        = Nil
fork Nil        (Leaf x y) = Leaf (x*2+1) y
fork (Leaf x y) Nil        = Leaf (x*2) y
fork l          r          = Fork l r

foldr :: ((Int, a) -> b -> b) -> b -> IntMap a -> b
foldr f z Nil = z
foldr f z (Leaf x y) = f (x,y) z
foldr f z (Fork l r) = foldr g (foldr h z r) l
    where g (x,y) z = f (2*x,y) z
          h (x,y) z = f (2*x+1,y) z

imap :: ((Int, a) -> (Int, b)) -> IntMap a -> IntMap b
imap f t = foldr (add . f) empty t

filter :: ((Int, a) -> Bool) -> IntMap a -> IntMap a
filter p t = foldr (\x l -> if p x then add x l else l) empty t

Plain-text version of IntMap.hs | Valid HTML?