lookupGE :: Key -> IntMap a -> Maybe (Key, a)
lookupGE k = k `seq` start
  where
    start (IntMap (WordMap Empty)) = Nothing
    start (IntMap (WordMap (NonEmpty min minV Tip)))
        | w2i min >= k = Just (w2i min, minV)
        | otherwise = Nothing
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 =
            if w2i max >= k -- if this is true, we know the result is negative
            then Just (goR (xor (i2w k) max) max maxV r)
            else if w2i min >= k -- if this is true, k is between the positives and negatives
                 then Just (w2i min, minV)
                 else case l of
                        Tip -> Nothing
                        Bin maxI maxVI lI rI
                            | maxI < i2w k -> Nothing
                            | otherwise -> Just (goR (xor (i2w k) maxI) maxI maxVI (Bin min minV lI rI))
        | w2i max >= k = Just (goR (xor (i2w k) max) max maxV (Bin min minV l r))
        | otherwise = Nothing
    
    goL !_ Tip fMax fMaxV fallback = getMin fMax fMaxV fallback
    goL !xorCache (Bin max maxV l r) fMax fMaxV fallback
        | w2i max < k = getMin fMax fMaxV fallback
        | xorCache < xorCacheMax = goL xorCache l max maxV r
        | otherwise = goR xorCacheMax max maxV r
      where
        xorCacheMax = xor (i2w k) max
    
    goR !_ max maxV Tip = (w2i max, maxV)
    goR !xorCache max maxV (Bin min minV l r)
        | w2i min >= k = (w2i min, minV)
        | xorCache < xorCacheMin = goR xorCache max maxV r
        | otherwise = goL xorCacheMin l max maxV r
      where
        xorCacheMin = xor min (i2w k)
    
    getMin max maxV Tip = (w2i max, maxV)
    getMin _   _   (Bin min minV _ _) = (w2i min, minV)

-- | /O(1)/. The empty map.
lookupGE :: Key -> IntMap a -> Maybe (Key, a)
lookupGE k = k `seq` start
  where
    start (IntMap (WordMap Empty)) = Nothing
    start (IntMap (WordMap (NonEmpty min minV Tip)))
        | w2i min >= k = Just (w2i min, minV)
        | otherwise = Nothing
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 =
            if w2i max >= k -- if this is true, we know the result is negative
            then Just (goR (xor (i2w k) max) max maxV r)
            else if w2i min >= k -- if this is true, k is between the positives and negatives
                 then Just (w2i min, minV)
                 else case l of
                        Tip -> Nothing
                        Bin maxI maxVI lI rI
                            | maxI < i2w k -> Nothing
                            | otherwise -> Just (goR (xor (i2w k) maxI) maxI maxVI (Bin min minV lI rI))
        | w2i max >= k = Just (goR (xor (i2w k) max) max maxV (Bin min minV l r))
        | otherwise = Nothing
    
    goL !_ Tip fMax fMaxV fallback = getMin fMax fMaxV fallback
    goL !xorCache (Bin max maxV l r) fMax fMaxV fallback
        | w2i max < k = getMin fMax fMaxV fallback
        | xorCache < xorCacheMax = goL xorCache l max maxV r
        | otherwise = goR xorCacheMax max maxV r
      where
        xorCacheMax = xor (i2w k) max
    
    goR !_ max maxV Tip = (w2i max, maxV)
    goR !xorCache max maxV (Bin min minV l r)
        | w2i min >= k = (w2i min, minV)
        | xorCache < xorCacheMin = goR xorCache max maxV r
        | otherwise = goL xorCacheMin l max maxV r
      where
        xorCacheMin = xor min (i2w k)
    
    getMin max maxV Tip = (w2i max, maxV)
    getMin _   _   (Bin min minV _ _) = (w2i min, minV)

-- | /O(1)/. The empty map.
lookupGE k = k `seq` start
  where
    start (IntMap (WordMap Empty)) = Nothing
    start (IntMap (WordMap (NonEmpty min minV Tip)))
        | w2i min >= k = Just (w2i min, minV)
        | otherwise = Nothing
    start (IntMap (WordMap (NonEmpty min minV (Bin max maxV l r))))
        | w2i (xor min max) < 0 =
            if w2i max >= k -- if this is true, we know the result is negative
            then Just (goR (xor (i2w k) max) max maxV r)
            else if w2i min >= k -- if this is true, k is between the positives and negatives
                 then Just (w2i min, minV)
                 else case l of
                        Tip -> Nothing
                        Bin maxI maxVI lI rI
                            | maxI < i2w k -> Nothing
                            | otherwise -> Just (goR (xor (i2w k) maxI) maxI maxVI (Bin min minV lI rI))
        | w2i max >= k = Just (goR (xor (i2w k) max) max maxV (Bin min minV l r))
        | otherwise = Nothing
    
    goL !_ Tip fMax fMaxV fallback = getMin fMax fMaxV fallback
    goL !xorCache (Bin max maxV l r) fMax fMaxV fallback
        | w2i max < k = getMin fMax fMaxV fallback
        | xorCache < xorCacheMax = goL xorCache l max maxV r
        | otherwise = goR xorCacheMax max maxV r
      where
        xorCacheMax = xor (i2w k) max
    
    goR !_ max maxV Tip = (w2i max, maxV)
    goR !xorCache max maxV (Bin min minV l r)
        | w2i min >= k = (w2i min, minV)
        | xorCache < xorCacheMin = goR xorCache max maxV r
        | otherwise = goL xorCacheMin l max maxV r
      where
        xorCacheMin = xor min (i2w k)
    
    getMin max maxV Tip = (w2i max, maxV)
    getMin _   _   (Bin min minV _ _) = (w2i min, minV)

-- | /O(1)/. The empty map.