foldrWithKey :: (Key -> a -> b -> b) -> b -> IntMap a -> b
foldrWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' min minV z
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r (f' max maxV (f' min minV (goL l z)))
        | otherwise = f' min minV (goL l (goR r (f' max maxV z)))
    
    goL Tip acc = acc
    goL (Bin max maxV l r) acc = goL l (goR r (f' max maxV acc))
    
    goR Tip acc = acc
    goR (Bin min minV l r) acc = f' min minV (goL l (goR r acc))
    
    f' k a b = f (w2i k) a b

-- | /O(n)/. Fold the keys and values in the map using the given left-associative
-- binary operator, such that
-- @'foldlWithKey' f z == 'Prelude.foldl' (\\z' (kx, x) -> f z' kx x) z . 'toAscList'@.
--
-- For example,
--
-- > keys = reverse . foldlWithKey (\ks k x -> k:ks) []
--
-- > let f result k a = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldlWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (3:b)(5:a)"

foldrWithKey :: (Key -> a -> b -> b) -> b -> IntMap a -> b
foldrWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' min minV z
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r (f' max maxV (f' min minV (goL l z)))
        | otherwise = f' min minV (goL l (goR r (f' max maxV z)))
    
    goL Tip acc = acc
    goL (Bin max maxV l r) acc = goL l (goR r (f' max maxV acc))
    
    goR Tip acc = acc
    goR (Bin min minV l r) acc = f' min minV (goL l (goR r acc))
    
    f' k a b = f (w2i k) a b

-- | /O(n)/. Fold the keys and values in the map using the given left-associative
-- binary operator, such that
-- @'foldlWithKey' f z == 'Prelude.foldl' (\\z' (kx, x) -> f z' kx x) z . 'toAscList'@.
--
-- For example,
--
-- > keys = reverse . foldlWithKey (\ks k x -> k:ks) []
--
-- > let f result k a = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldlWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (3:b)(5:a)"

foldrWithKey f z = start
  where
    start (IntMap (WordMap Empty)) = z
    start (IntMap (WordMap (NonEmpty min minV Tip))) = f' min minV z
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 = goR r (f' max maxV (f' min minV (goL l z)))
        | otherwise = f' min minV (goL l (goR r (f' max maxV z)))
    
    goL Tip acc = acc
    goL (Bin max maxV l r) acc = goL l (goR r (f' max maxV acc))
    
    goR Tip acc = acc
    goR (Bin min minV l r) acc = f' min minV (goL l (goR r acc))
    
    f' k a b = f (w2i k) a b

-- | /O(n)/. Fold the keys and values in the map using the given left-associative
-- binary operator, such that
-- @'foldlWithKey' f z == 'Prelude.foldl' (\\z' (kx, x) -> f z' kx x) z . 'toAscList'@.
--
-- For example,
--
-- > keys = reverse . foldlWithKey (\ks k x -> k:ks) []
--
-- > let f result k a = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
-- > foldlWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (3:b)(5:a)"
