ghc-9.12.1: GHC/Types/Unique/Set.hs
{-
(c) The University of Glasgow 2006
(c) The AQUA Project, Glasgow University, 1994-1998
\section[UniqSet]{Specialised sets, for things with @Uniques@}
Based on @UniqFMs@ (as you would expect).
Basically, the things need to be in class @Uniquable@.
-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
module GHC.Types.Unique.Set (
-- * Unique set type
UniqSet, -- type synonym for UniqFM a
getUniqSet,
pprUniqSet,
-- ** Manipulating these sets
emptyUniqSet,
unitUniqSet,
mkUniqSet,
addOneToUniqSet, addListToUniqSet,
delOneFromUniqSet, delOneFromUniqSet_Directly, delListFromUniqSet,
delListFromUniqSet_Directly,
unionUniqSets, unionManyUniqSets,
minusUniqSet, uniqSetMinusUFM, uniqSetMinusUDFM,
intersectUniqSets,
disjointUniqSets,
restrictUniqSetToUFM,
uniqSetAny, uniqSetAll,
elementOfUniqSet,
elemUniqSet_Directly,
filterUniqSet,
filterUniqSet_Directly,
sizeUniqSet,
isEmptyUniqSet,
lookupUniqSet,
lookupUniqSet_Directly,
partitionUniqSet,
mapUniqSet,
unsafeUFMToUniqSet,
nonDetEltsUniqSet,
nonDetKeysUniqSet,
nonDetStrictFoldUniqSet,
mapMaybeUniqSet_sameUnique,
-- UniqueSet
UniqueSet(..),
nullUniqueSet,
sizeUniqueSet,
memberUniqueSet,
emptyUniqueSet,
singletonUniqueSet,
insertUniqueSet,
deleteUniqueSet,
differenceUniqueSet,
unionUniqueSet,
unionsUniqueSet,
intersectionUniqueSet,
isSubsetOfUniqueSet,
filterUniqueSet,
foldlUniqueSet,
foldrUniqueSet,
elemsUniqueSet,
fromListUniqueSet,
) where
import GHC.Prelude
import GHC.Types.Unique.DFM
import GHC.Types.Unique.FM
import GHC.Types.Unique
import Data.Coerce
import GHC.Utils.Outputable
import Data.Data
import qualified Data.Semigroup as Semi
import Control.DeepSeq
import qualified GHC.Data.Word64Set as S
-- Note [UniqSet invariant]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~
-- UniqSet has the following invariant:
-- The keys in the map are the uniques of the values
-- It means that to implement mapUniqSet you have to update
-- both the keys and the values.
-- | Set of Uniquable values
newtype UniqSet a = UniqSet {getUniqSet' :: UniqFM a a}
deriving (Data, Semi.Semigroup, Monoid)
instance NFData a => NFData (UniqSet a) where
rnf = forceUniqSet rnf
emptyUniqSet :: UniqSet a
emptyUniqSet = UniqSet emptyUFM
unitUniqSet :: Uniquable a => a -> UniqSet a
unitUniqSet x = UniqSet $ unitUFM x x
mkUniqSet :: Uniquable a => [a] -> UniqSet a
mkUniqSet = foldl' addOneToUniqSet emptyUniqSet
{-# INLINEABLE mkUniqSet #-}
addOneToUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a
addOneToUniqSet (UniqSet set) x = UniqSet (addToUFM set x x)
addListToUniqSet :: Uniquable a => UniqSet a -> [a] -> UniqSet a
addListToUniqSet = foldl' addOneToUniqSet
{-# INLINEABLE addListToUniqSet #-}
delOneFromUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a
delOneFromUniqSet (UniqSet s) a = UniqSet (delFromUFM s a)
delOneFromUniqSet_Directly :: UniqSet a -> Unique -> UniqSet a
delOneFromUniqSet_Directly (UniqSet s) u = UniqSet (delFromUFM_Directly s u)
delListFromUniqSet :: Uniquable a => UniqSet a -> [a] -> UniqSet a
delListFromUniqSet (UniqSet s) l = UniqSet (delListFromUFM s l)
{-# INLINEABLE delListFromUniqSet #-}
delListFromUniqSet_Directly :: UniqSet a -> [Unique] -> UniqSet a
delListFromUniqSet_Directly (UniqSet s) l =
UniqSet (delListFromUFM_Directly s l)
{-# INLINEABLE delListFromUniqSet_Directly #-}
unionUniqSets :: UniqSet a -> UniqSet a -> UniqSet a
unionUniqSets (UniqSet s) (UniqSet t) = UniqSet (plusUFM s t)
unionManyUniqSets :: [UniqSet a] -> UniqSet a
unionManyUniqSets = foldl' (flip unionUniqSets) emptyUniqSet
minusUniqSet :: UniqSet a -> UniqSet a -> UniqSet a
minusUniqSet (UniqSet s) (UniqSet t) = UniqSet (minusUFM s t)
intersectUniqSets :: UniqSet a -> UniqSet a -> UniqSet a
intersectUniqSets (UniqSet s) (UniqSet t) = UniqSet (intersectUFM s t)
disjointUniqSets :: UniqSet a -> UniqSet a -> Bool
disjointUniqSets (UniqSet s) (UniqSet t) = disjointUFM s t
restrictUniqSetToUFM :: UniqSet key -> UniqFM key b -> UniqSet key
restrictUniqSetToUFM (UniqSet s) m = UniqSet (intersectUFM s m)
uniqSetMinusUFM :: UniqSet key -> UniqFM key b -> UniqSet key
uniqSetMinusUFM (UniqSet s) t = UniqSet (minusUFM s t)
uniqSetMinusUDFM :: UniqSet key -> UniqDFM key b -> UniqSet key
uniqSetMinusUDFM (UniqSet s) t = UniqSet (ufmMinusUDFM s t)
elementOfUniqSet :: Uniquable a => a -> UniqSet a -> Bool
elementOfUniqSet a (UniqSet s) = elemUFM a s
elemUniqSet_Directly :: Unique -> UniqSet a -> Bool
elemUniqSet_Directly a (UniqSet s) = elemUFM_Directly a s
filterUniqSet :: (a -> Bool) -> UniqSet a -> UniqSet a
filterUniqSet p (UniqSet s) = UniqSet (filterUFM p s)
filterUniqSet_Directly :: (Unique -> elt -> Bool) -> UniqSet elt -> UniqSet elt
filterUniqSet_Directly f (UniqSet s) = UniqSet (filterUFM_Directly f s)
partitionUniqSet :: (a -> Bool) -> UniqSet a -> (UniqSet a, UniqSet a)
partitionUniqSet p (UniqSet s) = coerce (partitionUFM p s)
uniqSetAny :: (a -> Bool) -> UniqSet a -> Bool
uniqSetAny p (UniqSet s) = anyUFM p s
uniqSetAll :: (a -> Bool) -> UniqSet a -> Bool
uniqSetAll p (UniqSet s) = allUFM p s
sizeUniqSet :: UniqSet a -> Int
sizeUniqSet (UniqSet s) = sizeUFM s
isEmptyUniqSet :: UniqSet a -> Bool
isEmptyUniqSet (UniqSet s) = isNullUFM s
-- | What's the point you might ask? We might have changed an object
-- without it's key changing. In which case this lookup makes sense.
lookupUniqSet :: Uniquable key => UniqSet key -> key -> Maybe key
lookupUniqSet (UniqSet s) k = lookupUFM s k
lookupUniqSet_Directly :: UniqSet a -> Unique -> Maybe a
lookupUniqSet_Directly (UniqSet s) k = lookupUFM_Directly s k
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
-- nondeterminism.
nonDetEltsUniqSet :: UniqSet elt -> [elt]
nonDetEltsUniqSet = nonDetEltsUFM . getUniqSet'
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
-- nondeterminism.
nonDetKeysUniqSet :: UniqSet elt -> [Unique]
nonDetKeysUniqSet = nonDetKeysUFM . getUniqSet'
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
-- nondeterminism.
nonDetStrictFoldUniqSet :: (elt -> a -> a) -> a -> UniqSet elt -> a
nonDetStrictFoldUniqSet c n (UniqSet s) = nonDetStrictFoldUFM c n s
-- See Note [UniqSet invariant]
mapUniqSet :: Uniquable b => (a -> b) -> UniqSet a -> UniqSet b
mapUniqSet f = mkUniqSet . map f . nonDetEltsUniqSet
-- | Like 'Data.Set.mapMaybe', but you must ensure the passed in function
-- does not change the 'Unique'.
mapMaybeUniqSet_sameUnique :: (a -> Maybe b) -> UniqSet a -> UniqSet b
mapMaybeUniqSet_sameUnique f (UniqSet a) = UniqSet $ mapMaybeUFM_sameUnique f a
-- Two 'UniqSet's are considered equal if they contain the same
-- uniques.
instance Eq (UniqSet a) where
UniqSet a == UniqSet b = equalKeysUFM a b
getUniqSet :: UniqSet a -> UniqFM a a
getUniqSet = getUniqSet'
-- | 'unsafeUFMToUniqSet' converts a @'UniqFM' a@ into a @'UniqSet' a@
-- assuming, without checking, that it maps each 'Unique' to a value
-- that has that 'Unique'. See Note [UniqSet invariant].
unsafeUFMToUniqSet :: UniqFM a a -> UniqSet a
unsafeUFMToUniqSet = UniqSet
instance Outputable a => Outputable (UniqSet a) where
ppr = pprUniqSet ppr
pprUniqSet :: (a -> SDoc) -> UniqSet a -> SDoc
-- It's OK to use nonDetUFMToList here because we only use it for
-- pretty-printing.
pprUniqSet f = braces . pprWithCommas f . nonDetEltsUniqSet
forceUniqSet :: (a -> ()) -> UniqSet a -> ()
forceUniqSet f (UniqSet fm) = seqEltsUFM f fm
--------------------------------------------------------
-- UniqueSet
--------------------------------------------------------
-- | Set of Unique values
--
-- Similar to 'UniqSet Unique' but with a more compact representation.
newtype UniqueSet = US { unUniqueSet :: S.Word64Set }
deriving (Eq, Ord, Show, Semigroup, Monoid)
{-# INLINE nullUniqueSet #-}
nullUniqueSet :: UniqueSet -> Bool
nullUniqueSet (US s) = S.null s
{-# INLINE sizeUniqueSet #-}
sizeUniqueSet :: UniqueSet -> Int
sizeUniqueSet (US s) = S.size s
{-# INLINE memberUniqueSet #-}
memberUniqueSet :: Unique -> UniqueSet -> Bool
memberUniqueSet k (US s) = S.member (getKey k) s
{-# INLINE emptyUniqueSet #-}
emptyUniqueSet :: UniqueSet
emptyUniqueSet = US S.empty
{-# INLINE singletonUniqueSet #-}
singletonUniqueSet :: Unique -> UniqueSet
singletonUniqueSet k = US (S.singleton (getKey k))
{-# INLINE insertUniqueSet #-}
insertUniqueSet :: Unique -> UniqueSet -> UniqueSet
insertUniqueSet k (US s) = US (S.insert (getKey k) s)
{-# INLINE deleteUniqueSet #-}
deleteUniqueSet :: Unique -> UniqueSet -> UniqueSet
deleteUniqueSet k (US s) = US (S.delete (getKey k) s)
{-# INLINE unionUniqueSet #-}
unionUniqueSet :: UniqueSet -> UniqueSet -> UniqueSet
unionUniqueSet (US x) (US y) = US (S.union x y)
{-# INLINE unionsUniqueSet #-}
unionsUniqueSet :: [UniqueSet] -> UniqueSet
unionsUniqueSet xs = US (S.unions (map unUniqueSet xs))
{-# INLINE differenceUniqueSet #-}
differenceUniqueSet :: UniqueSet -> UniqueSet -> UniqueSet
differenceUniqueSet (US x) (US y) = US (S.difference x y)
{-# INLINE intersectionUniqueSet #-}
intersectionUniqueSet :: UniqueSet -> UniqueSet -> UniqueSet
intersectionUniqueSet (US x) (US y) = US (S.intersection x y)
{-# INLINE isSubsetOfUniqueSet #-}
isSubsetOfUniqueSet :: UniqueSet -> UniqueSet -> Bool
isSubsetOfUniqueSet (US x) (US y) = S.isSubsetOf x y
{-# INLINE filterUniqueSet #-}
filterUniqueSet :: (Unique -> Bool) -> UniqueSet -> UniqueSet
filterUniqueSet f (US s) = US (S.filter (f . mkUniqueGrimily) s)
{-# INLINE foldlUniqueSet #-}
foldlUniqueSet :: (a -> Unique -> a) -> a -> UniqueSet -> a
foldlUniqueSet k z (US s) = S.foldl' (\a b -> k a (mkUniqueGrimily b)) z s
{-# INLINE foldrUniqueSet #-}
foldrUniqueSet :: (Unique -> b -> b) -> b -> UniqueSet -> b
foldrUniqueSet k z (US s) = S.foldr (k . mkUniqueGrimily) z s
{-# INLINE elemsUniqueSet #-}
elemsUniqueSet :: UniqueSet -> [Unique]
elemsUniqueSet (US s) = map mkUniqueGrimily (S.elems s)
{-# INLINE fromListUniqueSet #-}
fromListUniqueSet :: [Unique] -> UniqueSet
fromListUniqueSet ks = US (S.fromList (map getKey ks))