{-# LANGUAGE GADTs, RankNTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE CPP #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 708
{-# LANGUAGE PolyKinds #-}
#endif
module Data.Dependent.Map
( DMap
, DSum(..), Some(..)
, GCompare(..), GOrdering(..)
, (!), (\\)
, null
, size
, member
, notMember
, lookup
, findWithDefault
, empty
, singleton
, insert
, insertWith
, insertWith'
, insertWithKey
, insertWithKey'
, insertLookupWithKey
, insertLookupWithKey'
, delete
, adjust
, adjustWithKey
, adjustWithKey'
, update
, updateWithKey
, updateLookupWithKey
, alter
, union
, unionWithKey
, unions
, unionsWithKey
, difference
, differenceWithKey
, intersection
, intersectionWithKey
, map
, mapWithKey
, traverseWithKey
, mapAccumLWithKey
, mapAccumRWithKey
, mapKeysWith
, mapKeysMonotonic
, foldWithKey
, foldrWithKey
, foldlWithKey
, keys
, assocs
, toList
, fromList
, fromListWithKey
, toAscList
, toDescList
, fromAscList
, fromAscListWithKey
, fromDistinctAscList
, filter
, filterWithKey
, partitionWithKey
, mapMaybeWithKey
, mapEitherWithKey
, split
, splitLookup
, isSubmapOf, isSubmapOfBy
, isProperSubmapOf, isProperSubmapOfBy
, lookupIndex
, findIndex
, elemAt
, updateAt
, deleteAt
, findMin
, findMax
, lookupMin
, lookupMax
, deleteMin
, deleteMax
, deleteFindMin
, deleteFindMax
, updateMinWithKey
, updateMaxWithKey
, minViewWithKey
, maxViewWithKey
, showTree
, showTreeWith
, valid
) where
import Prelude hiding (null, lookup, map)
import qualified Prelude
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative (Applicative(..), (<$>))
#endif
import Data.Dependent.Map.Internal
#if !MIN_VERSION_base(4,7,0)
import Data.Dependent.Map.Typeable ()
#endif
import Data.Dependent.Sum
import Data.GADT.Compare
import Data.Maybe (isJust)
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
import Data.Semigroup
import Data.Some
import Text.Read
import Data.Dependent.Map.PtrEquality
instance (GCompare k) => Monoid (DMap k f) where
mempty = empty
mappend = union
mconcat = unions
instance (GCompare k) => Semigroup (DMap k f) where
(<>) = mappend
infixl 9 !,\\
(!) :: GCompare k => DMap k f -> k v -> f v
(!) m k = find k m
(\\) :: GCompare k => DMap k f -> DMap k f -> DMap k f
m1 \\ m2 = difference m1 m2
member :: GCompare k => k a -> DMap k f -> Bool
member k = isJust . lookup k
notMember :: GCompare k => k v -> DMap k f -> Bool
notMember k m = not (member k m)
find :: GCompare k => k v -> DMap k f -> f v
find k m = case lookup k m of
Nothing -> error "DMap.find: element not in the map"
Just v -> v
findWithDefault :: GCompare k => f v -> k v -> DMap k f -> f v
findWithDefault def k m = case lookup k m of
Nothing -> def
Just v -> v
insert :: forall k f v. GCompare k => k v -> f v -> DMap k f -> DMap k f
insert kx x = kx `seq` go
where
go :: DMap k f -> DMap k f
go Tip = singleton kx x
go t@(Bin sz ky y l r) = case gcompare kx ky of
GLT -> let !l' = go l
in if l' `ptrEq` l
then t
else balance ky y l' r
GGT -> let !r' = go r
in if r' `ptrEq` r
then t
else balance ky y l r'
GEQ
| kx `ptrEq` ky && x `ptrEq` y -> t
| otherwise -> Bin sz kx x l r
insertR :: forall k f v. GCompare k => k v -> f v -> DMap k f -> DMap k f
insertR kx x = kx `seq` go
where
go :: DMap k f -> DMap k f
go Tip = singleton kx x
go t@(Bin sz ky y l r) = case gcompare kx ky of
GLT -> let !l' = go l
in if l' `ptrEq` l
then t
else balance ky y l' r
GGT -> let !r' = go r
in if r' `ptrEq` r
then t
else balance ky y l r'
GEQ -> t
insertWith :: GCompare k => (f v -> f v -> f v) -> k v -> f v -> DMap k f -> DMap k f
insertWith f = insertWithKey (\_ x' y' -> f x' y')
insertWith' :: GCompare k => (f v -> f v -> f v) -> k v -> f v -> DMap k f -> DMap k f
insertWith' f = insertWithKey' (\_ x' y' -> f x' y')
insertWithKey :: forall k f v. GCompare k => (k v -> f v -> f v -> f v) -> k v -> f v -> DMap k f -> DMap k f
insertWithKey f kx x = kx `seq` go
where
go :: DMap k f -> DMap k f
go Tip = singleton kx x
go (Bin sy ky y l r) =
case gcompare kx ky of
GLT -> balance ky y (go l) r
GGT -> balance ky y l (go r)
GEQ -> Bin sy kx (f kx x y) l r
insertWithKey' :: forall k f v. GCompare k => (k v -> f v -> f v -> f v) -> k v -> f v -> DMap k f -> DMap k f
insertWithKey' f kx x = kx `seq` go
where
go :: DMap k f -> DMap k f
go Tip = singleton kx $! x
go (Bin sy ky y l r) =
case gcompare kx ky of
GLT -> balance ky y (go l) r
GGT -> balance ky y l (go r)
GEQ -> let x' = f kx x y in seq x' (Bin sy kx x' l r)
insertLookupWithKey :: forall k f v. GCompare k => (k v -> f v -> f v -> f v) -> k v -> f v -> DMap k f
-> (Maybe (f v), DMap k f)
insertLookupWithKey f kx x = kx `seq` go
where
go :: DMap k f -> (Maybe (f v), DMap k f)
go Tip = (Nothing, singleton kx x)
go (Bin sy ky y l r) =
case gcompare kx ky of
GLT -> let (found, l') = go l
in (found, balance ky y l' r)
GGT -> let (found, r') = go r
in (found, balance ky y l r')
GEQ -> (Just y, Bin sy kx (f kx x y) l r)
insertLookupWithKey' :: forall k f v. GCompare k => (k v -> f v -> f v -> f v) -> k v -> f v -> DMap k f
-> (Maybe (f v), DMap k f)
insertLookupWithKey' f kx x = kx `seq` go
where
go :: DMap k f -> (Maybe (f v), DMap k f)
go Tip = x `seq` (Nothing, singleton kx x)
go (Bin sy ky y l r) =
case gcompare kx ky of
GLT -> let (found, l') = go l
in (found, balance ky y l' r)
GGT -> let (found, r') = go r
in (found, balance ky y l r')
GEQ -> let x' = f kx x y in x' `seq` (Just y, Bin sy kx x' l r)
delete :: forall k f v. GCompare k => k v -> DMap k f -> DMap k f
delete k = k `seq` go
where
go :: DMap k f -> DMap k f
go Tip = Tip
go (Bin _ kx x l r) =
case gcompare k kx of
GLT -> balance kx x (go l) r
GGT -> balance kx x l (go r)
GEQ -> glue l r
adjust :: GCompare k => (f v -> f v) -> k v -> DMap k f -> DMap k f
adjust f = adjustWithKey (\_ x -> f x)
adjustWithKey :: GCompare k => (k v -> f v -> f v) -> k v -> DMap k f -> DMap k f
adjustWithKey f0 !k0 = go f0 k0
where
go :: GCompare k => (k v -> f v -> f v) -> k v -> DMap k f -> DMap k f
go _f _k Tip = Tip
go f k (Bin sx kx x l r) =
case gcompare k kx of
GLT -> Bin sx kx x (go f k l) r
GGT -> Bin sx kx x l (go f k r)
GEQ -> Bin sx kx (f kx x) l r
adjustWithKey' :: GCompare k => (k v -> f v -> f v) -> k v -> DMap k f -> DMap k f
adjustWithKey' f0 !k0 = go f0 k0
where
go :: GCompare k => (k v -> f v -> f v) -> k v -> DMap k f -> DMap k f
go _f _k Tip = Tip
go f k (Bin sx kx x l r) =
case gcompare k kx of
GLT -> Bin sx kx x (go f k l) r
GGT -> Bin sx kx x l (go f k r)
GEQ -> let !x' = f kx x in Bin sx kx x' l r
update :: GCompare k => (f v -> Maybe (f v)) -> k v -> DMap k f -> DMap k f
update f = updateWithKey (\_ x -> f x)
updateWithKey :: forall k f v. GCompare k => (k v -> f v -> Maybe (f v)) -> k v -> DMap k f -> DMap k f
updateWithKey f k = k `seq` go
where
go :: DMap k f -> DMap k f
go Tip = Tip
go (Bin sx kx x l r) =
case gcompare k kx of
GLT -> balance kx x (go l) r
GGT -> balance kx x l (go r)
GEQ -> case f kx x of
Just x' -> Bin sx kx x' l r
Nothing -> glue l r
updateLookupWithKey :: forall k f v. GCompare k => (k v -> f v -> Maybe (f v)) -> k v -> DMap k f -> (Maybe (f v), DMap k f)
updateLookupWithKey f k = k `seq` go
where
go :: DMap k f -> (Maybe (f v), DMap k f)
go Tip = (Nothing,Tip)
go (Bin sx kx x l r) =
case gcompare k kx of
GLT -> let (found,l') = go l in (found,balance kx x l' r)
GGT -> let (found,r') = go r in (found,balance kx x l r')
GEQ -> case f kx x of
Just x' -> (Just x',Bin sx kx x' l r)
Nothing -> (Just x,glue l r)
alter :: forall k f v. GCompare k => (Maybe (f v) -> Maybe (f v)) -> k v -> DMap k f -> DMap k f
alter f k = k `seq` go
where
go :: DMap k f -> DMap k f
go Tip = case f Nothing of
Nothing -> Tip
Just x -> singleton k x
go (Bin sx kx x l r) = case gcompare k kx of
GLT -> balance kx x (go l) r
GGT -> balance kx x l (go r)
GEQ -> case f (Just x) of
Just x' -> Bin sx kx x' l r
Nothing -> glue l r
findIndex :: GCompare k => k v -> DMap k f -> Int
findIndex k t
= case lookupIndex k t of
Nothing -> error "Map.findIndex: element is not in the map"
Just idx -> idx
lookupIndex :: forall k f v. GCompare k => k v -> DMap k f -> Maybe Int
lookupIndex k = k `seq` go 0
where
go :: Int -> DMap k f -> Maybe Int
go !idx Tip = idx `seq` Nothing
go !idx (Bin _ kx _ l r)
= case gcompare k kx of
GLT -> go idx l
GGT -> go (idx + size l + 1) r
GEQ -> Just (idx + size l)
elemAt :: Int -> DMap k f -> DSum k f
elemAt _ Tip = error "Map.elemAt: index out of range"
elemAt i (Bin _ kx x l r)
= case compare i sizeL of
LT -> elemAt i l
GT -> elemAt (i-sizeL-1) r
EQ -> kx :=> x
where
sizeL = size l
updateAt :: (forall v. k v -> f v -> Maybe (f v)) -> Int -> DMap k f -> DMap k f
updateAt f i0 t = i0 `seq` go i0 t
where
go _ Tip = Tip
go i (Bin sx kx x l r) = case compare i sizeL of
LT -> balance kx x (go i l) r
GT -> balance kx x l (go (i-sizeL-1) r)
EQ -> case f kx x of
Just x' -> Bin sx kx x' l r
Nothing -> glue l r
where
sizeL = size l
deleteAt :: Int -> DMap k f -> DMap k f
deleteAt i m
= updateAt (\_ _ -> Nothing) i m
findMin :: DMap k f -> DSum k f
findMin m = case lookupMin m of
Just x -> x
Nothing -> error "Map.findMin: empty map has no minimal element"
lookupMin :: DMap k f -> Maybe (DSum k f)
lookupMin m = case m of
Tip -> Nothing
Bin _ kx x l _ -> Just $! go kx x l
where
go :: k v -> f v -> DMap k f -> DSum k f
go kx x Tip = kx :=> x
go _ _ (Bin _ kx x l _) = go kx x l
findMax :: DMap k f -> DSum k f
findMax m = case lookupMax m of
Just x -> x
Nothing -> error "Map.findMax: empty map has no maximal element"
lookupMax :: DMap k f -> Maybe (DSum k f)
lookupMax m = case m of
Tip -> Nothing
Bin _ kx x _ r -> Just $! go kx x r
where
go :: k v -> f v -> DMap k f -> DSum k f
go kx x Tip = kx :=> x
go _ _ (Bin _ kx x _ r) = go kx x r
deleteMin :: DMap k f -> DMap k f
deleteMin (Bin _ _ _ Tip r) = r
deleteMin (Bin _ kx x l r) = balance kx x (deleteMin l) r
deleteMin Tip = Tip
deleteMax :: DMap k f -> DMap k f
deleteMax (Bin _ _ _ l Tip) = l
deleteMax (Bin _ kx x l r) = balance kx x l (deleteMax r)
deleteMax Tip = Tip
updateMinWithKey :: (forall v. k v -> f v -> Maybe (f v)) -> DMap k f -> DMap k f
updateMinWithKey f = go
where
go (Bin sx kx x Tip r) = case f kx x of
Nothing -> r
Just x' -> Bin sx kx x' Tip r
go (Bin _ kx x l r) = balance kx x (go l) r
go Tip = Tip
updateMaxWithKey :: (forall v. k v -> f v -> Maybe (f v)) -> DMap k f -> DMap k f
updateMaxWithKey f = go
where
go (Bin sx kx x l Tip) = case f kx x of
Nothing -> l
Just x' -> Bin sx kx x' l Tip
go (Bin _ kx x l r) = balance kx x l (go r)
go Tip = Tip
unions :: GCompare k => [DMap k f] -> DMap k f
unions ts
= foldlStrict union empty ts
unionsWithKey :: GCompare k => (forall v. k v -> f v -> f v -> f v) -> [DMap k f] -> DMap k f
unionsWithKey f ts
= foldlStrict (unionWithKey f) empty ts
union :: GCompare k => DMap k f -> DMap k f -> DMap k f
union t1 Tip = t1
union t1 (Bin _ kx x Tip Tip) = insertR kx x t1
union Tip t2 = t2
union (Bin _ kx x Tip Tip) t2 = insert kx x t2
union t1@(Bin _ k1 x1 l1 r1) t2 = case split k1 t2 of
(l2, r2)
| l1 `ptrEq` l1l2 && r1 `ptrEq` r1r2 -> t1
| otherwise -> combine k1 x1 l1l2 r1r2
where !l1l2 = l1 `union` l2
!r1r2 = r1 `union` r2
unionWithKey :: GCompare k => (forall v. k v -> f v -> f v -> f v) -> DMap k f -> DMap k f -> DMap k f
unionWithKey _ t1 Tip = t1
unionWithKey _ Tip t2 = t2
unionWithKey f (Bin _ k1 x1 l1 r1) t2 = case splitLookup k1 t2 of
(l2, mx2, r2) -> case mx2 of
Nothing -> combine k1 x1 l1l2 r1r2
Just x2 -> combine k1 (f k1 x1 x2) l1l2 r1r2
where !l1l2 = unionWithKey f l1 l2
!r1r2 = unionWithKey f r1 r2
difference :: GCompare k => DMap k f -> DMap k g -> DMap k f
difference Tip _ = Tip
difference t1 Tip = t1
difference t1 (Bin _ k2 _x2 l2 r2) = case split k2 t1 of
(l1, r1)
| size t1 == size l1l2 + size r1r2 -> t1
| otherwise -> merge l1l2 r1r2
where
!l1l2 = l1 `difference` l2
!r1r2 = r1 `difference` r2
differenceWithKey :: GCompare k => (forall v. k v -> f v -> g v -> Maybe (f v)) -> DMap k f -> DMap k g -> DMap k f
differenceWithKey _ Tip _ = Tip
differenceWithKey _ t1 Tip = t1
differenceWithKey f (Bin _ k1 x1 l1 r1) t2 = case splitLookup k1 t2 of
(l2, mx2, r2) -> case mx2 of
Nothing -> combine k1 x1 l1l2 r1r2
Just x2 -> case f k1 x1 x2 of
Nothing -> merge l1l2 r1r2
Just x1x2 -> combine k1 x1x2 l1l2 r1r2
where !l1l2 = differenceWithKey f l1 l2
!r1r2 = differenceWithKey f r1 r2
intersection :: GCompare k => DMap k f -> DMap k f -> DMap k f
intersection Tip _ = Tip
intersection _ Tip = Tip
intersection t1@(Bin s1 k1 x1 l1 r1) t2 =
let !(l2, found, r2) = splitMember k1 t2
!l1l2 = intersection l1 l2
!r1r2 = intersection r1 r2
in if found
then if l1l2 `ptrEq` l1 && r1r2 `ptrEq` r1
then t1
else combine k1 x1 l1l2 r1r2
else merge l1l2 r1r2
intersectionWithKey :: GCompare k => (forall v. k v -> f v -> g v -> h v) -> DMap k f -> DMap k g -> DMap k h
intersectionWithKey _ Tip _ = Tip
intersectionWithKey _ _ Tip = Tip
intersectionWithKey f (Bin s1 k1 x1 l1 r1) t2 =
let !(l2, found, r2) = splitLookup k1 t2
!l1l2 = intersectionWithKey f l1 l2
!r1r2 = intersectionWithKey f r1 r2
in case found of
Nothing -> merge l1l2 r1r2
Just x2 -> combine k1 (f k1 x1 x2) l1l2 r1r2
isSubmapOf :: (GCompare k, EqTag k f) => DMap k f -> DMap k f -> Bool
isSubmapOf m1 m2 = isSubmapOfBy eqTagged m1 m2
isSubmapOfBy :: GCompare k => (forall v. k v -> k v -> f v -> g v -> Bool) -> DMap k f -> DMap k g -> Bool
isSubmapOfBy f t1 t2
= (size t1 <= size t2) && (submap' f t1 t2)
submap' :: GCompare k => (forall v. k v -> k v -> f v -> g v -> Bool) -> DMap k f -> DMap k g -> Bool
submap' _ Tip _ = True
submap' _ _ Tip = False
submap' f (Bin _ kx x l r) t
= case found of
Nothing -> False
Just (ky, y) -> f kx ky x y && submap' f l lt && submap' f r gt
where
(lt,found,gt) = splitLookupWithKey kx t
isProperSubmapOf :: (GCompare k, EqTag k f) => DMap k f -> DMap k f -> Bool
isProperSubmapOf m1 m2
= isProperSubmapOfBy eqTagged m1 m2
isProperSubmapOfBy :: GCompare k => (forall v. k v -> k v -> f v -> g v -> Bool) -> DMap k f -> DMap k g -> Bool
isProperSubmapOfBy f t1 t2
= (size t1 < size t2) && (submap' f t1 t2)
filterWithKey :: GCompare k => (forall v. k v -> f v -> Bool) -> DMap k f -> DMap k f
filterWithKey p = go
where
go Tip = Tip
go t@(Bin _ kx x l r)
| p kx x = if l' `ptrEq` l && r' `ptrEq` r
then t
else combine kx x l' r'
| otherwise = merge l' r'
where !l' = go l
!r' = go r
partitionWithKey :: GCompare k => (forall v. k v -> f v -> Bool) -> DMap k f -> (DMap k f, DMap k f)
partitionWithKey p0 m0 = toPair (go p0 m0)
where
go :: GCompare k => (forall v. k v -> f v -> Bool) -> DMap k f -> (DMap k f :*: DMap k f)
go _ Tip = (Tip :*: Tip)
go p (Bin _ kx x l r)
| p kx x = (combine kx x l1 r1 :*: merge l2 r2)
| otherwise = (merge l1 r1 :*: combine kx x l2 r2)
where
(l1 :*: l2) = go p l
(r1 :*: r2) = go p r
mapMaybeWithKey :: GCompare k => (forall v. k v -> f v -> Maybe (g v)) -> DMap k f -> DMap k g
mapMaybeWithKey f = go
where
go Tip = Tip
go (Bin _ kx x l r) = case f kx x of
Just y -> combine kx y (go l) (go r)
Nothing -> merge (go l) (go r)
mapEitherWithKey :: GCompare k =>
(forall v. k v -> f v -> Either (g v) (h v)) -> DMap k f -> (DMap k g, DMap k h)
mapEitherWithKey f0 = toPair . go f0
where
go :: GCompare k
=> (forall v. k v -> f v -> Either (g v) (h v))
-> DMap k f -> (DMap k g :*: DMap k h)
go _ Tip = (Tip :*: Tip)
go f (Bin _ kx x l r) = case f kx x of
Left y -> (combine kx y l1 r1 :*: merge l2 r2)
Right z -> (merge l1 r1 :*: combine kx z l2 r2)
where
(l1,l2) = mapEitherWithKey f l
(r1,r2) = mapEitherWithKey f r
map :: (forall v. f v -> g v) -> DMap k f -> DMap k g
map f = go
where
go Tip = Tip
go (Bin sx kx x l r) = Bin sx kx (f x) (go l) (go r)
mapWithKey :: (forall v. k v -> f v -> g v) -> DMap k f -> DMap k g
mapWithKey f = go
where
go Tip = Tip
go (Bin sx kx x l r) = Bin sx kx (f kx x) (go l) (go r)
traverseWithKey :: Applicative t => (forall v. k v -> f v -> t (g v)) -> DMap k f -> t (DMap k g)
traverseWithKey f = go
where
go Tip = pure Tip
go (Bin 1 k v _ _) = (\v' -> Bin 1 k v' Tip Tip) <$> f k v
go (Bin s k v l r) = flip (Bin s k) <$> go l <*> f k v <*> go r
mapAccumLWithKey :: (forall v. a -> k v -> f v -> (a, g v)) -> a -> DMap k f -> (a, DMap k g)
mapAccumLWithKey f = go
where
go a Tip = (a,Tip)
go a (Bin sx kx x l r) =
let (a1,l') = go a l
(a2,x') = f a1 kx x
(a3,r') = go a2 r
in (a3,Bin sx kx x' l' r')
mapAccumRWithKey :: (forall v. a -> k v -> f v -> (a, g v)) -> a -> DMap k f -> (a, DMap k g)
mapAccumRWithKey f = go
where
go a Tip = (a,Tip)
go a (Bin sx kx x l r) =
let (a1,r') = go a r
(a2,x') = f a1 kx x
(a3,l') = go a2 l
in (a3,Bin sx kx x' l' r')
mapKeysWith :: GCompare k2 => (forall v. k2 v -> f v -> f v -> f v) -> (forall v. k1 v -> k2 v) -> DMap k1 f -> DMap k2 f
mapKeysWith c f = fromListWithKey c . Prelude.map fFirst . toList
where fFirst (x :=> y) = (f x :=> y)
mapKeysMonotonic :: (forall v. k1 v -> k2 v) -> DMap k1 f -> DMap k2 f
mapKeysMonotonic _ Tip = Tip
mapKeysMonotonic f (Bin sz k x l r) =
Bin sz (f k) x (mapKeysMonotonic f l) (mapKeysMonotonic f r)
foldWithKey :: (forall v. k v -> f v -> b -> b) -> b -> DMap k f -> b
foldWithKey = foldrWithKey
{-# DEPRECATED foldWithKey "Use foldrWithKey instead" #-}
foldrWithKey :: (forall v. k v -> f v -> b -> b) -> b -> DMap k f -> b
foldrWithKey f = go
where
go z Tip = z
go z (Bin _ kx x l r) = go (f kx x (go z r)) l
foldlWithKey :: (forall v. b -> k v -> f v -> b) -> b -> DMap k f -> b
foldlWithKey f = go
where
go z Tip = z
go z (Bin _ kx x l r) = go (f (go z l) kx x) r
keys :: DMap k f -> [Some k]
keys m
= [This k | (k :=> _) <- assocs m]
assocs :: DMap k f -> [DSum k f]
assocs m
= toList m
fromList :: GCompare k => [DSum k f] -> DMap k f
fromList xs
= foldlStrict ins empty xs
where
ins :: GCompare k => DMap k f -> DSum k f -> DMap k f
ins t (k :=> x) = insert k x t
fromListWithKey :: GCompare k => (forall v. k v -> f v -> f v -> f v) -> [DSum k f] -> DMap k f
fromListWithKey f xs
= foldlStrict (ins f) empty xs
where
ins :: GCompare k => (forall v. k v -> f v -> f v -> f v) -> DMap k f -> DSum k f -> DMap k f
ins f t (k :=> x) = insertWithKey f k x t
toList :: DMap k f -> [DSum k f]
toList t = toAscList t
toAscList :: DMap k f -> [DSum k f]
toAscList t = foldrWithKey (\k x xs -> (k :=> x):xs) [] t
toDescList :: DMap k f -> [DSum k f]
toDescList t = foldlWithKey (\xs k x -> (k :=> x):xs) [] t
fromAscList :: GEq k => [DSum k f] -> DMap k f
fromAscList xs
= fromAscListWithKey (\_ x _ -> x) xs
fromAscListWithKey :: GEq k => (forall v. k v -> f v -> f v -> f v) -> [DSum k f] -> DMap k f
fromAscListWithKey f xs
= fromDistinctAscList (combineEq f xs)
where
combineEq _ xs'
= case xs' of
[] -> []
[x] -> [x]
(x:xx) -> combineEq' f x xx
combineEq' :: GEq k => (forall v. k v -> f v -> f v -> f v) -> DSum k f -> [DSum k f] -> [DSum k f]
combineEq' f z [] = [z]
combineEq' f z@(kz :=> zz) (x@(kx :=> xx):xs') =
case geq kx kz of
Just Refl -> let yy = f kx xx zz in combineEq' f (kx :=> yy) xs'
Nothing -> z : combineEq' f x xs'
fromDistinctAscList :: [DSum k f] -> DMap k f
fromDistinctAscList xs
= build const (length xs) xs
where
build :: (DMap k f -> [DSum k f] -> b) -> Int -> [DSum k f] -> b
build c 0 xs' = c Tip xs'
build c 5 xs' = case xs' of
((k1:=>x1):(k2:=>x2):(k3:=>x3):(k4:=>x4):(k5:=>x5):xx)
-> c (bin k4 x4 (bin k2 x2 (singleton k1 x1) (singleton k3 x3)) (singleton k5 x5)) xx
_ -> error "fromDistinctAscList build"
build c n xs' = seq nr $ build (buildR nr c) nl xs'
where
nl = n `div` 2
nr = n - nl - 1
buildR :: Int -> (DMap k f -> [DSum k f] -> b) -> DMap k f -> [DSum k f] -> b
buildR n c l ((k:=>x):ys) = build (buildB l k x c) n ys
buildR _ _ _ [] = error "fromDistinctAscList buildR []"
buildB :: DMap k f -> k v -> f v -> (DMap k f -> a -> b) -> DMap k f -> a -> b
buildB l k x c r zs = c (bin k x l r) zs
split :: forall k f v. GCompare k => k v -> DMap k f -> (DMap k f, DMap k f)
split k = toPair . go
where
go :: DMap k f -> (DMap k f :*: DMap k f)
go Tip = (Tip :*: Tip)
go (Bin _ kx x l r) = case gcompare k kx of
GLT -> let !(lt :*: gt) = go l in (lt :*: combine kx x gt r)
GGT -> let !(lt :*: gt) = go r in (combine kx x l lt :*: gt)
GEQ -> (l :*: r)
{-# INLINABLE split #-}
splitLookup :: forall k f v. GCompare k => k v -> DMap k f -> (DMap k f, Maybe (f v), DMap k f)
splitLookup k = toTriple . go
where
go :: DMap k f -> Triple' (DMap k f) (Maybe (f v)) (DMap k f)
go Tip = Triple' Tip Nothing Tip
go (Bin _ kx x l r) = case gcompare k kx of
GLT -> let !(Triple' lt z gt) = go l in Triple' lt z (combine kx x gt r)
GGT -> let !(Triple' lt z gt) = go r in Triple' (combine kx x l lt) z gt
GEQ -> Triple' l (Just x) r
splitMember :: forall k f v. GCompare k => k v -> DMap k f -> (DMap k f, Bool, DMap k f)
splitMember k = toTriple . go
where
go :: DMap k f -> Triple' (DMap k f) Bool (DMap k f)
go Tip = Triple' Tip False Tip
go (Bin _ kx x l r) = case gcompare k kx of
GLT -> let !(Triple' lt z gt) = go l in Triple' lt z (combine kx x gt r)
GGT -> let !(Triple' lt z gt) = go r in Triple' (combine kx x l lt) z gt
GEQ -> Triple' l True r
splitLookupWithKey :: forall k f v. GCompare k => k v -> DMap k f -> (DMap k f, Maybe (k v, f v), DMap k f)
splitLookupWithKey k = toTriple . go
where
go :: DMap k f -> Triple' (DMap k f) (Maybe (k v, f v)) (DMap k f)
go Tip = Triple' Tip Nothing Tip
go (Bin _ kx x l r) = case gcompare k kx of
GLT -> let !(Triple' lt z gt) = go l in Triple' lt z (combine kx x gt r)
GGT -> let !(Triple' lt z gt) = go r in Triple' (combine kx x l lt) z gt
GEQ -> Triple' l (Just (kx, x)) r
instance EqTag k f => Eq (DMap k f) where
t1 == t2 = (size t1 == size t2) && (toAscList t1 == toAscList t2)
instance OrdTag k f => Ord (DMap k f) where
compare m1 m2 = compare (toAscList m1) (toAscList m2)
instance (GCompare k, ReadTag k f) => Read (DMap k f) where
readPrec = parens $ prec 10 $ do
Ident "fromList" <- lexP
xs <- readPrec
return (fromList xs)
readListPrec = readListPrecDefault
instance ShowTag k f => Show (DMap k f) where
showsPrec p m = showParen (p>10)
( showString "fromList "
. showsPrec 11 (toList m)
)
showTree :: ShowTag k f => DMap k f -> String
showTree m
= showTreeWith showElem True False m
where
showElem :: ShowTag k f => k v -> f v -> String
showElem k x = show (k :=> x)
showTreeWith :: (forall v. k v -> f v -> String) -> Bool -> Bool -> DMap k f -> String
showTreeWith showelem hang wide t
| hang = (showsTreeHang showelem wide [] t) ""
| otherwise = (showsTree showelem wide [] [] t) ""
showsTree :: (forall v. k v -> f v -> String) -> Bool -> [String] -> [String] -> DMap k f -> ShowS
showsTree showelem wide lbars rbars t
= case t of
Tip -> showsBars lbars . showString "|\n"
Bin _ kx x Tip Tip
-> showsBars lbars . showString (showelem kx x) . showString "\n"
Bin _ kx x l r
-> showsTree showelem wide (withBar rbars) (withEmpty rbars) r .
showWide wide rbars .
showsBars lbars . showString (showelem kx x) . showString "\n" .
showWide wide lbars .
showsTree showelem wide (withEmpty lbars) (withBar lbars) l
showsTreeHang :: (forall v. k v -> f v -> String) -> Bool -> [String] -> DMap k f -> ShowS
showsTreeHang showelem wide bars t
= case t of
Tip -> showsBars bars . showString "|\n"
Bin _ kx x Tip Tip
-> showsBars bars . showString (showelem kx x) . showString "\n"
Bin _ kx x l r
-> showsBars bars . showString (showelem kx x) . showString "\n" .
showWide wide bars .
showsTreeHang showelem wide (withBar bars) l .
showWide wide bars .
showsTreeHang showelem wide (withEmpty bars) r
showWide :: Bool -> [String] -> String -> String
showWide wide bars
| wide = showString (concat (reverse bars)) . showString "|\n"
| otherwise = id
showsBars :: [String] -> ShowS
showsBars bars
= case bars of
[] -> id
_ -> showString (concat (reverse (tail bars))) . showString node
node :: String
node = "+--"
withBar, withEmpty :: [String] -> [String]
withBar bars = "| ":bars
withEmpty bars = " ":bars
valid :: GCompare k => DMap k f -> Bool
valid t
= balanced t && ordered t && validsize t
ordered :: GCompare k => DMap k f -> Bool
ordered t
= bounded (const True) (const True) t
where
bounded :: GCompare k => (Some k -> Bool) -> (Some k -> Bool) -> DMap k f -> Bool
bounded lo hi t'
= case t' of
Tip -> True
Bin _ kx _ l r -> (lo (This kx)) && (hi (This kx)) && bounded lo (< This kx) l && bounded (> This kx) hi r
balanced :: DMap k f -> Bool
balanced t
= case t of
Tip -> True
Bin _ _ _ l r -> (size l + size r <= 1 || (size l <= delta*size r && size r <= delta*size l)) &&
balanced l && balanced r
validsize :: DMap k f -> Bool
validsize t
= (realsize t == Just (size t))
where
realsize t'
= case t' of
Tip -> Just 0
Bin sz _ _ l r -> case (realsize l,realsize r) of
(Just n,Just m) | n+m+1 == sz -> Just sz
_ -> Nothing
foldlStrict :: (a -> b -> a) -> a -> [b] -> a
foldlStrict f = go
where
go z [] = z
go z (x:xs) = z `seq` go (f z x) xs