-\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}
-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@}
-%* *
-%************************************************************************
-
-\begin{code}
-fmToList fm = foldFM (\ key elt rest -> (key, elt) : rest) [] fm
-keysFM fm = foldFM (\ key _elt rest -> key : rest) [] fm
-eltsFM fm = foldFM (\ _key elt rest -> elt : rest) [] fm
-\end{code}
-
-
-%************************************************************************
-%* *
-\subsection{The implementation of balancing}
-%* *
-%************************************************************************
-
-%************************************************************************
-%* *
-\subsubsection{Basic construction of a @FiniteMap@}
-%* *
-%************************************************************************
-
-@mkBranch@ simply gets the size component right. This is the ONLY
-(non-trivial) place the Branch object is built, so the ASSERTion
-recursively checks consistency. (The trivial use of Branch is in
-@unitFM@.)
-
-\begin{code}
-sIZE_RATIO :: Int
-sIZE_RATIO = 5
-
-mkBranch :: (Ord key OUTPUTABLE_key) -- Used for the assertion checking only
- => Int
- -> key -> elt
- -> FiniteMap key elt -> FiniteMap key elt
- -> FiniteMap key elt
-
-mkBranch _which key elt fm_l fm_r
- = --ASSERT( left_ok && right_ok && balance_ok )
-#if defined(DEBUG_FINITEMAPS)
- if not ( left_ok && right_ok && balance_ok ) then
- pprPanic ("mkBranch:"++show _which)
- (vcat [ppr [left_ok, right_ok, balance_ok],
- ppr key,
- ppr fm_l,
- ppr fm_r])
- else
-#endif
- let
- result = Branch key elt (1 + left_size + right_size) fm_l fm_r
- in
--- if sizeFM result <= 8 then
- result
--- else
--- pprTrace ("mkBranch:"++(show which)) (ppr result) (
--- result
--- )
- where
-#if defined(DEBUG_FINITEMAPS)
- left_ok = case fm_l of
- EmptyFM -> True
- Branch _ _ _ _ _ -> let
- biggest_left_key = fst (findMax fm_l)
- in
- biggest_left_key < key
- right_ok = case fm_r of
- EmptyFM -> True
- Branch _ _ _ _ _ -> let
- smallest_right_key = fst (findMin fm_r)
- in
- key < smallest_right_key
- balance_ok = True -- sigh
-#endif
-{- LATER:
- balance_ok
- = -- Both subtrees have one or no elements...
- (left_size + right_size <= 1)
--- NO || left_size == 0 -- ???
--- NO || right_size == 0 -- ???
- -- ... or the number of elements in a subtree does not exceed
- -- sIZE_RATIO times the number of elements in the other subtree
- || (left_size * sIZE_RATIO >= right_size &&
- right_size * sIZE_RATIO >= left_size)
--}
-
- left_size = sizeFM fm_l
- right_size = sizeFM fm_r
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection{{\em Balanced} construction of a @FiniteMap@}