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