radix-tree-1.1.0.0: src/Data/Patricia/Word/Strict/Internal.hs
{-# LANGUAGE BangPatterns
, DeriveLift
, GADTs
, RankNTypes
, ScopedTypeVariables
, UnboxedTuples #-}
module Data.Patricia.Word.Strict.Internal
( StrictPatricia
, Patricia (..)
, Data.Patricia.Word.Strict.Internal.null
, size
, Data.Patricia.Word.Strict.Internal.map
, map'
, mapWithKey
, mapWithKey'
, Data.Patricia.Word.Strict.Internal.foldl
, Data.Patricia.Word.Strict.Internal.foldl'
, foldlWithKey
, foldlWithKey'
, Data.Patricia.Word.Strict.Internal.foldr
, Data.Patricia.Word.Strict.Internal.foldr'
, foldrWithKey
, foldrWithKey'
, Data.Patricia.Word.Strict.Internal.foldMap
, foldMapWithKey
, Data.Patricia.Word.Strict.Internal.traverse
, traverseWithKey
, union
, unionL
, unionWith'
, unionWithKey'
, difference
, differenceWith
, differenceWithKey
, Data.Patricia.Word.Strict.Internal.compare
, disjoint
, intersection
, intersectionL
, intersectionWith'
, intersectionWithKey'
, merge
, Data.Patricia.Word.Strict.Internal.lookup
, Data.Patricia.Word.Strict.Internal.find
, member
, takeOne
, dirtyLookup
, dirtyFind
, dirtyMember
, insert
, insertWith
, insertWith'
, adjust
, adjust'
, delete
, update
, alter
, lookupL
, lookupR
, adjustL
, adjustL'
, adjustLWithKey
, adjustLWithKey'
, adjustR
, adjustR'
, adjustRWithKey
, adjustRWithKey'
, deleteL
, deleteR
, updateL
, updateR
, updateLWithKey
, updateRWithKey
, adjustRange
, unsafeAdjustRange
, adjustRange'
, unsafeAdjustRange'
, adjustRangeWithKey
, unsafeAdjustRangeWithKey
, adjustRangeWithKey'
, unsafeAdjustRangeWithKey'
, deleteRange
, unsafeDeleteRange
, updateRange
, unsafeUpdateRange
, updateRangeWithKey
, unsafeUpdateRangeWithKey
, takeRange
, unsafeTakeRange
, takeL
, takeR
, Split (..)
, splitL
, splitR
, SplitLookup (..)
, splitLookup
, Data.Patricia.Word.Strict.Internal.filter
, filterWithKey
, mapMaybe
, mapMaybeWithKey
, partition
, partitionWithKey
, mapEither
, mapEitherWithKey
, lookupMin
, lookupMinWithKey
, lookupMax
, lookupMaxWithKey
, unsafeLookupMin
, unsafeLookupMinWithKey
, unsafeLookupMax
, unsafeLookupMaxWithKey
, deleteMin
, deleteMax
, adjustMin
, adjustMin'
, adjustMinWithKey
, adjustMinWithKey'
, adjustMax
, adjustMax'
, adjustMaxWithKey
, adjustMaxWithKey'
, updateMin
, updateMinWithKey
, updateMax
, updateMaxWithKey
, ViewL (..)
, minView
, unsafeMinView
, ViewR (..)
, maxView
, unsafeMaxView
) where
import Data.Patricia.Word.Common
import Radix.Common
import Radix.Exception
import Radix.Word.Common
import Radix.Word.Foundation
import Control.Applicative
import Control.DeepSeq
import Control.Exception (throw)
import Data.Bits
import Data.Foldable
import Data.Functor.Classes
import Language.Haskell.TH.Syntax (Lift)
import Text.Read
import Text.Show
-- | Convenience synonym.
type StrictPatricia = Patricia
-- | Spine-strict PATRICIA tree.
data Patricia a = Bin
{-# UNPACK #-} !Prefix
!(Patricia a) -- ^ Masked bit is @0@.
!(Patricia a) -- ^ Masked bit is @1@.
| Tip
{-# UNPACK #-} !Key
a
| Nil -- ^ Invariant: only allowed as the root of the tree.
deriving Lift
instance Show a => Show (Patricia a) where
showsPrec = liftShowsPrec showsPrec showList
instance Show1 Patricia where
liftShowsPrec showsPrec_ showList_ _ t =
showListWith (liftShowsPrec showsPrec_ showList_ 0) $
foldrWithKey (\k a -> (:) (k, a)) [] t
instance Read a => Read (Patricia a) where
readPrec = liftReadPrec readPrec readListPrec
instance Read1 Patricia where
liftReadPrec readPrec_ readList_ =
fmap (Data.Foldable.foldl' (\z (k, a) -> insert k a z) Nil)
(liftReadListPrec readPrec_ readList_)
instance Eq a => Eq (Patricia a) where
(==) = liftEq (==)
instance Eq1 Patricia where
liftEq eq = go
where
go l r =
case l of
Bin p xl xr ->
case r of
Bin q yl yr -> p == q && go xl yl && go xr yr
_ -> False
Tip kA a ->
case r of
Tip kB b -> kA == kB && eq a b
_ -> False
Nil ->
case r of
Nil -> True
_ -> False
-- | Uses 'Data.Patricia.Word.Strict.map'.
instance Functor Patricia where
fmap = Data.Patricia.Word.Strict.Internal.map
instance Foldable Patricia where
foldl = Data.Patricia.Word.Strict.Internal.foldl
foldr = Data.Patricia.Word.Strict.Internal.foldr
foldMap = Data.Patricia.Word.Strict.Internal.foldMap
foldl' = Data.Patricia.Word.Strict.Internal.foldl'
foldr' = Data.Patricia.Word.Strict.Internal.foldr'
null = Data.Patricia.Word.Strict.Internal.null
length = fromIntegral . size
instance Traversable Patricia where
traverse = Data.Patricia.Word.Strict.Internal.traverse
instance NFData a => NFData (Patricia a) where
rnf = liftRnf rnf
instance NFData1 Patricia where
liftRnf nf = go
where
go t =
case t of
Bin _ l r -> go l `seq` go r
Tip _ a -> nf a
Nil -> ()
{-# INLINE join #-}
-- | Knowing that the prefices of two non-'Nil' trees disagree, construct a 'Bin'.
join :: Prefix -> Patricia a -> Prefix -> Patricia a -> Patricia a
join p0 t0 p1 t1 =
let m = branchingBit p0 p1
p = mask p0 m .|. m
in if zeroBit p0 m
then Bin p t0 t1
else Bin p t1 t0
{-# INLINE safeJoin #-}
-- | Knowing that the prefices of two trees disagree, construct a 'Bin'.
safeJoin :: Prefix -> Patricia a -> Prefix -> Patricia a -> Patricia a
safeJoin _ Nil _ t1 = t1
safeJoin _ t0 _ Nil = t0
safeJoin p0 t0 p1 t1 = join p0 t0 p1 t1
{-# INLINE rebin #-}
-- | Reconstruct a 'Bin' knowing that either of the sides may now be a 'Nil'.
rebin :: Prefix -> Patricia a -> Patricia a -> Patricia a
rebin p l r =
case l of
Nil -> r
_ ->
case r of
Nil -> l
_ -> Bin p l r
{-# INLINE rebinL #-}
-- | Reconstruct a 'Bin' knowing that the left side may now be a 'Nil'.
rebinL :: Prefix -> Patricia a -> Patricia a -> Patricia a
rebinL p l r =
case l of
Nil -> r
_ -> Bin p l r
{-# INLINE rebinR #-}
-- | Reconstruct a 'Bin' knowing that the right side may now be a 'Nil'.
rebinR :: Prefix -> Patricia a -> Patricia a -> Patricia a
rebinR p l r =
case r of
Nil -> l
_ -> Bin p l r
{-# INLINE retip #-}
-- | Reconstruct a 'Tip' knowing that the value may not be there anymore.
retip :: Key -> Maybe a -> Patricia a
retip w (Just a) = Tip w a
retip _ Nothing = Nil
-- | \(\mathcal{O}(1)\).
-- Check if the tree is empty.
null :: Patricia a -> Bool
null Nil = True
null _ = False
-- | \(\mathcal{O}(n)\).
-- Calculate the number of elements stored in the tree.
-- The returned number is guaranteed to be non-negative.
size :: Patricia a -> Int
size t =
case t of
Bin _ l r -> let !m = size l
!n = size r
in m + n
Tip _ _ -> 1
Nil -> 0
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree.
map :: (a -> b) -> Patricia a -> Patricia b
map f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) (go r)
Tip k a -> Tip k (f a)
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree.
--
-- New values are evaluated to WHNF.
map' :: (a -> b) -> Patricia a -> Patricia b
map' f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) (go r)
Tip k a -> Tip k $! f a
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree.
mapWithKey :: (Word -> a -> b) -> Patricia a -> Patricia b
mapWithKey f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) (go r)
Tip k a -> Tip k (f k a)
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree.
--
-- New values are evaluated to WHNF.
mapWithKey' :: (Word -> a -> b) -> Patricia a -> Patricia b
mapWithKey' f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) (go r)
Tip k a -> Tip k $! f k a
Nil -> Nil
-- | \(\mathcal{O}(n_R)\).
-- Fold the tree left-to-right.
foldl :: (b -> a -> b) -> b -> Patricia a -> b
foldl f = go
where
go z t =
case t of
Bin _ l r -> go (go z l) r
Tip _ a -> f z a
Nil -> z
-- | \(\mathcal{O}(n_R)\).
-- Fold the tree left-to-right.
foldlWithKey :: (b -> Word -> a -> b) -> b -> Patricia a -> b
foldlWithKey f = go
where
go z t =
case t of
Bin _ l r -> go (go z l) r
Tip k a -> f z k a
Nil -> z
-- | \(\mathcal{O}(n)\).
-- Fold the tree left-to-right with a strict accumulator.
foldl' :: (b -> a -> b) -> b -> Patricia a -> b
foldl' f = go
where
go !z t =
case t of
Bin _ l r -> let !z' = go z l
in go z' r
Tip _ a -> f z a
Nil -> z
-- | \(\mathcal{O}(n)\).
-- Fold the tree left-to-right with a strict accumulator.
foldlWithKey' :: (b -> Word -> a -> b) -> b -> Patricia a -> b
foldlWithKey' f = go
where
go !z t =
case t of
Bin _ l r -> let !z' = go z l
in go z' r
Tip k a -> f z k a
Nil -> z
-- | \(\mathcal{O}(n_L)\).
-- Fold the tree right-to-left.
foldr :: (a -> b -> b) -> b -> Patricia a -> b
foldr f = go
where
go z t =
case t of
Bin _ l r -> go (go z r) l
Tip _ a -> f a z
Nil -> z
-- | \(\mathcal{O}(n_L)\).
-- Fold the tree right-to-left.
foldrWithKey :: (Word -> a -> b -> b) -> b -> Patricia a -> b
foldrWithKey f = go
where
go z t =
case t of
Bin _ l r -> go (go z r) l
Tip k a -> f k a z
Nil -> z
-- | \(\mathcal{O}(n)\).
-- Fold the tree right-to-left with a strict accumulator.
foldr' :: (a -> b -> b) -> b -> Patricia a -> b
foldr' f = go
where
go !z t =
case t of
Bin _ l r -> let !z' = go z r
in go z' l
Tip _ a -> f a z
Nil -> z
-- | \(\mathcal{O}(n)\).
-- Fold the tree right-to-left with a strict accumulator.
foldrWithKey' :: (Word -> a -> b -> b) -> b -> Patricia a -> b
foldrWithKey' f = go
where
go !z t =
case t of
Bin _ l r -> let !z' = go z r
in go z' l
Tip k a -> f k a z
Nil -> z
-- | \(\mathcal{O}(n_M)\).
-- Map each element in the tree to a monoid and combine the results.
foldMap :: Monoid m => (a -> m) -> Patricia a -> m
foldMap f = go
where
go t =
case t of
Bin _ l r -> go l <> go r
Tip _ a -> f a
Nil -> mempty
-- | \(\mathcal{O}(n_M)\).
-- Map each element in the tree to a monoid and combine the results.
foldMapWithKey :: Monoid m => (Word -> a -> m) -> Patricia a -> m
foldMapWithKey f = go
where
go t =
case t of
Bin _ l r -> go l <> go r
Tip k a -> f k a
Nil -> mempty
-- | \(\mathcal{O}(n)\).
-- Map each element in the tree to an action, evaluate these actions
-- left-to-right and collect the results.
traverse :: Applicative f => (a -> f b) -> Patricia a -> f (Patricia b)
traverse f = go
where
go t =
case t of
Bin p l r -> liftA2 (Bin p) (go l) (go r)
Tip k a -> Tip k <$> f a
Nil -> pure Nil
-- | \(\mathcal{O}(n)\).
-- Map each element in the tree to an action, evaluate these actions
-- left-to-right and collect the results.
traverseWithKey :: Applicative f => (Word -> a -> f b) -> Patricia a -> f (Patricia b)
traverseWithKey f = go
where
go t =
case t of
Bin p l r -> liftA2 (Bin p) (go l) (go r)
Tip k a -> Tip k <$> f k a
Nil -> pure Nil
type UBin a = (# Prefix, Patricia a, Patricia a #)
type UTip a = (# Word, a #)
-- | \(\mathcal{O}(n_A + n_B)\).
-- Unbiased union of two trees.
union :: Patricia a -> Patricia a -> Patricia a
union = anyAny
where
anyAny tA tB =
case tA of
Bin pA lA rA -> binAny (# pA, lA, rA #) tA tB
Tip kA _ -> tipAny kA tA tB
Nil -> tB
tipAny kA tA tB =
case tB of
Bin pB lB rB -> tipBin kA tA (# pB, lB, rB #) tB
Tip kB _
| kA == kB -> tA
| otherwise -> join kA tA kB tB
Nil -> tA
binAny uA tA tB =
case tB of
Bin pB lB rB -> binBin uA tA (# pB, lB, rB #) tB
Tip kB _ -> tipBin kB tB uA tA
Nil -> tA
tipBin kA tA (# pB, lB, rB #) tB
| beyond pB kA = join kA tA pB tB
| kA < pB = Bin pB (tipAny kA tA lB) rB
| otherwise = Bin pB lB (tipAny kA tA rB)
binBin uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
let {-# NOINLINE no #-}
no = join pA tA pB tB
in case Prelude.compare pA pB of
EQ -> Bin pA (anyAny lA lB) (anyAny rA rB)
LT | pB <= upper pA -> Bin pA lA (binAny uB tB rA)
| pA >= lower pB -> Bin pB (binAny uA tA lB) rB
| otherwise -> no
GT | pA <= upper pB -> Bin pB lB (binAny uA tA rB)
| pB >= lower pA -> Bin pA (binAny uB tB lA) rA
| otherwise -> no
-- | \(\mathcal{O}(n_A + n_B)\).
-- Left-biased union of two trees.
unionL :: Patricia a -> Patricia a -> Patricia a
unionL =
union_ $ \s k a b ->
let !(# c #) = case s of
L -> (# a #)
R -> (# b #)
in Tip k c
-- | \(\mathcal{O}(n_A + n_B)\).
-- Union of two trees with a combining function.
--
-- New values are evaluated to WHNF.
unionWith'
:: (a -> a -> a)
-> Patricia a
-> Patricia a
-> Patricia a
unionWith' f =
union_ $ \s k a b ->
Tip k $! case s of
L -> f a b
R -> f b a
-- | \(\mathcal{O}(n_A + n_B)\).
-- Union of two trees with a combining function.
--
-- New values are evaluated to WHNF.
unionWithKey'
:: (Word -> a -> a -> a)
-> Patricia a
-> Patricia a
-> Patricia a
unionWithKey' f =
union_ $ \s k a b ->
Tip k $! case s of
L -> f k a b
R -> f k b a
{-# INLINE union_ #-}
union_
:: (forall x y. S x y a a -> Key -> x -> y -> Patricia a)
-> Patricia a
-> Patricia a
-> Patricia a
union_ f = anyAny L
where
anyAny s tA tB =
case tA of
Bin pA lA rA -> binAny s (# pA, lA, rA #) tA tB
Tip kA a -> tipAny s (# kA, a #) tA tB
Nil -> tB
tipAny s uA@(# kA, a #) tA tB =
case tB of
Bin pB lB rB -> tipBin s uA tA (# pB, lB, rB #) tB
Tip kB b
| kA == kB -> f s kA a b
| otherwise -> join kA tA kB tB
Nil -> tA
binAny s uA tA tB =
case tB of
Bin pB lB rB -> binBin s uA tA (# pB, lB, rB #) tB
Tip kB b ->
let !(# s' #) = other s
in tipBin s' (# kB, b #) tB uA tA
Nil -> tA
tipBin s uA@(# kA, _ #) tA (# pB, lB, rB #) tB
| beyond pB kA = join kA tA pB tB
| kA < pB = Bin pB (tipAny s uA tA lB) rB
| otherwise = Bin pB lB (tipAny s uA tA rB)
binBin s uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
let {-# NOINLINE no #-}
no = join pA tA pB tB
in case Prelude.compare pA pB of
EQ -> Bin pA (anyAny s lA lB) (anyAny s rA rB)
LT | pB <= upper pA -> let !(# s' #) = other s
in Bin pA lA (binAny s' uB tB rA)
| pA >= lower pB -> Bin pB (binAny s uA tA lB) rB
| otherwise -> no
GT | pA <= upper pB -> Bin pB lB (binAny s uA tA rB)
| pB >= lower pA -> let !(# s' #) = other s
in Bin pA (binAny s' uB tB lA) rA
| otherwise -> no
-- | \(\mathcal{O}(n_A + n_B)\).
-- Difference of two trees.
difference :: Patricia a -> Patricia b -> Patricia a
difference =
difference_ $ \_ _ _ _ ->
Nil
-- | \(\mathcal{O}(n_A + n_B)\).
-- Difference of two trees with a combining function.
--
-- The 'Maybe' is evaluated to WHNF.
differenceWith
:: (a -> b -> Maybe a)
-> Patricia a
-> Patricia b
-> Patricia a
differenceWith f =
difference_ $ \s k a b ->
retip k $ case s of
L -> f a b
R -> f b a
-- | \(\mathcal{O}(n_A + n_B)\).
-- Difference of two trees with a combining function.
--
-- The 'Maybe' is evaluated to WHNF.
differenceWithKey
:: (Word -> a -> b -> Maybe a)
-> Patricia a
-> Patricia b
-> Patricia a
differenceWithKey f =
difference_ $ \s k a b ->
retip k $ case s of
L -> f k a b
R -> f k b a
{-# INLINE difference_ #-}
difference_
:: (forall x y. S x y a b -> Key -> x -> y -> Patricia a)
-> Patricia a
-> Patricia b
-> Patricia a
difference_ (f :: forall n o. S n o x y -> Key -> n -> o -> Patricia x) = anyAny L
where
anyAny
:: forall a b. S a b x y -> Patricia a -> Patricia b -> Patricia x
anyAny s tA tB =
case tA of
Bin pA lA rA -> binAny s (# pA, lA, rA #) tA tB
Tip kA a -> tipAny s (# kA, a #) tA tB
Nil -> case s of
L -> tA
R -> tB
tipAny
:: forall a b. S a b x y -> UTip a -> Patricia a -> Patricia b -> Patricia x
tipAny s uA@(# kA, a #) tA tB =
case tB of
Bin pB lB rB -> tipBin s uA tA (# pB, lB, rB #) tB
Tip kB b
| kA == kB -> f s kA a b
| otherwise -> case s of
L -> tA
R -> tB
Nil -> case s of
L -> tA
R -> tB
binAny
:: forall a b. S a b x y -> UBin a -> Patricia a -> Patricia b -> Patricia x
binAny s uA tA tB =
case tB of
Bin pB lB rB -> binBin s uA tA (# pB, lB, rB #) tB
Tip kB b -> let !(# s' #) = other s
in tipBin s' (# kB, b #) tB uA tA
Nil -> case s of
L -> tA
R -> tB
tipBin
:: forall a b. S a b x y -> UTip a -> Patricia a -> UBin b -> Patricia b -> Patricia x
tipBin s uA@(# kA, _ #) tA (# pB, lB, rB #) tB
| beyond pB kA = case s of
L -> tA
R -> tB
| kA < pB = case s of
L -> tipAny s uA tA lB
R -> rebinL pB (tipAny s uA tA lB) rB
| otherwise = case s of
L -> tipAny s uA tA rB
R -> rebinR pB lB (tipAny s uA tA rB)
binBin
:: forall a b. S a b x y -> UBin a -> Patricia a -> UBin b -> Patricia b -> Patricia x
binBin s uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
let {-# NOINLINE no #-}
no = case s of
L -> tA
R -> tB
in case Prelude.compare pA pB of
EQ -> rebin pA (anyAny s lA lB) (anyAny s rA rB)
LT | pB <= upper pA -> case s of
L -> rebinR pA lA (binAny R uB tB rA)
R -> binAny L uB tB rA
| pA >= lower pB -> case s of
L -> binAny s uA tA lB
R -> rebinL pB (binAny s uA tA lB) rB
| otherwise -> no
GT | pA <= upper pB -> case s of
L -> binAny s uA tA rB
R -> rebinR pB lB (binAny s uA tA rB)
| pB >= lower pA -> case s of
L -> rebinL pA (binAny R uB tB lA) rA
R -> binAny L uB tB lA
| otherwise -> no
-- | \(\mathcal{O}(n_A + n_B)\).
-- Compare two trees with respect to set inclusion,
-- using the given equality function for intersecting keys.
-- If any intersecting keys hold unequal values, the trees are 'Incomparable'.
compare :: (a -> b -> Bool) -> Patricia a -> Patricia b -> PartialOrdering
compare (f :: x -> y -> Bool) = anyAny L
where
anyAny
:: forall a b. S a b x y -> Patricia a -> Patricia b -> PartialOrdering
anyAny s tA tB =
case tA of
Bin pA lA rA -> binAny s (# pA, lA, rA #) tA tB
Tip kA a -> tipAny s (# kA, a #) tA tB
Nil -> case tB of
Nil -> Equal
_ -> Subset
tipAny
:: forall a b. S a b x y -> UTip a -> Patricia a -> Patricia b -> PartialOrdering
tipAny s uA@(# kA, a #) tA tB =
case tB of
Bin pB lB rB -> tipBin s uA tA (# pB, lB, rB #)
Tip kB b
| kA == kB -> let eq = case s of
L -> f a b
R -> f b a
in if eq
then Equal
else Incomparable
| otherwise -> Incomparable
Nil -> Superset
binAny
:: forall a b. S a b x y -> UBin a -> Patricia a -> Patricia b -> PartialOrdering
binAny s uA tA tB =
case tB of
Bin pB lB rB -> binBin s uA tA (# pB, lB, rB #) tB
Tip kB b -> let !(# s' #) = other s
in tipBin s' (# kB, b #) tB uA
Nil -> Superset
tipBin
:: forall a b. S a b x y -> UTip a -> Patricia a -> UBin b -> PartialOrdering
tipBin s uA@(# kA, _ #) tA (# pB, lB, rB #) =
if beyond pB kA
then Incomparable
else limit s . tipAny s uA tA $ if kA < pB
then lB
else rB
binBin
:: forall a b. S a b x y -> UBin a -> Patricia a -> UBin b -> Patricia b -> PartialOrdering
binBin s uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
case Prelude.compare pA pB of
EQ -> order (anyAny s lA lB) (anyAny s rA rB)
LT | pB <= upper pA -> let !(# s' #) = other s
in limit s' $ binAny s' uB tB rA
| pA >= lower pB -> limit s $ binAny s uA tA lB
| otherwise -> Incomparable
GT | pA <= upper pB -> limit s $ binAny s uA tA rB
| pB >= lower pA -> let !(# s' #) = other s
in limit s' $ binAny s' uB tB lA
| otherwise -> Incomparable
-- | \(\mathcal{O}(n_A + n_B)\).
-- Determine whether two trees' key sets are disjoint.
disjoint :: Patricia a -> Patricia b -> Bool
disjoint = anyAny
where
anyAny tA tB =
case tA of
Bin pA lA rA -> binAny (# pA, lA, rA #) tA tB
Tip kA _ -> tipAny kA tA tB
Nil -> True
tipAny kA tA tB =
case tB of
Bin pB lB rB -> tipBin kA tA (# pB, lB, rB #)
Tip kB _ -> kA /= kB
Nil -> True
binAny :: forall a b. UBin a -> Patricia a -> Patricia b -> Bool
binAny uA tA tB =
case tB of
Bin pB lB rB -> binBin uA tA (# pB, lB, rB #) tB
Tip kB _ -> tipBin kB tB uA
Nil -> True
tipBin kA tA (# pB, lB, rB #)
| beyond pB kA = True
| otherwise = tipAny kA tA $ if kA < pB
then lB
else rB
binBin uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
case Prelude.compare pA pB of
EQ -> anyAny lA lB && anyAny rA rB
LT | pB <= upper pA -> binAny uB tB rA
| pA >= lower pB -> binAny uA tA lB
| otherwise -> True
GT | pA <= upper pB -> binAny uA tA rB
| pB >= lower pA -> binAny uB tB lA
| otherwise -> True
-- | \(\mathcal{O}(n_A + n_B)\).
-- Unbiased intersection of two trees.
intersection :: Patricia a -> Patricia a -> Patricia a
intersection = anyAny
where
anyAny tA tB =
case tA of
Bin pA lA rA -> binAny (# pA, lA, rA #) tA tB
Tip kA _ -> tipAny kA tA tB
Nil -> Nil
tipAny kA tA tB =
case tB of
Bin pB lB rB -> tipBin kA tA (# pB, lB, rB #)
Tip kB _
| kA == kB -> tA
| otherwise -> Nil
Nil -> Nil
binAny uA tA tB =
case tB of
Bin pB lB rB -> binBin uA tA (# pB, lB, rB #) tB
Tip kB _ -> tipBin kB tB uA
Nil -> Nil
tipBin kA tA (# pB, lB, rB #)
| beyond pB kA = Nil
| otherwise = tipAny kA tA $ if kA < pB
then lB
else rB
binBin uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
case Prelude.compare pA pB of
EQ -> rebin pA (anyAny lA lB) (anyAny rA rB)
LT | pB <= upper pA -> binAny uB tB rA
| pA >= lower pB -> binAny uA tA lB
| otherwise -> Nil
GT | pA <= upper pB -> binAny uA tA rB
| pB >= lower pA -> binAny uB tB lA
| otherwise -> Nil
-- | \(\mathcal{O}(n_A + n_B)\).
-- Left-biased intersection of two trees.
intersectionL :: Patricia a -> Patricia b -> Patricia a
intersectionL =
intersection_ $ \s k a b ->
let !(# c #) = case s of
L -> (# a #)
R -> (# b #)
in Tip k c
-- | \(\mathcal{O}(n_A + n_B)\).
-- Intersection of two trees with a combining function.
--
-- New values are evaluated to WHNF.
intersectionWith'
:: (a -> b -> c)
-> Patricia a
-> Patricia b
-> Patricia c
intersectionWith' f =
intersection_ $ \s k a b ->
Tip k $! case s of
L -> f a b
R -> f b a
-- | \(\mathcal{O}(n_A + n_B)\).
-- Intersection of two trees with a combining function.
--
-- New values are evaluated to WHNF.
intersectionWithKey'
:: (Word -> a -> b -> c)
-> Patricia a
-> Patricia b
-> Patricia c
intersectionWithKey' f =
intersection_ $ \s k a b ->
Tip k $! case s of
L -> f k a b
R -> f k b a
{-# INLINE intersection_ #-}
intersection_
:: (forall x y. S x y a b -> Key -> x -> y -> Patricia c)
-> Patricia a
-> Patricia b
-> Patricia c
intersection_ (f :: forall n o. S n o x y -> Word -> n -> o -> Patricia c) =
anyAny L
where
anyAny
:: forall a b. S a b x y -> Patricia a -> Patricia b -> Patricia c
anyAny s tA tB =
case tA of
Bin pA lA rA -> binAny s (# pA, lA, rA #) tA tB
Tip kA a -> tipAny s (# kA, a #) tA tB
Nil -> Nil
tipAny
:: forall a b. S a b x y -> UTip a -> Patricia a -> Patricia b -> Patricia c
tipAny s uA@(# kA, a #) tA tB =
case tB of
Bin pB lB rB -> tipBin s uA tA (# pB, lB, rB #)
Tip kB b
| kA == kB -> f s kA a b
| otherwise -> Nil
Nil -> Nil
binAny
:: forall a b. S a b x y -> UBin a -> Patricia a -> Patricia b -> Patricia c
binAny s uA tA tB =
case tB of
Bin pB lB rB -> binBin s uA tA (# pB, lB, rB #) tB
Tip kB b -> let !(# s' #) = other s
in tipBin s' (# kB, b #) tB uA
Nil -> Nil
tipBin
:: forall a b. S a b x y -> UTip a -> Patricia a -> UBin b -> Patricia c
tipBin s uA@(# kA, _ #) tA (# pB, lB, rB #)
| beyond pB kA = Nil
| otherwise = tipAny s uA tA $ if kA < pB
then lB
else rB
binBin
:: forall a b. S a b x y -> UBin a -> Patricia a -> UBin b -> Patricia b -> Patricia c
binBin s uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
case Prelude.compare pA pB of
EQ -> rebin pA (anyAny s lA lB) (anyAny s rA rB)
LT | pB <= upper pA -> let !(# s' #) = other s
in binAny s' uB tB rA
| pA >= lower pB -> binAny s uA tA lB
| otherwise -> Nil
GT | pA <= upper pB -> binAny s uA tA rB
| pB >= lower pA -> let !(# s' #) = other s
in binAny s' uB tB lA
| otherwise -> Nil
{-# INLINE merge #-}
-- | \(\mathcal{O}(n_A + n_B)\).
-- General merge of two trees.
--
-- Collision and single value functions __must__ return either
-- 'Tip' with the respective key, or 'Nil'.
--
-- Subtree argument functions may return any tree, however the shape of said tree
-- __must__ be compatible with the prefix passed to the function.
--
-- Resulting 'Patricia' trees in argument functions are evaluated to WHNF.
--
-- This functions inlines when all argument functions are provided.
merge
:: (Key -> a -> b -> Patricia c) -- ^ Single value collision
-> (Key -> a -> Patricia c) -- ^ Single left value
-> (Prefix -> Patricia a -> Patricia a -> Patricia c) -- ^ Left subtree
-> (Key -> b -> Patricia c) -- ^ Single right value
-> (Prefix -> Patricia b -> Patricia b -> Patricia c) -- ^ Right subtree
-> Patricia a
-> Patricia b
-> Patricia c
merge (f :: Key -> x -> y -> Patricia c) oneX treeX oneY treeY = anyAny L
where
{-# INLINE side #-}
side one tree t =
case t of
Bin p l r -> tree p l r
Tip k a -> one k a
Nil -> Nil
sideX = side oneX treeX
sideY = side oneY treeY
sideA :: forall a b. S a b x y -> Patricia a -> Patricia c
sideA s tA = case s of
L -> sideX tA
R -> sideY tA
sideB :: forall a b. S a b x y -> Patricia b -> Patricia c
sideB s tB = case s of
L -> sideY tB
R -> sideX tB
anyAny
:: forall a b. S a b x y -> Patricia a -> Patricia b -> Patricia c
anyAny s tA tB =
case tA of
Bin pA lA rA -> binAny s (# pA, lA, rA #) tA tB
Tip kA a -> tipAny s (# kA, a #) tA tB
Nil -> sideB s tB
tipAny
:: forall a b. S a b x y -> UTip a -> Patricia a -> Patricia b -> Patricia c
tipAny s uA@(# kA, a #) tA tB =
case tB of
Bin pB lB rB -> tipBin s uA tA (# pB, lB, rB #)
Tip kB b
| kA == kB -> case s of
L -> f kA a b
R -> f kA b a
| otherwise -> case s of
L -> safeJoin kA (oneX kA a) kB (sideY tB)
R -> safeJoin kA (oneY kA a) kB (sideX tB)
Nil -> sideA s tA
binAny
:: forall a b. S a b x y -> UBin a -> Patricia a -> Patricia b -> Patricia c
binAny s uA tA tB =
case tB of
Bin pB lB rB -> binBin s uA tA (# pB, lB, rB #) tB
Tip kB b -> let !(# s' #) = other s
in tipBin s' (# kB, b #) tB uA
Nil -> sideA s tA
tipBin
:: forall a b. S a b x y -> UTip a -> Patricia a -> UBin b -> Patricia c
tipBin s uA@(# kA, a #) tA (# pB, lB, rB #)
| beyond pB kA = case s of
L -> safeJoin kA (oneX kA a) pB (treeY pB lB rB)
R -> safeJoin kA (oneY kA a) pB (treeX pB lB rB)
| kA < pB = rebin pB (tipAny s uA tA lB) (sideB s rB)
| otherwise = rebin pB (sideB s lB) (tipAny s uA tA rB)
binBin
:: forall a b. S a b x y -> UBin a -> Patricia a -> UBin b -> Patricia b -> Patricia c
binBin s uA@(# pA, lA, rA #) tA uB@(# pB, lB, rB #) tB =
let {-# NOINLINE no #-}
no = case s of
L -> safeJoin pA (treeX pA lA rA) pB (treeY pB lB rB)
R -> safeJoin pA (treeY pA lA rA) pB (treeX pB lB rB)
in case Prelude.compare pA pB of
EQ -> rebin pA (anyAny s lA lB) (anyAny s rA rB)
LT | pB <= upper pA -> let !(# s' #) = other s
in rebin pA (sideA s lA) (binAny s' uB tB rA)
| pA >= lower pB -> rebin pB (binAny s uA tA lB) (sideB s rB)
| otherwise -> no
GT | pA <= upper pB -> rebin pB (sideB s lB) (binAny s uA tA rB)
| pB >= lower pA -> let !(# s' #) = other s
in rebin pA (binAny s' uB tB lA) (sideA s rA)
| otherwise -> no
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the value at a key in the tree.
lookup :: Word -> Patricia a -> Maybe a
lookup !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> Nothing
| w < p -> go l
| otherwise -> go r
Tip k a
| k == w -> Just a
| otherwise -> Nothing
Nil -> Nothing
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the value at a key in the tree, falling back to the given default value
-- if it does not exist.
find :: a -> Word -> Patricia a -> a
find d !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> d
| w < p -> go l
| otherwise -> go r
Tip k a
| k == w -> a
| otherwise -> d
Nil -> d
-- | \(\mathcal{O}(\min(n,W))\).
-- Check whether the value exists at a key in the tree.
member :: Word -> Patricia a -> Bool
member !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> False
| w < p -> go l
| otherwise -> go r
Tip k _ -> k == w
Nil -> False
-- 'lookup' that doesn't allocate a 'Maybe'.
takeOne :: Word -> Patricia a -> Patricia a
takeOne !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> Nil
| w < p -> go l
| otherwise -> go r
Tip k _
| k == w -> t
| otherwise -> Nil
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the value at a key in the tree.
dirtyLookup :: Word -> Patricia a -> Maybe a
dirtyLookup !w = go
where
go t =
case t of
Bin p l r
| w < p -> go l
| otherwise -> go r
Tip k a
| k == w -> Just a
| otherwise -> Nothing
Nil -> Nothing
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the value at a key in the tree, falling back to the default value
-- if it does not exist.
dirtyFind :: a -> Word -> Patricia a -> a
dirtyFind d !w = go
where
go t =
case t of
Bin p l r
| w < p -> go l
| otherwise -> go r
Tip k a
| k == w -> a
| otherwise -> d
Nil -> d
-- | \(\mathcal{O}(\min(n,W))\).
-- Check whether the value exists at a key in the tree.
dirtyMember :: Word -> Patricia a -> Bool
dirtyMember !w = go
where
go t =
case t of
Bin p l r
| w < p -> go l
| otherwise -> go r
Tip k _ -> k == w
Nil -> False
-- | \(\mathcal{O}(\min(n,W))\).
-- Insert a new value in the tree at the given key.
-- If a value already exists at that key, it is replaced.
insert :: Word -> a -> Patricia a -> Patricia a
insert !w a = go
where
go t =
case t of
Bin p l r
| beyond p w -> join w (Tip w a) p t
| w < p -> Bin p (go l) r
| otherwise -> Bin p l (go r)
Tip k _
| k == w -> Tip k a
| otherwise -> join w (Tip w a) k t
Nil -> Tip w a
-- | \(\mathcal{O}(\min(n,W))\).
-- Insert a new value in the tree at the given key.
-- If a value already exists at that key, the function is used instead.
insertWith :: (a -> a) -> Word -> a -> Patricia a -> Patricia a
insertWith f !w b = go
where
go t =
case t of
Bin p l r
| beyond p w -> join w (Tip w b) p t
| w < p -> Bin p (go l) r
| otherwise -> Bin p l (go r)
Tip k a
| k == w -> Tip k (f a)
| otherwise -> join w (Tip w b) k t
Nil -> Tip w b
-- | \(\mathcal{O}(\min(n,W))\).
-- Insert a new value in the tree at the given key.
-- If a value already exists at that key, the function is used instead.
--
-- New value is evaluted to WHNF.
insertWith' :: (a -> a) -> Word -> a -> Patricia a -> Patricia a
insertWith' f !w b = go
where
go t =
case t of
Bin p l r
| beyond p w -> join w (b `seq` Tip w b) p t
| w < p -> Bin p (go l) r
| otherwise -> Bin p l (go r)
Tip k a
| k == w -> Tip k $! f a
| otherwise -> join w (b `seq` Tip w b) k t
Nil -> Tip w b
-- | \(\mathcal{O}(\min(n,W))\).
-- Apply a function to a value in the tree at the given key.
adjust :: (a -> a) -> Word -> Patricia a -> Patricia a
adjust f !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> t
| w < p -> Bin p (go l) r
| otherwise -> Bin p l (go r)
Tip k a
| k == w -> Tip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Apply a function to a value in the tree at the given key.
--
-- New value is evaluated to WHNF.
adjust' :: (a -> a) -> Word -> Patricia a -> Patricia a
adjust' f !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> t
| w < p -> Bin p (go l) r
| otherwise -> Bin p l (go r)
Tip k a
| k == w -> Tip k $! f a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete a value in the tree at the given key.
delete :: Word -> Patricia a -> Patricia a
delete !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> t
| w < p -> rebinL p (go l) r
| otherwise -> rebinR p l (go r)
Tip k _
| k == w -> Nil
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update or delete a value in the tree at the given key.
--
-- The 'Maybe' is evaluated to WHNF.
update :: (a -> Maybe a) -> Word -> Patricia a -> Patricia a
update f !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> t
| w < p -> rebinL p (go l) r
| otherwise -> rebinR p l (go r)
Tip k a
| k == w -> retip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Insert, update or delete a value in the tree at the given key.
--
-- The resulting 'Maybe' is evaluated to WHNF.
alter :: (Maybe a -> Maybe a) -> Word -> Patricia a -> Patricia a
alter f !w = go
where
go t =
case t of
Bin p l r
| beyond p w -> case f Nothing of
Just b -> join p t w (Tip w b)
Nothing -> t
| w < p -> rebinL p (go l) r
| otherwise -> rebinR p l (go r)
Tip k a
| k == w -> case f (Just a) of
Just b -> Tip k b
Nothing -> Nil
| otherwise -> case f Nothing of
Just b -> join k t w (Tip w b)
Nothing -> t
Nil -> case f Nothing of
Just b -> Tip w b
Nothing -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at a largest key smaller than or equal to the given key.
lookupL :: Word -> Patricia a -> Maybe (Lookup a)
lookupL !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then go l
else Nothing
else Just $! if w <= upper p
then case go r of
Just x -> x
Nothing -> unsafeLookupMaxWithKey l
else unsafeLookupMaxWithKey r
Tip k a
| k <= w -> Just $! Lookup k a
| otherwise -> Nothing
Nil -> Nothing
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at a smallest key greater than or equal to the given key.
lookupR :: Word -> Patricia a -> Maybe (Lookup a)
lookupR !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then Just $! if w >= lower p
then case go l of
Just x -> x
Nothing -> unsafeLookupMinWithKey r
else unsafeLookupMinWithKey l
else if w <= upper p
then go r
else Nothing
Tip k a
| k >= w -> Just $! Lookup k a
| otherwise -> Nothing
Nil -> Nothing
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Apply a function to every value for which the key is smaller than
-- or equal to the given one.
adjustL :: (a -> a) -> Word -> Patricia a -> Patricia a
adjustL f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then Bin p (go l) r
else t
else Bin p (Data.Patricia.Word.Strict.Internal.map f l) $
if w <= upper p
then go r
else Data.Patricia.Word.Strict.Internal.map f r
Tip k a
| k <= w -> Tip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Apply a function to every value for which the key is smaller than
-- or equal to the given one.
--
-- New value is evaluated to WHNF.
adjustL' :: (a -> a) -> Word -> Patricia a -> Patricia a
adjustL' f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then Bin p (go l) r
else t
else Bin p (map' f l) $
if w <= upper p
then go r
else map' f r
Tip k a
| k <= w -> Tip k $! f a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Apply a function to every value for which the key is smaller than
-- or equal to the given one.
adjustLWithKey :: (Word -> a -> a) -> Word -> Patricia a -> Patricia a
adjustLWithKey f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then Bin p (go l) r
else t
else Bin p (mapWithKey f l) $
if w <= upper p
then go r
else mapWithKey f r
Tip k a
| k <= w -> Tip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Apply a function to every value for which the key is smaller than
-- or equal to the given one.
--
-- New value is evaluated to WHNF.
adjustLWithKey' :: (Word -> a -> a) -> Word -> Patricia a -> Patricia a
adjustLWithKey' f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then Bin p (go l) r
else t
else Bin p (mapWithKey' f l) $
if w <= upper p
then go r
else mapWithKey' f r
Tip k a
| k <= w -> Tip k $! f k a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete values for which keys are smaller than or equal to the given one.
deleteL :: Word -> Patricia a -> Patricia a
deleteL !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then rebinL p (go l) r
else t
else if w <= upper p
then go r
else Nil
Tip k _
| k <= w -> Nil
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Update every value for which the key is smaller than or equal to the given one.
--
-- The 'Maybe' is evaluated to WHNF.
updateL :: (a -> Maybe a) -> Word -> Patricia a -> Patricia a
updateL f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then rebinL p (go l) r
else t
else rebin p (mapMaybe f l) $
if w <= upper p
then go r
else mapMaybe f r
Tip k a
| k <= w -> retip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_L)\).
-- Update every value for which the key is smaller than or equal to the given one.
--
-- The 'Maybe' is evaluated to WHNF.
updateLWithKey :: (Word -> a -> Maybe a) -> Word -> Patricia a -> Patricia a
updateLWithKey f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then rebinL p (go l) r
else t
else rebin p (mapMaybeWithKey f l) $
if w <= upper p
then go r
else mapMaybeWithKey f r
Tip k a
| k <= w -> retip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Take values for which keys are smaller than or equal to the given one.
takeL :: Word -> Patricia a -> Patricia a
takeL !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then go l
else Nil
else if w <= upper p
then rebinR p l (go r)
else t
Tip k _
| k <= w -> t
| otherwise -> Nil
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Apply a function to every value for which the key is greater than
-- or equal to the given one.
adjustR :: (a -> a) -> Word -> Patricia a -> Patricia a
adjustR f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else Data.Patricia.Word.Strict.Internal.map f l
in Bin p l' (Data.Patricia.Word.Strict.Internal.map f r)
else if w <= upper p
then Bin p l (go r)
else t
Tip k a
| k >= w -> Tip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Apply a function to every value for which the key is greater than
-- or equal to the given one.
--
-- New value is evaluated to WHNF.
adjustR' :: (a -> a) -> Word -> Patricia a -> Patricia a
adjustR' f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else map' f l
in Bin p l' (map' f r)
else if w <= upper p
then Bin p l (go r)
else t
Tip k a
| k >= w -> Tip k $! f a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Apply a function to every value for which the key is greater than
-- or equal to the given one.
adjustRWithKey :: (Word -> a -> a) -> Word -> Patricia a -> Patricia a
adjustRWithKey f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else mapWithKey f l
in Bin p l' (mapWithKey f r)
else if w <= upper p
then Bin p l (go r)
else t
Tip k a
| k >= w -> Tip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Apply a function to every value for which the key is greater than
-- or equal to the given one.
--
-- New value is evaluated to WHNF.
adjustRWithKey' :: (Word -> a -> a) -> Word -> Patricia a -> Patricia a
adjustRWithKey' f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else mapWithKey' f l
in Bin p l' (mapWithKey' f r)
else if w <= upper p
then Bin p l (go r)
else t
Tip k a
| k >= w -> Tip k $! f k a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete values for which keys are greater than or equal to the given one.
deleteR :: Word -> Patricia a -> Patricia a
deleteR !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then go l
else Nil
else if w <= upper p
then rebinR p l (go r)
else t
Tip k _
| k >= w -> Nil
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Update every value for which the key is greater than or equal to the given one.
--
-- The 'Maybe' is evaluated to WHNF.
updateR :: (a -> Maybe a) -> Word -> Patricia a -> Patricia a
updateR f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else mapMaybe f l
in rebin p l' (mapMaybe f r)
else if w <= upper p
then rebinR p l (go r)
else t
Tip k a
| k >= w -> retip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_R)\).
-- Update every value for which the key is greater than or equal to the given one.
--
-- The 'Maybe' is evaluated to WHNF.
updateRWithKey :: (Word -> a -> Maybe a) -> Word -> Patricia a -> Patricia a
updateRWithKey f !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then let l' = if w >= lower p
then go l
else mapMaybeWithKey f l
in rebin p l' (mapMaybeWithKey f r)
else if w <= upper p
then rebinR p l (go r)
else t
Tip k a
| k >= w -> retip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Take values for which keys are greater than or equal to the given one.
takeR :: Word -> Patricia a -> Patricia a
takeR !w = go
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then rebinL p (go l) r
else t
else if w <= upper p
then go r
else Nil
Tip k _
| k >= w -> t
| otherwise -> Nil
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
adjustRange :: (a -> a) -> Range -> Patricia a -> Patricia a
adjustRange f (UnsafeRange kL kR)
| kL == kR = adjust f kL
| otherwise = unsafeAdjustRange f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeAdjustRange
:: (a -> a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeAdjustRange f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> Bin p (adjustR f wL l) (adjustL f wR r)
LT | pM <= upper p -> Bin p l (go r)
| p >= lower pM -> if wL < p
then Bin p
(adjustR f wL l)
(Data.Patricia.Word.Strict.Internal.map f r)
else Bin p l (adjustR f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then Bin p
(Data.Patricia.Word.Strict.Internal.map f l)
(adjustL f wR r)
else Bin p (adjustL f wR l) r
| pM >= lower p -> Bin p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> Tip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- New value is evaluated to WHNF.
adjustRange' :: (a -> a) -> Range -> Patricia a -> Patricia a
adjustRange' f (UnsafeRange kL kR)
| kL == kR = adjust' f kL
| otherwise = unsafeAdjustRange' f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- New value is evaluated to WHNF.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeAdjustRange'
:: (a -> a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeAdjustRange' f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> Bin p (adjustR' f wL l) (adjustL' f wR r)
LT | pM <= upper p -> Bin p l (go r)
| p >= lower pM -> if wL < p
then Bin p (adjustR' f wL l) (map' f r)
else Bin p l (adjustR' f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then Bin p (map' f l) (adjustL' f wR r)
else Bin p (adjustL' f wR l) r
| pM >= lower p -> Bin p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> Tip k $! f a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
adjustRangeWithKey :: (Word -> a -> a) -> Range -> Patricia a -> Patricia a
adjustRangeWithKey f (UnsafeRange kL kR)
| kL == kR = adjust (f kL) kL
| otherwise = unsafeAdjustRangeWithKey f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeAdjustRangeWithKey
:: (Word -> a -> a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeAdjustRangeWithKey f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> Bin p (adjustRWithKey f wL l) (adjustLWithKey f wR r)
LT | pM <= upper p -> Bin p l (go r)
| p >= lower pM -> if wL < p
then Bin p (adjustRWithKey f wL l) (mapWithKey f r)
else Bin p l (adjustRWithKey f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then Bin p (mapWithKey f l) (adjustLWithKey f wR r)
else Bin p (adjustLWithKey f wR l) r
| pM >= lower p -> Bin p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> Tip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- New value is evaluated to WHNF.
adjustRangeWithKey' :: (Word -> a -> a) -> Range -> Patricia a -> Patricia a
adjustRangeWithKey' f (UnsafeRange kL kR)
| kL == kR = adjust' (f kL) kL
| otherwise = unsafeAdjustRangeWithKey' f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Apply a function to every value for which the key is in the given range.
--
-- New value is evaluated to WHNF.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeAdjustRangeWithKey'
:: (Word -> a -> a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeAdjustRangeWithKey' f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> Bin p (adjustRWithKey' f wL l) (adjustLWithKey' f wR r)
LT | pM <= upper p -> Bin p l (go r)
| p >= lower pM -> if wL < p
then Bin p (adjustRWithKey' f wL l) (mapWithKey' f r)
else Bin p l (adjustRWithKey' f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then Bin p (mapWithKey' f l) (adjustLWithKey' f wR r)
else Bin p (adjustLWithKey' f wR l) r
| pM >= lower p -> Bin p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> Tip k $! f k a
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete values for which keys are in the given range.
deleteRange :: Range -> Patricia a -> Patricia a
deleteRange (UnsafeRange kL kR)
| kL == kR = delete kL
| otherwise = unsafeDeleteRange kL kR
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete values for which keys are in the given range.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeDeleteRange
:: Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeDeleteRange !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> rebin p (deleteR wL l) (deleteL wR r)
LT | pM <= upper p -> rebinR p l (go r)
| p >= lower pM -> if wL < p
then deleteR wL l
else rebinR p l (deleteR wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then deleteL wR r
else rebinL p (deleteL wR l) r
| pM >= lower p -> rebinL p (go l) r
| otherwise -> t
Tip k _
| k >= wL && k <= wR -> Nil
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Update every value for which the key is in the given range.
--
-- The 'Maybe' is evaluated to WHNF.
updateRange :: (a -> Maybe a) -> Range -> Patricia a -> Patricia a
updateRange f (UnsafeRange kL kR)
| kL == kR = update f kL
| otherwise = unsafeUpdateRange f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Update every value for which the key is in the given range.
--
-- The 'Maybe' is evaluated to WHNF.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeUpdateRange
:: (a -> Maybe a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeUpdateRange f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> rebin p (updateR f wL l) (updateL f wR r)
LT | pM <= upper p -> rebinR p l (go r)
| p >= lower pM -> if wL < p
then rebinL p (updateR f wL l) (mapMaybe f r)
else rebinR p l (updateR f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then rebinR p (mapMaybe f l) (updateL f wR r)
else rebinL p (updateL f wR l) r
| pM >= lower p -> rebinL p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> retip k (f a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Update every value for which the key is in the given range.
--
-- The 'Maybe' is evaluated to WHNF.
updateRangeWithKey :: (Word -> a -> Maybe a) -> Range -> Patricia a -> Patricia a
updateRangeWithKey f (UnsafeRange kL kR)
| kL == kR = update (f kL) kL
| otherwise = unsafeUpdateRangeWithKey f kL kR
-- | \(\mathcal{O}(\min(n,W) + n_I)\).
-- Update every value for which the key is in the given range.
--
-- The 'Maybe' is evaluated to WHNF.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeUpdateRangeWithKey
:: (Word -> a -> Maybe a)
-> Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeUpdateRangeWithKey f !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> rebin p (updateRWithKey f wL l) (updateLWithKey f wR r)
LT | pM <= upper p -> rebinR p l (go r)
| p >= lower pM -> if wL < p
then rebinL p (updateRWithKey f wL l)
(mapMaybeWithKey f r)
else rebinR p l (updateRWithKey f wL r)
| otherwise -> t
GT | p <= upper pM -> if wR >= p
then rebinR p (mapMaybeWithKey f l)
(updateLWithKey f wR r)
else rebinL p (updateLWithKey f wR l) r
| pM >= lower p -> rebinL p (go l) r
| otherwise -> t
Tip k a
| k >= wL && k <= wR -> retip k (f k a)
| otherwise -> t
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Take values for which keys are in the given range.
takeRange :: Range -> Patricia a -> Patricia a
takeRange (UnsafeRange kL kR)
| kL == kR = takeOne kL
| otherwise = unsafeTakeRange kL kR
-- | \(\mathcal{O}(\min(n,W))\).
-- Take values for which keys are in the given range.
--
-- \(k_R\) __must__ be greater than \(k_L\).
unsafeTakeRange
:: Word -- ^ \(k_L\)
-> Word -- ^ \(k_R\)
-> Patricia a
-> Patricia a
unsafeTakeRange !wL !wR = go
where
!mM = branchingBit wL wR
!pM = mask wL mM .|. mM
go t =
case t of
Bin p l r ->
case Prelude.compare p pM of
EQ -> rebin p (takeR wL l) (takeL wR r)
LT | pM <= upper p -> go r
| p >= lower pM -> if wL < p
then rebinL p (takeR wL l) r
else takeR wL r
| otherwise -> Nil
GT | p <= upper pM -> if wR >= p
then rebinR p l (takeL wR r)
else takeL wR l
| pM >= lower p -> go l
| otherwise -> Nil
Tip k _
| k >= wL && k <= wR -> t
| otherwise -> Nil
Nil -> Nil
-- | Result of a tree split.
data Split l r = Split !(Patricia l) !(Patricia r)
deriving Show
-- | \(\mathcal{O}(\min(n,W))\).
-- Split the tree into two, such that
-- values with keys smaller than or equal to the given one are on the left,
-- and values with keys greater than the given one are on the right.
splitL :: Word -> Patricia a -> Split a a
splitL !w = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then let !(# !ll, !lr #) = go l
in (# ll, rebinL p lr r #)
else (# Nil, t #)
else if w <= upper p
then let !(# !rl, !rr #) = go r
in (# rebinR p l rl, rr #)
else (# t, Nil #)
Tip k _
| w >= k -> (# t, Nil #)
| otherwise -> (# Nil, t #)
Nil -> (# Nil, Nil #)
-- | \(\mathcal{O}(\min(n,W))\).
-- Split the tree into two, such that
-- values with keys smaller than the given one are on the left,
-- and values with keys greater than or equal to the given one are on the right.
splitR :: Word -> Patricia a -> Split a a
splitR !w = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then let !(# !ll, !lr #) = go l
in (# ll, rebinL p lr r #)
else (# Nil, t #)
else if w <= upper p
then let !(# !rl, !rr #) = go r
in (# rebinR p l rl, rr #)
else (# t, Nil #)
Tip k _
| w > k -> (# t, Nil #)
| otherwise -> (# Nil, t #)
Nil -> (# Nil, Nil #)
-- | Result of a tree split with a lookup.
data SplitLookup l x r = SplitLookup !(Patricia l) !(Maybe x) !(Patricia r)
deriving Show
-- | \(\mathcal{O}(\min(n,W))\).
-- Split the tree into two, such that
-- values with keys smaller than the given one are on the left,
-- values with keys greater than the given one are on the right,
-- and the value at the given key is returned separately.
splitLookup :: Word -> Patricia a -> SplitLookup a a a
splitLookup !w = \t ->
case go t of
(# !l, !mx, !r #) -> SplitLookup l mx r
where
go t =
case t of
Bin p l r ->
if w < p
then if w >= lower p
then let !(# !ll, !mx, !lr #) = go l
in (# ll, mx, rebinL p lr r #)
else (# Nil, Nothing, t #)
else if w <= upper p
then let !(# !rl, !mx, !rr #) = go r
in (# rebinR p l rl, mx, rr #)
else (# t, Nothing, Nil #)
Tip k a ->
case w `Prelude.compare` k of
EQ -> (# Nil, Just a , Nil #)
GT -> (# t , Nothing, Nil #)
LT -> (# Nil, Nothing, t #)
Nil -> (# Nil, Nothing, Nil #)
-- | \(\mathcal{O}(n)\).
-- Filter values that satisfy the value predicate.
filter :: (a -> Bool) -> Patricia a -> Patricia a
filter f = go
where
go t =
case t of
Bin p l r -> rebin p (go l) (go r)
Tip _ a
| f a -> t
| otherwise -> Nil
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Filter values that satisfy the value predicate.
filterWithKey :: (Word -> a -> Bool) -> Patricia a -> Patricia a
filterWithKey f = go
where
go t =
case t of
Bin p l r -> rebin p (go l) (go r)
Tip k a
| f k a -> t
| otherwise -> Nil
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree and create one out of 'Just' values.
--
-- The 'Maybe' is evaluated to WHNF.
mapMaybe :: (a -> Maybe b) -> Patricia a -> Patricia b
mapMaybe f = go
where
go t =
case t of
Bin p l r -> rebin p (go l) (go r)
Tip k a ->
case f a of
Just b -> Tip k b
Nothing -> Nil
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree
-- and create a tree out of 'Just' results.
--
-- The 'Maybe' is evaluated to WHNF.
mapMaybeWithKey :: (Word -> a -> Maybe b) -> Patricia a -> Patricia b
mapMaybeWithKey f = go
where
go t =
case t of
Bin p l r -> rebin p (go l) (go r)
Tip k a ->
case f k a of
Just b -> Tip k b
Nothing -> Nil
Nil -> Nil
-- | \(\mathcal{O}(n)\).
-- Split the tree into two, such that values that satisfy the predicate
-- are on the left and values that do not are on the right.
partition :: (a -> Bool) -> Patricia a -> Split a a
partition f = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
let !(# !ll, !lr #) = go l
!(# !rl, !rr #) = go r
in (# rebin p ll rl, rebin p lr rr #)
Tip _ a
| f a -> (# t, Nil #)
| otherwise -> (# Nil, t #)
Nil -> (# Nil, Nil #)
-- | \(\mathcal{O}(n)\).
-- Split the tree into two, such that values that satisfy the predicate
-- are on the left and values that do not are on the right.
partitionWithKey :: (Word -> a -> Bool) -> Patricia a -> Split a a
partitionWithKey f = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
let !(# !ll, !lr #) = go l
!(# !rl, !rr #) = go r
in (# rebin p ll rl, rebin p lr rr #)
Tip k a
| f k a -> (# t, Nil #)
| otherwise -> (# Nil, t #)
Nil -> (# Nil, Nil #)
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree and create two trees,
-- one out of 'Left' results and one out of 'Right' ones.
--
-- The 'Either' is evaluated to WHNF.
mapEither :: (a -> Either b c) -> Patricia a -> Split b c
mapEither f = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
let !(# !ll, !lr #) = go l
!(# !rl, !rr #) = go r
in (# rebin p ll rl, rebin p lr rr #)
Tip k a ->
case f a of
Left b -> (# Tip k b, Nil #)
Right c -> (# Nil, Tip k c #)
Nil -> (# Nil, Nil #)
-- | \(\mathcal{O}(n)\).
-- Apply a function to every value in the tree and create two trees,
-- one out of 'Left' results and one out of 'Right' ones.
--
-- The 'Either' is evaluated to WHNF.
mapEitherWithKey :: (Word -> a -> Either b c) -> Patricia a -> Split b c
mapEitherWithKey f = \t ->
case go t of
(# !l, !r #) -> Split l r
where
go t =
case t of
Bin p l r ->
let !(# !ll, !lr #) = go l
!(# !rl, !rr #) = go r
in (# rebin p ll rl, rebin p lr rr #)
Tip k a ->
case f k a of
Left b -> (# Tip k b, Nil #)
Right c -> (# Nil, Tip k c #)
Nil -> (# Nil, Nil #)
moduleLoc :: String
moduleLoc = "Patricia.Word.Strict"
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the leftmost key in the tree.
lookupMin :: Patricia a -> Maybe a
lookupMin Nil = Nothing
lookupMin t = let !(# a #) = unsafeLookupMin t
in Just a
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the leftmost key in the tree.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeLookupMin :: Patricia a -> (# a #)
unsafeLookupMin t =
case t of
Bin _ l _ -> unsafeLookupMin l
Tip _ a -> (# a #)
Nil -> throw $ MalformedTree moduleLoc "lookupMin"
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the leftmost key in the tree.
lookupMinWithKey :: Patricia a -> Maybe (Lookup a)
lookupMinWithKey Nil = Nothing
lookupMinWithKey t = Just $! unsafeLookupMinWithKey t
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the leftmost key in the tree.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeLookupMinWithKey :: Patricia a -> Lookup a
unsafeLookupMinWithKey t =
case t of
Bin _ l _ -> unsafeLookupMinWithKey l
Tip k a -> Lookup k a
Nil -> throw $ MalformedTree moduleLoc "lookupMinWithKey"
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the rightmost key in the tree.
lookupMax :: Patricia a -> Maybe a
lookupMax Nil = Nothing
lookupMax t = let !(# a #) = unsafeLookupMax t
in Just a
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the rightmost key in the tree.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeLookupMax :: Patricia a -> (# a #)
unsafeLookupMax t =
case t of
Bin _ _ r -> unsafeLookupMax r
Tip _ a -> (# a #)
Nil -> throw $ MalformedTree moduleLoc "lookupMax"
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the rightmost key in the tree.
lookupMaxWithKey :: Patricia a -> Maybe (Lookup a)
lookupMaxWithKey Nil = Nothing
lookupMaxWithKey t = Just $! unsafeLookupMaxWithKey t
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up a value at the rightmost key in the tree.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeLookupMaxWithKey :: Patricia a -> Lookup a
unsafeLookupMaxWithKey t =
case t of
Bin _ _ r -> unsafeLookupMaxWithKey r
Tip k a -> Lookup k a
Nil -> throw $ MalformedTree moduleLoc "lookupMaxWithKey"
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete a value at the leftmost key in the tree.
deleteMin :: Patricia a -> Patricia a
deleteMin = go
where
go t =
case t of
Bin p l r -> rebinL p (go l) r
_ -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Delete a value at the rightmost key in the tree.
deleteMax :: Patricia a -> Patricia a
deleteMax = go
where
go t =
case t of
Bin p l r -> rebinR p l (go r)
_ -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the leftmost key in the tree.
adjustMin :: (a -> a) -> Patricia a -> Patricia a
adjustMin f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) r
Tip k a -> Tip k (f a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the leftmost key in the tree.
--
-- New value is evaluated to WHNF.
adjustMin' :: (a -> a) -> Patricia a -> Patricia a
adjustMin' f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) r
Tip k a -> Tip k $! f a
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the leftmost key in the tree.
adjustMinWithKey :: (Word -> a -> a) -> Patricia a -> Patricia a
adjustMinWithKey f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) r
Tip k a -> Tip k (f k a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the leftmost key in the tree.
--
-- New value is evaluated to WHNF.
adjustMinWithKey' :: (Word -> a -> a) -> Patricia a -> Patricia a
adjustMinWithKey' f = go
where
go t =
case t of
Bin p l r -> Bin p (go l) r
Tip k a -> Tip k $! f k a
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the rightmost key in the tree.
adjustMax :: (a -> a) -> Patricia a -> Patricia a
adjustMax f = go
where
go t =
case t of
Bin p l r -> Bin p l (go r)
Tip k a -> Tip k (f a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the rightmost key in the tree.
--
-- New value is evaluated to WHNF.
adjustMax' :: (a -> a) -> Patricia a -> Patricia a
adjustMax' f = go
where
go t =
case t of
Bin p l r -> Bin p l (go r)
Tip k a -> Tip k $! f a
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the rightmost key in the tree.
adjustMaxWithKey :: (Word -> a -> a) -> Patricia a -> Patricia a
adjustMaxWithKey f = go
where
go t =
case t of
Bin p l r -> Bin p l (go r)
Tip k a -> Tip k (f k a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update a value at the rightmost key in the tree.
--
-- New value is evaluated to WHNF.
adjustMaxWithKey' :: (Word -> a -> a) -> Patricia a -> Patricia a
adjustMaxWithKey' f = go
where
go t =
case t of
Bin p l r -> Bin p l (go r)
Tip k a -> Tip k $! f k a
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update or delete a value at the leftmost key in the tree.
--
-- The 'Maybe' is evaluated to WHNF.
updateMin :: (a -> Maybe a) -> Patricia a -> Patricia a
updateMin f = go
where
go t =
case t of
Bin p l r -> rebinL p (go l) r
Tip k a -> retip k (f a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update or delete a value at the leftmost key in the tree.
--
-- The 'Maybe' is evaluated to WHNF.
updateMinWithKey :: (Word -> a -> Maybe a) -> Patricia a -> Patricia a
updateMinWithKey f = go
where
go t =
case t of
Bin p l r -> rebinL p (go l) r
Tip k a -> retip k (f k a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update or delete a value at the rightmost key in the tree.
--
-- The 'Maybe' is evaluated to WHNF.
updateMax :: (a -> Maybe a) -> Patricia a -> Patricia a
updateMax f = go
where
go t =
case t of
Bin p l r -> rebinR p l (go r)
Tip k a -> retip k (f a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Update or delete a value at the rightmost key in the tree.
--
-- The 'Maybe' is evaluated to WHNF.
updateMaxWithKey :: (Word -> a -> Maybe a) -> Patricia a -> Patricia a
updateMaxWithKey f = go
where
go t =
case t of
Bin p l r -> rebinR p l (go r)
Tip k a -> retip k (f k a)
Nil -> Nil
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the leftmost value and return it alongside the tree without it.
minView :: Patricia a -> Maybe (ViewL a)
minView Nil = Nothing
minView t = Just $! unsafeMinView t
-- | The leftmost value with its key and the rest of the tree.
data ViewL a = ViewL {-# UNPACK #-} !(Lookup a) !(Patricia a)
deriving Show
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the leftmost value and return it alongside the tree without it.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeMinView :: Patricia a -> ViewL a
unsafeMinView t =
case t of
Bin p l r ->
let !(ViewL a l0) = unsafeMinView l
in ViewL a (rebinL p l0 r)
Tip k a -> ViewL (Lookup k a) Nil
Nil -> throw $ MalformedTree moduleLoc "minView"
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the rightmost value and return it alongside the tree without it.
maxView :: Patricia a -> Maybe (ViewR a)
maxView Nil = Nothing
maxView t = Just $! unsafeMaxView t
-- | The rightmost value with its key and the rest of the tree.
data ViewR a = ViewR !(Patricia a) {-# UNPACK #-} !(Lookup a)
deriving Show
-- | \(\mathcal{O}(\min(n,W))\).
-- Look up the rightmost value and return it alongside the tree without it.
--
-- Throws t'MalformedTree' if the tree is empty.
unsafeMaxView :: Patricia a -> ViewR a
unsafeMaxView t =
case t of
Bin p l r ->
let !(ViewR r0 a) = unsafeMaxView r
in ViewR (rebinR p l r0) a
Tip k a -> ViewR Nil (Lookup k a)
Nil -> throw $ MalformedTree moduleLoc "maxView"