-\subsection{The @FiniteMap@ data type, and building of same}
-%* *
-%************************************************************************
-
-Invariants about @FiniteMap@:
-\begin{enumerate}
-\item
-all keys in a FiniteMap are distinct
-\item
-all keys in left subtree are $<$ key in Branch and
-all keys in right subtree are $>$ key in Branch
-\item
-size field of a Branch gives number of Branch nodes in the tree
-\item
-size of left subtree is differs from size of right subtree by a
-factor of at most \tr{sIZE_RATIO}
-\end{enumerate}
-
-\begin{code}
--- | A finite mapping from (orderable) key types to elements
-data FiniteMap key elt
- = EmptyFM
- | Branch key elt -- Key and elt stored here
- {-# UNPACK #-} !Int -- Size >= 1
- (FiniteMap key elt) -- Children
- (FiniteMap key elt)
-\end{code}
-
-\begin{code}
-emptyFM = EmptyFM
-{-
-emptyFM
- = Branch bottom bottom 0 bottom bottom
- where
- bottom = panic "emptyFM"
--}
-
--- #define EmptyFM (Branch _ _ 0 _ _)
-
-unitFM key elt = Branch key elt 1 emptyFM emptyFM
-
-listToFM = addListToFM emptyFM
-
-bagToFM = foldrBag (\(k,v) fm -> addToFM fm k v) emptyFM
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Adding to and deleting from @FiniteMaps@}
-%* *
-%************************************************************************
-
-\begin{code}
-addToFM fm key elt = addToFM_C (\ _old new -> new) fm key elt
-
-addToFM_C _ EmptyFM key elt = unitFM key elt
-addToFM_C combiner (Branch key elt size fm_l fm_r) new_key new_elt
- = case compare new_key key of
- LT -> mkBalBranch key elt (addToFM_C combiner fm_l new_key new_elt) fm_r
- GT -> mkBalBranch key elt fm_l (addToFM_C combiner fm_r new_key new_elt)
- EQ -> Branch new_key (combiner elt new_elt) size fm_l fm_r
-
-addListToFM fm key_elt_pairs
- = addListToFM_C (\ _old new -> new) fm key_elt_pairs
-
-addListToFM_C combiner fm key_elt_pairs
- = foldl' add fm key_elt_pairs -- foldl adds from the left
- where
- add fmap (key,elt) = addToFM_C combiner fmap key elt
-\end{code}
-
-\begin{code}
-delFromFM EmptyFM _ = emptyFM
-delFromFM (Branch key elt _ fm_l fm_r) del_key
- = case compare del_key key of
- GT -> mkBalBranch key elt fm_l (delFromFM fm_r del_key)
- LT -> mkBalBranch key elt (delFromFM fm_l del_key) fm_r
- EQ -> glueBal fm_l fm_r
-
-delListFromFM fm keys = foldl' delFromFM fm keys
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Combining @FiniteMaps@}
-%* *
-%************************************************************************
-
-\begin{code}
-plusFM_C _ EmptyFM fm2 = fm2
-plusFM_C _ fm1 EmptyFM = fm1
-plusFM_C combiner fm1 (Branch split_key elt2 _ left right)
- = mkVBalBranch split_key new_elt
- (plusFM_C combiner lts left)
- (plusFM_C combiner gts right)
- where
- lts = splitLT fm1 split_key
- gts = splitGT fm1 split_key
- new_elt = case lookupFM fm1 split_key of
- Nothing -> elt2
- Just elt1 -> combiner elt1 elt2
-
--- It's worth doing plusFM specially, because we don't need
--- to do the lookup in fm1.
--- FM2 over-rides FM1.
-
-plusFM EmptyFM fm2 = fm2
-plusFM fm1 EmptyFM = fm1
-plusFM fm1 (Branch split_key elt1 _ left right)
- = mkVBalBranch split_key elt1 (plusFM lts left) (plusFM gts right)
- where
- lts = splitLT fm1 split_key
- gts = splitGT fm1 split_key
-
-minusFM EmptyFM _ = emptyFM
-minusFM fm1 EmptyFM = fm1
-minusFM fm1 (Branch split_key _ _ left right)
- = glueVBal (minusFM lts left) (minusFM gts right)
- -- The two can be way different, so we need glueVBal
- where
- lts = splitLT fm1 split_key -- NB gt and lt, so the equal ones
- gts = splitGT fm1 split_key -- are not in either.
-
-intersectFM fm1 fm2 = intersectFM_C (\ _ right -> right) fm1 fm2
-
-intersectFM_C _ _ EmptyFM = emptyFM
-intersectFM_C _ EmptyFM _ = emptyFM
-intersectFM_C combiner fm1 (Branch split_key elt2 _ left right)
-
- | maybeToBool maybe_elt1 -- split_elt *is* in intersection
- = mkVBalBranch split_key (combiner elt1 elt2)
- (intersectFM_C combiner lts left)
- (intersectFM_C combiner gts right)
-
- | otherwise -- split_elt is *not* in intersection
- = glueVBal (intersectFM_C combiner lts left)
- (intersectFM_C combiner gts right)
-
- where
- lts = splitLT fm1 split_key -- NB gt and lt, so the equal ones
- gts = splitGT fm1 split_key -- are not in either.
-
- maybe_elt1 = lookupFM fm1 split_key
- Just elt1 = maybe_elt1
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Mapping, folding, and filtering with @FiniteMaps@}
-%* *
-%************************************************************************
-
-\begin{code}
-foldFM _ z EmptyFM = z
-foldFM k z (Branch key elt _ fm_l fm_r)
- = foldFM k (k key elt (foldFM k z fm_r)) fm_l
-
-mapFM _ EmptyFM = emptyFM
-mapFM f (Branch key elt size fm_l fm_r)
- = Branch key (f key elt) size (mapFM f fm_l) (mapFM f fm_r)
-
-filterFM _ EmptyFM = emptyFM
-filterFM p (Branch key elt _ fm_l fm_r)
- | p key elt -- Keep the item
- = mkVBalBranch key elt (filterFM p fm_l) (filterFM p fm_r)
-
- | otherwise -- Drop the item
- = glueVBal (filterFM p fm_l) (filterFM p fm_r)
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Interrogating @FiniteMaps@}
-%* *
-%************************************************************************
-
-\begin{code}
---{-# INLINE sizeFM #-}
-sizeFM EmptyFM = 0
-sizeFM (Branch _ _ size _ _) = size
-
-isEmptyFM fm = sizeFM fm == 0
-
-lookupFM EmptyFM _ = Nothing
-lookupFM (Branch key elt _ fm_l fm_r) key_to_find
- = case compare key_to_find key of
- LT -> lookupFM fm_l key_to_find
- GT -> lookupFM fm_r key_to_find
- EQ -> Just elt
-
-key `elemFM` fm = isJust (lookupFM fm key)
-
-lookupWithDefaultFM fm deflt key
- = case (lookupFM fm key) of { Nothing -> deflt; Just elt -> elt }
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Listifying @FiniteMaps@}