packages feed

rangeset-0.1.0.0: src/ghc/Data/RangeSet/Internal/SmartConstructors.hs

{-# LANGUAGE BangPatterns, Safe #-}
module Data.RangeSet.Internal.SmartConstructors (
    single,
    fork, forkH,
    balance, balanceL, balanceR,
    uncheckedBalanceL, uncheckedBalanceR
  ) where

import Prelude
import Data.RangeSet.Internal.Types

-- Basic tree constructors
{-# INLINE single #-}
single :: E -> E -> RangeSet a
single !l !u = Fork 1 l u Tip Tip

{-# INLINE heightOfFork #-}
heightOfFork :: H -> H -> H
heightOfFork lh rh = max lh rh + 1

{-# INLINE fork #-}
fork :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
fork !l !u !lt !rt = forkH l u (height lt) lt (height rt) rt

{-# INLINE forkH #-}
forkH :: E -> E -> H -> RangeSet a -> H -> RangeSet a -> RangeSet a
forkH !l !u !lh !lt !rh !rt =  Fork (heightOfFork lh rh) l u lt rt

-- Balancers
{-# NOINLINE balance #-}
balance :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
balance !l !u Tip Tip = single l u
balance l u lt@(Fork lh ll lu llt lrt) Tip
  | lh == 1   = Fork (lh + 1) l u lt Tip
  | otherwise = uncheckedBalanceL l u ll lu llt lrt Tip
balance l u Tip rt@(Fork rh rl ru rlt rrt)
  | rh == 1   = Fork (rh + 1) l u Tip rt
  | otherwise = uncheckedBalanceR l u Tip rl ru rlt rrt
balance l u lt@(Fork lh ll lu llt lrt) rt@(Fork rh rl ru rlt rrt)
  | height lt > height rt + 1 = uncheckedBalanceL l u ll lu llt lrt rt
  | height rt > height lt + 1 = uncheckedBalanceR l u lt rl ru rlt rrt
  | otherwise = forkH l u lh lt rh rt

{-# INLINEABLE balanceL #-}
balanceL :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
-- PRE: left grew or right shrank, difference in height at most 2 biasing to the left
balanceL !l1 !u1 lt@(Fork lh l2 u2 llt lrt) !rt
  -- both sides are equal height or off by one
  | dltrt <= 1 = forkH l1 u1 lh lt rh rt
  -- The bias is 2 (dltrt == 2)
  | otherwise  = uncheckedBalanceL l1 u1 l2 u2 llt lrt rt
  where
    !rh = height rt
    !dltrt = absDiff lh rh
-- If the right shrank (or nothing changed), we have to be prepared to handle the Tip case for lt
balanceL l u Tip rt = Fork (height rt + 1) l u Tip rt

{-# INLINEABLE balanceR #-}
balanceR :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
-- PRE: left shrank or right grew, difference in height at most 2 biasing to the right
balanceR !l1 !u1 !lt rt@(Fork rh l2 u2 rlt rrt)
  -- both sides are equal height or off by one
  | dltrt <= 1 = forkH l1 u1 lh lt rh rt
  | otherwise  = uncheckedBalanceR l1 u1 lt l2 u2 rlt rrt
  where
    !lh = height lt
    !dltrt = absDiff rh lh
-- If the left shrank (or nothing changed), we have to be prepared to handle the Tip case for rt
balanceR l u lt Tip = Fork (height lt + 1) l u lt Tip

{-# NOINLINE uncheckedBalanceL #-}
-- PRE: left grew or right shrank, difference in height at most 2 biasing to the left
uncheckedBalanceL :: E -> E -> E -> E -> RangeSet a -> RangeSet a -> RangeSet a -> RangeSet a
uncheckedBalanceL !l1 !u1 !l2 !u2 !llt !lrt !rt
  -- The bias is 2 (dltrt == 2)
  | hllt >= hlrt = rotr' l1 u1 l2 u2 llt lrt rt
  | otherwise    = rotr l1 u1 (rotl l2 u2 llt lrt) rt
  where
    !hllt = height llt
    !hlrt = height lrt

{-# NOINLINE uncheckedBalanceR #-}
uncheckedBalanceR :: E -> E -> RangeSet a -> E -> E -> RangeSet a -> RangeSet a -> RangeSet a
-- PRE: left shrank or right grew, difference in height at most 2 biasing to the right
uncheckedBalanceR !l1 !u1 !lt !l2 !u2 !rlt !rrt
  -- The bias is 2 (drtlt == 2)
  | hrrt >= hrlt = rotl' l1 u1 lt l2 u2 rlt rrt
  | otherwise    = rotl l1 u1 lt (rotr l2 u2 rlt rrt)
  where
    !hrlt = height rlt
    !hrrt = height rrt

{-# INLINE rotr #-}
rotr :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
rotr !l1 !u1 (Fork _ l2 u2 p q) !r = rotr' l1 u1 l2 u2 p q r
rotr _ _ _ _ = error "rotr on Tip"

{-# INLINE rotl #-}
rotl :: E -> E -> RangeSet a -> RangeSet a -> RangeSet a
rotl !l1 !u1 !p (Fork _ l2 u2 q r) = rotl' l1 u1 p l2 u2 q r
rotl _ _ _ _ = error "rotr on Tip"

{-# INLINE rotr' #-}
rotr' :: E -> E -> E -> E -> RangeSet a -> RangeSet a -> RangeSet a -> RangeSet a
rotr' !l1 !u1 !l2 !u2 !p !q !r = fork l2 u2 p (fork l1 u1 q r)

{-# INLINE rotl' #-}
rotl' :: E -> E -> RangeSet a -> E -> E -> RangeSet a -> RangeSet a -> RangeSet a
rotl' !l1 !u1 !p !l2 !u2 !q !r = fork l2 u2 (fork l1 u1 p q) r