packages feed

unordered-containers 0.2.11.0 → 0.2.12.0

raw patch · 21 files changed

+4531/−4077 lines, 21 filesdep −deepseq-genericsdep ~deepseqPVP ok

version bump matches the API change (PVP)

Dependencies removed: deepseq-generics

Dependency ranges changed: deepseq

API changes (from Hackage documentation)

+ Data.HashMap.Internal: (!) :: (Eq k, Hashable k, HasCallStack) => HashMap k v -> k -> v
+ Data.HashMap.Internal: (!?) :: (Eq k, Hashable k) => HashMap k v -> k -> Maybe v
+ Data.HashMap.Internal: Absent :: LookupRes a
+ Data.HashMap.Internal: BitmapIndexed :: !Bitmap -> !Array (HashMap k v) -> HashMap k v
+ Data.HashMap.Internal: Collision :: !Hash -> !Array (Leaf k v) -> HashMap k v
+ Data.HashMap.Internal: Empty :: HashMap k v
+ Data.HashMap.Internal: Full :: !Array (HashMap k v) -> HashMap k v
+ Data.HashMap.Internal: L :: !k -> v -> Leaf k v
+ Data.HashMap.Internal: Leaf :: !Hash -> !Leaf k v -> HashMap k v
+ Data.HashMap.Internal: Present :: a -> !Int -> LookupRes a
+ Data.HashMap.Internal: adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: adjust# :: (Eq k, Hashable k) => (v -> (# v #)) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: alterF :: (Functor f, Eq k, Hashable k) => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)
+ Data.HashMap.Internal: bitmapIndexedOrFull :: Bitmap -> Array (HashMap k v) -> HashMap k v
+ Data.HashMap.Internal: bitsPerSubkey :: Int
+ Data.HashMap.Internal: collision :: Hash -> Leaf k v -> Leaf k v -> HashMap k v
+ Data.HashMap.Internal: data HashMap k v
+ Data.HashMap.Internal: data Leaf k v
+ Data.HashMap.Internal: data LookupRes a
+ Data.HashMap.Internal: delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: delete' :: Eq k => Hash -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: difference :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal: differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal: elems :: HashMap k v -> [v]
+ Data.HashMap.Internal: empty :: HashMap k v
+ Data.HashMap.Internal: equalKeys :: Eq k => HashMap k v -> HashMap k v' -> Bool
+ Data.HashMap.Internal: equalKeys1 :: (k -> k' -> Bool) -> HashMap k v -> HashMap k' v' -> Bool
+ Data.HashMap.Internal: filter :: (v -> Bool) -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: filterMapAux :: forall k v1 v2. (HashMap k v1 -> Maybe (HashMap k v2)) -> (Leaf k v1 -> Maybe (Leaf k v2)) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal: filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: findWithDefault :: (Eq k, Hashable k) => v -> k -> HashMap k v -> v
+ Data.HashMap.Internal: foldMapWithKey :: Monoid m => (k -> v -> m) -> HashMap k v -> m
+ Data.HashMap.Internal: foldl :: (a -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldl' :: (a -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldlWithKey :: (a -> k -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldr :: (v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldr' :: (v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldrWithKey :: (k -> v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: foldrWithKey' :: (k -> v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal: fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v
+ Data.HashMap.Internal: fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v
+ Data.HashMap.Internal: fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v
+ Data.HashMap.Internal: fullNodeMask :: Bitmap
+ Data.HashMap.Internal: hash :: Hashable a => a -> Hash
+ Data.HashMap.Internal: index :: Hash -> Shift -> Int
+ Data.HashMap.Internal: infixl 9 !
+ Data.HashMap.Internal: insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: insert' :: Eq k => Hash -> k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: insertKeyExists :: Int -> Hash -> k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: insertModifying :: (Eq k, Hashable k) => v -> (v -> (# v #)) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: insertNewKey :: Hash -> k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: instance (Control.DeepSeq.NFData k, Control.DeepSeq.NFData v) => Control.DeepSeq.NFData (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (Control.DeepSeq.NFData k, Control.DeepSeq.NFData v) => Control.DeepSeq.NFData (Data.HashMap.Internal.Leaf k v)
+ Data.HashMap.Internal: instance (Data.Data.Data k, Data.Data.Data v, GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Data.Data.Data (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (Data.Hashable.Class.Hashable k, Data.Hashable.Class.Hashable v) => Data.Hashable.Class.Hashable (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => GHC.Base.Monoid (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => GHC.Base.Semigroup (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => GHC.Exts.IsList (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k, GHC.Read.Read k) => Data.Functor.Classes.Read1 (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k, GHC.Read.Read k, GHC.Read.Read e) => GHC.Read.Read (Data.HashMap.Internal.HashMap k e)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.HashMap.Internal.Leaf k v)
+ Data.HashMap.Internal: instance (GHC.Classes.Ord k, GHC.Classes.Ord v) => GHC.Classes.Ord (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.HashMap.Internal.HashMap k v)
+ Data.HashMap.Internal: instance Data.Bifoldable.Bifoldable Data.HashMap.Internal.HashMap
+ Data.HashMap.Internal: instance Data.Foldable.Foldable (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance Data.Functor.Classes.Eq2 Data.HashMap.Internal.HashMap
+ Data.HashMap.Internal: instance Data.Functor.Classes.Ord2 Data.HashMap.Internal.HashMap
+ Data.HashMap.Internal: instance Data.Functor.Classes.Show2 Data.HashMap.Internal.HashMap
+ Data.HashMap.Internal: instance Data.Hashable.Class.Hashable k => Data.Hashable.Class.Hashable1 (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance Data.Hashable.Class.Hashable2 Data.HashMap.Internal.HashMap
+ Data.HashMap.Internal: instance Data.Traversable.Traversable (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance GHC.Base.Functor (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance GHC.Classes.Eq k => Data.Functor.Classes.Eq1 (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance GHC.Classes.Ord k => Data.Functor.Classes.Ord1 (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: instance GHC.Show.Show k => Data.Functor.Classes.Show1 (Data.HashMap.Internal.HashMap k)
+ Data.HashMap.Internal: intersection :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal: intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+ Data.HashMap.Internal: intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3) -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+ Data.HashMap.Internal: isSubmapOf :: (Eq k, Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool
+ Data.HashMap.Internal: isSubmapOfBy :: (Eq k, Hashable k) => (v1 -> v2 -> Bool) -> HashMap k v1 -> HashMap k v2 -> Bool
+ Data.HashMap.Internal: keys :: HashMap k v -> [k]
+ Data.HashMap.Internal: lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
+ Data.HashMap.Internal: lookup' :: Eq k => Hash -> k -> HashMap k v -> Maybe v
+ Data.HashMap.Internal: lookupDefault :: (Eq k, Hashable k) => v -> k -> HashMap k v -> v
+ Data.HashMap.Internal: lookupRecordCollision :: Eq k => Hash -> k -> HashMap k v -> LookupRes v
+ Data.HashMap.Internal: map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal: mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal: mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal: mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal: mask :: Word -> Shift -> Bitmap
+ Data.HashMap.Internal: member :: (Eq k, Hashable k) => k -> HashMap k a -> Bool
+ Data.HashMap.Internal: null :: HashMap k v -> Bool
+ Data.HashMap.Internal: ptrEq :: a -> a -> Bool
+ Data.HashMap.Internal: singleton :: Hashable k => k -> v -> HashMap k v
+ Data.HashMap.Internal: size :: HashMap k v -> Int
+ Data.HashMap.Internal: sparseIndex :: Bitmap -> Bitmap -> Int
+ Data.HashMap.Internal: toList :: HashMap k v -> [(k, v)]
+ Data.HashMap.Internal: traverseWithKey :: Applicative f => (k -> v1 -> f v2) -> HashMap k v1 -> f (HashMap k v2)
+ Data.HashMap.Internal: two :: Shift -> Hash -> k -> v -> Hash -> HashMap k v -> ST s (HashMap k v)
+ Data.HashMap.Internal: type Bitmap = Word
+ Data.HashMap.Internal: type Hash = Word
+ Data.HashMap.Internal: union :: (Eq k, Hashable k) => HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: unionArrayBy :: (a -> a -> a) -> Bitmap -> Bitmap -> Array a -> Array a -> Array a
+ Data.HashMap.Internal: unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: unions :: (Eq k, Hashable k) => [HashMap k v] -> HashMap k v
+ Data.HashMap.Internal: unsafeInsert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal: update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a
+ Data.HashMap.Internal: update16 :: Array e -> Int -> e -> Array e
+ Data.HashMap.Internal: update16M :: Array e -> Int -> e -> ST s (Array e)
+ Data.HashMap.Internal: update16With' :: Array e -> Int -> (e -> e) -> Array e
+ Data.HashMap.Internal: updateOrConcatWith :: Eq k => (v -> v -> v) -> Array (Leaf k v) -> Array (Leaf k v) -> Array (Leaf k v)
+ Data.HashMap.Internal: updateOrConcatWithKey :: Eq k => (k -> v -> v -> v) -> Array (Leaf k v) -> Array (Leaf k v) -> Array (Leaf k v)
+ Data.HashMap.Internal.Array: all :: (a -> Bool) -> Array a -> Bool
+ Data.HashMap.Internal.Array: copy :: Array e -> Int -> MArray s e -> Int -> Int -> ST s ()
+ Data.HashMap.Internal.Array: copyM :: MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()
+ Data.HashMap.Internal.Array: data Array a
+ Data.HashMap.Internal.Array: data MArray s a
+ Data.HashMap.Internal.Array: delete :: Array e -> Int -> Array e
+ Data.HashMap.Internal.Array: foldMap :: Monoid m => (a -> m) -> Array a -> m
+ Data.HashMap.Internal.Array: foldl :: (b -> a -> b) -> b -> Array a -> b
+ Data.HashMap.Internal.Array: foldl' :: (b -> a -> b) -> b -> Array a -> b
+ Data.HashMap.Internal.Array: foldr :: (a -> b -> b) -> b -> Array a -> b
+ Data.HashMap.Internal.Array: foldr' :: (a -> b -> b) -> b -> Array a -> b
+ Data.HashMap.Internal.Array: fromList :: Int -> [a] -> Array a
+ Data.HashMap.Internal.Array: index :: Array a -> Int -> a
+ Data.HashMap.Internal.Array: index# :: Array a -> Int -> (# a #)
+ Data.HashMap.Internal.Array: indexM :: Array a -> Int -> ST s a
+ Data.HashMap.Internal.Array: insert :: Array e -> Int -> e -> Array e
+ Data.HashMap.Internal.Array: insertM :: Array e -> Int -> e -> ST s (Array e)
+ Data.HashMap.Internal.Array: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Data.HashMap.Internal.Array.Array a)
+ Data.HashMap.Internal.Array: instance GHC.Show.Show a => GHC.Show.Show (Data.HashMap.Internal.Array.Array a)
+ Data.HashMap.Internal.Array: length :: Array a -> Int
+ Data.HashMap.Internal.Array: lengthM :: MArray s a -> Int
+ Data.HashMap.Internal.Array: map :: (a -> b) -> Array a -> Array b
+ Data.HashMap.Internal.Array: map' :: (a -> b) -> Array a -> Array b
+ Data.HashMap.Internal.Array: new :: Int -> a -> ST s (MArray s a)
+ Data.HashMap.Internal.Array: new_ :: Int -> ST s (MArray s a)
+ Data.HashMap.Internal.Array: pair :: a -> a -> Array a
+ Data.HashMap.Internal.Array: read :: MArray s a -> Int -> ST s a
+ Data.HashMap.Internal.Array: run :: (forall s. ST s (MArray s e)) -> Array e
+ Data.HashMap.Internal.Array: sameArray1 :: (a -> b -> Bool) -> Array a -> Array b -> Bool
+ Data.HashMap.Internal.Array: singleton :: a -> Array a
+ Data.HashMap.Internal.Array: singletonM :: a -> ST s (Array a)
+ Data.HashMap.Internal.Array: thaw :: Array e -> Int -> Int -> ST s (MArray s e)
+ Data.HashMap.Internal.Array: toList :: Array a -> [a]
+ Data.HashMap.Internal.Array: traverse :: Applicative f => (a -> f b) -> Array a -> f (Array b)
+ Data.HashMap.Internal.Array: traverse' :: Applicative f => (a -> f b) -> Array a -> f (Array b)
+ Data.HashMap.Internal.Array: trim :: MArray s a -> Int -> ST s (Array a)
+ Data.HashMap.Internal.Array: unsafeFreeze :: MArray s a -> ST s (Array a)
+ Data.HashMap.Internal.Array: unsafeSameArray :: Array a -> Array b -> Bool
+ Data.HashMap.Internal.Array: unsafeThaw :: Array a -> ST s (MArray s a)
+ Data.HashMap.Internal.Array: unsafeUpdateM :: Array e -> Int -> e -> ST s ()
+ Data.HashMap.Internal.Array: update :: Array e -> Int -> e -> Array e
+ Data.HashMap.Internal.Array: updateWith' :: Array e -> Int -> (e -> e) -> Array e
+ Data.HashMap.Internal.Array: write :: MArray s a -> Int -> a -> ST s ()
+ Data.HashMap.Internal.List: deleteBy :: (a -> b -> Bool) -> a -> [b] -> Maybe [b]
+ Data.HashMap.Internal.List: isPermutationBy :: (a -> b -> Bool) -> [a] -> [b] -> Bool
+ Data.HashMap.Internal.List: unorderedCompare :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering
+ Data.HashMap.Internal.Strict: (!) :: (Eq k, Hashable k, HasCallStack) => HashMap k v -> k -> v
+ Data.HashMap.Internal.Strict: (!?) :: (Eq k, Hashable k) => HashMap k v -> k -> Maybe v
+ Data.HashMap.Internal.Strict: adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: alterF :: (Functor f, Eq k, Hashable k) => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)
+ Data.HashMap.Internal.Strict: data HashMap k v
+ Data.HashMap.Internal.Strict: delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: difference :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal.Strict: differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal.Strict: elems :: HashMap k v -> [v]
+ Data.HashMap.Internal.Strict: empty :: HashMap k v
+ Data.HashMap.Internal.Strict: filter :: (v -> Bool) -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: findWithDefault :: (Eq k, Hashable k) => v -> k -> HashMap k v -> v
+ Data.HashMap.Internal.Strict: foldMapWithKey :: Monoid m => (k -> v -> m) -> HashMap k v -> m
+ Data.HashMap.Internal.Strict: foldl :: (a -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldl' :: (a -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldlWithKey :: (a -> k -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldr :: (v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldr' :: (v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldrWithKey :: (k -> v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: foldrWithKey' :: (k -> v -> a -> a) -> a -> HashMap k v -> a
+ Data.HashMap.Internal.Strict: fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v
+ Data.HashMap.Internal.Strict: fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v
+ Data.HashMap.Internal.Strict: fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v
+ Data.HashMap.Internal.Strict: infixl 9 !
+ Data.HashMap.Internal.Strict: insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: intersection :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v
+ Data.HashMap.Internal.Strict: intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+ Data.HashMap.Internal.Strict: intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3) -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+ Data.HashMap.Internal.Strict: isSubmapOf :: (Eq k, Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool
+ Data.HashMap.Internal.Strict: isSubmapOfBy :: (Eq k, Hashable k) => (v1 -> v2 -> Bool) -> HashMap k v1 -> HashMap k v2 -> Bool
+ Data.HashMap.Internal.Strict: keys :: HashMap k v -> [k]
+ Data.HashMap.Internal.Strict: lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
+ Data.HashMap.Internal.Strict: lookupDefault :: (Eq k, Hashable k) => v -> k -> HashMap k v -> v
+ Data.HashMap.Internal.Strict: map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal.Strict: mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal.Strict: mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal.Strict: mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2
+ Data.HashMap.Internal.Strict: member :: (Eq k, Hashable k) => k -> HashMap k a -> Bool
+ Data.HashMap.Internal.Strict: null :: HashMap k v -> Bool
+ Data.HashMap.Internal.Strict: singleton :: Hashable k => k -> v -> HashMap k v
+ Data.HashMap.Internal.Strict: size :: HashMap k v -> Int
+ Data.HashMap.Internal.Strict: toList :: HashMap k v -> [(k, v)]
+ Data.HashMap.Internal.Strict: traverseWithKey :: Applicative f => (k -> v1 -> f v2) -> HashMap k v1 -> f (HashMap k v2)
+ Data.HashMap.Internal.Strict: union :: (Eq k, Hashable k) => HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v -> HashMap k v
+ Data.HashMap.Internal.Strict: unions :: (Eq k, Hashable k) => [HashMap k v] -> HashMap k v
+ Data.HashMap.Internal.Strict: update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a
+ Data.HashMap.Internal.Unsafe: runST :: () => (forall s. () => ST s a) -> a
+ Data.HashMap.Lazy: isSubmapOf :: (Eq k, Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool
+ Data.HashMap.Lazy: isSubmapOfBy :: (Eq k, Hashable k) => (v1 -> v2 -> Bool) -> HashMap k v1 -> HashMap k v2 -> Bool
+ Data.HashMap.Strict: isSubmapOf :: (Eq k, Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool
+ Data.HashMap.Strict: isSubmapOfBy :: (Eq k, Hashable k) => (v1 -> v2 -> Bool) -> HashMap k v1 -> HashMap k v2 -> Bool
+ Data.HashSet: isSubsetOf :: (Eq a, Hashable a) => HashSet a -> HashSet a -> Bool
+ Data.HashSet.Internal: data HashSet a
+ Data.HashSet.Internal: delete :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a
+ Data.HashSet.Internal: difference :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a
+ Data.HashSet.Internal: empty :: HashSet a
+ Data.HashSet.Internal: filter :: (a -> Bool) -> HashSet a -> HashSet a
+ Data.HashSet.Internal: foldl :: (a -> b -> a) -> a -> HashSet b -> a
+ Data.HashSet.Internal: foldl' :: (a -> b -> a) -> a -> HashSet b -> a
+ Data.HashSet.Internal: foldr :: (b -> a -> a) -> a -> HashSet b -> a
+ Data.HashSet.Internal: foldr' :: (b -> a -> a) -> a -> HashSet b -> a
+ Data.HashSet.Internal: fromList :: (Eq a, Hashable a) => [a] -> HashSet a
+ Data.HashSet.Internal: fromMap :: HashMap a () -> HashSet a
+ Data.HashSet.Internal: insert :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a
+ Data.HashSet.Internal: instance (Data.Data.Data a, GHC.Classes.Eq a, Data.Hashable.Class.Hashable a) => Data.Data.Data (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance (Data.Hashable.Class.Hashable a, GHC.Classes.Eq a) => GHC.Base.Monoid (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance (Data.Hashable.Class.Hashable a, GHC.Classes.Eq a) => GHC.Base.Semigroup (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance (GHC.Classes.Eq a, Data.Hashable.Class.Hashable a) => GHC.Exts.IsList (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance (GHC.Classes.Eq a, Data.Hashable.Class.Hashable a, GHC.Read.Read a) => GHC.Read.Read (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance Data.Foldable.Foldable Data.HashSet.Internal.HashSet
+ Data.HashSet.Internal: instance Data.Functor.Classes.Eq1 Data.HashSet.Internal.HashSet
+ Data.HashSet.Internal: instance Data.Functor.Classes.Ord1 Data.HashSet.Internal.HashSet
+ Data.HashSet.Internal: instance Data.Functor.Classes.Show1 Data.HashSet.Internal.HashSet
+ Data.HashSet.Internal: instance Data.Hashable.Class.Hashable a => Data.Hashable.Class.Hashable (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance Data.Hashable.Class.Hashable1 Data.HashSet.Internal.HashSet
+ Data.HashSet.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: instance GHC.Show.Show a => GHC.Show.Show (Data.HashSet.Internal.HashSet a)
+ Data.HashSet.Internal: intersection :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a
+ Data.HashSet.Internal: isSubsetOf :: (Eq a, Hashable a) => HashSet a -> HashSet a -> Bool
+ Data.HashSet.Internal: keysSet :: HashMap k a -> HashSet k
+ Data.HashSet.Internal: map :: (Hashable b, Eq b) => (a -> b) -> HashSet a -> HashSet b
+ Data.HashSet.Internal: member :: (Eq a, Hashable a) => a -> HashSet a -> Bool
+ Data.HashSet.Internal: null :: HashSet a -> Bool
+ Data.HashSet.Internal: singleton :: Hashable a => a -> HashSet a
+ Data.HashSet.Internal: size :: HashSet a -> Int
+ Data.HashSet.Internal: toList :: HashSet a -> [a]
+ Data.HashSet.Internal: toMap :: HashSet a -> HashMap a ()
+ Data.HashSet.Internal: union :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a
+ Data.HashSet.Internal: unions :: (Eq a, Hashable a) => [HashSet a] -> HashSet a

Files

CHANGES.md view
@@ -1,3 +1,25 @@+## [0.2.12.0]++* Add `HashMap.isSubmapOf[By]` and `HashSet.isSubsetOf`. Thanks Sven Keidel. ([#282])++* Expose internal modules. ([#283])++* Documentation improvements in `Data.HashSet`, including a beginner-friendly+  introduction. Thanks Matt Renaud. ([#267])++* `HashMap[.Strict].alterF`: Skip key deletion for absent keys. ([#288])++* Remove custom `unsafeShift{L,R}` definitions. ([#281])++* Various other documentation improvements.++[0.2.12.0]: https://github.com/haskell-unordered-containers/unordered-containers/compare/v0.2.11.0...v0.2.12.0+[#267]: https://github.com/haskell-unordered-containers/unordered-containers/pull/267+[#281]: https://github.com/haskell-unordered-containers/unordered-containers/pull/281+[#282]: https://github.com/haskell-unordered-containers/unordered-containers/pull/282+[#283]: https://github.com/haskell-unordered-containers/unordered-containers/pull/283+[#288]: https://github.com/haskell-unordered-containers/unordered-containers/pull/288+ ## 0.2.11.0   * Add `HashMap.findWithDefault` (soft-deprecates `HashMap.lookupDefault`).
− Data/HashMap/Array.hs
@@ -1,619 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples, ScopedTypeVariables #-}-{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}---- | Zero based arrays.------ Note that no bounds checking are performed.-module Data.HashMap.Array-    ( Array-    , MArray--      -- * Creation-    , new-    , new_-    , singleton-    , singletonM-    , pair--      -- * Basic interface-    , length-    , lengthM-    , read-    , write-    , index-    , indexM-    , index#-    , update-    , updateWith'-    , unsafeUpdateM-    , insert-    , insertM-    , delete-    , sameArray1-    , trim--    , unsafeFreeze-    , unsafeThaw-    , unsafeSameArray-    , run-    , run2-    , copy-    , copyM--      -- * Folds-    , foldl-    , foldl'-    , foldr-    , foldr'-    , foldMap--    , thaw-    , map-    , map'-    , traverse-    , traverse'-    , toList-    , fromList-    ) where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative (Applicative (..), (<$>))-#endif-import Control.Applicative (liftA2)-import Control.DeepSeq-import GHC.Exts(Int(..), Int#, reallyUnsafePtrEquality#, tagToEnum#, unsafeCoerce#, State#)-import GHC.ST (ST(..))-import Control.Monad.ST (stToIO)--#if __GLASGOW_HASKELL__ >= 709-import Prelude hiding (filter, foldMap, foldr, foldl, length, map, read, traverse)-#else-import Prelude hiding (filter, foldr, foldl, length, map, read)-#endif--#if __GLASGOW_HASKELL__ >= 710-import GHC.Exts (SmallArray#, newSmallArray#, readSmallArray#, writeSmallArray#,-                 indexSmallArray#, unsafeFreezeSmallArray#, unsafeThawSmallArray#,-                 SmallMutableArray#, sizeofSmallArray#, copySmallArray#, thawSmallArray#,-                 sizeofSmallMutableArray#, copySmallMutableArray#, cloneSmallMutableArray#)--#else-import GHC.Exts (Array#, newArray#, readArray#, writeArray#,-                 indexArray#, unsafeFreezeArray#, unsafeThawArray#,-                 MutableArray#, sizeofArray#, copyArray#, thawArray#,-                 sizeofMutableArray#, copyMutableArray#, cloneMutableArray#)-import Data.Monoid (Monoid (..))-#endif--#if defined(ASSERTS)-import qualified Prelude-#endif--import Data.HashMap.Unsafe (runST)-import Control.Monad ((>=>))---#if __GLASGOW_HASKELL__ >= 710-type Array# a = SmallArray# a-type MutableArray# a = SmallMutableArray# a--newArray# :: Int# -> a -> State# d -> (# State# d, SmallMutableArray# d a #)-newArray# = newSmallArray#--unsafeFreezeArray# :: SmallMutableArray# d a-                   -> State# d -> (# State# d, SmallArray# a #)-unsafeFreezeArray# = unsafeFreezeSmallArray#--readArray# :: SmallMutableArray# d a-           -> Int# -> State# d -> (# State# d, a #)-readArray# = readSmallArray#--writeArray# :: SmallMutableArray# d a-            -> Int# -> a -> State# d -> State# d-writeArray# = writeSmallArray#--indexArray# :: SmallArray# a -> Int# -> (# a #)-indexArray# = indexSmallArray#--unsafeThawArray# :: SmallArray# a-                 -> State# d -> (# State# d, SmallMutableArray# d a #)-unsafeThawArray# = unsafeThawSmallArray#--sizeofArray# :: SmallArray# a -> Int#-sizeofArray# = sizeofSmallArray#--copyArray# :: SmallArray# a-           -> Int#-           -> SmallMutableArray# d a-           -> Int#-           -> Int#-           -> State# d-           -> State# d-copyArray# = copySmallArray#--cloneMutableArray# :: SmallMutableArray# s a-                   -> Int#-                   -> Int#-                   -> State# s-                   -> (# State# s, SmallMutableArray# s a #)-cloneMutableArray# = cloneSmallMutableArray#--thawArray# :: SmallArray# a-           -> Int#-           -> Int#-           -> State# d-           -> (# State# d, SmallMutableArray# d a #)-thawArray# = thawSmallArray#--sizeofMutableArray# :: SmallMutableArray# s a -> Int#-sizeofMutableArray# = sizeofSmallMutableArray#--copyMutableArray# :: SmallMutableArray# d a-                  -> Int#-                  -> SmallMutableArray# d a-                  -> Int#-                  -> Int#-                  -> State# d-                  -> State# d-copyMutableArray# = copySmallMutableArray#-#endif----------------------------------------------------------------------------#if defined(ASSERTS)--- This fugly hack is brought by GHC's apparent reluctance to deal--- with MagicHash and UnboxedTuples when inferring types. Eek!-# define CHECK_BOUNDS(_func_,_len_,_k_) \-if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.HashMap.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else-# define CHECK_OP(_func_,_op_,_lhs_,_rhs_) \-if not ((_lhs_) _op_ (_rhs_)) then error ("Data.HashMap.Array." ++ (_func_) ++ ": Check failed: _lhs_ _op_ _rhs_ (" ++ show (_lhs_) ++ " vs. " ++ show (_rhs_) ++ ")") else-# define CHECK_GT(_func_,_lhs_,_rhs_) CHECK_OP(_func_,>,_lhs_,_rhs_)-# define CHECK_LE(_func_,_lhs_,_rhs_) CHECK_OP(_func_,<=,_lhs_,_rhs_)-# define CHECK_EQ(_func_,_lhs_,_rhs_) CHECK_OP(_func_,==,_lhs_,_rhs_)-#else-# define CHECK_BOUNDS(_func_,_len_,_k_)-# define CHECK_OP(_func_,_op_,_lhs_,_rhs_)-# define CHECK_GT(_func_,_lhs_,_rhs_)-# define CHECK_LE(_func_,_lhs_,_rhs_)-# define CHECK_EQ(_func_,_lhs_,_rhs_)-#endif--data Array a = Array {-      unArray :: !(Array# a)-    }--instance Show a => Show (Array a) where-    show = show . toList---- Determines whether two arrays have the same memory address.--- This is more reliable than testing pointer equality on the--- Array wrappers, but it's still slightly bogus.-unsafeSameArray :: Array a -> Array b -> Bool-unsafeSameArray (Array xs) (Array ys) =-  tagToEnum# (unsafeCoerce# reallyUnsafePtrEquality# xs ys)--sameArray1 :: (a -> b -> Bool) -> Array a -> Array b -> Bool-sameArray1 eq !xs0 !ys0-  | lenxs /= lenys = False-  | otherwise = go 0 xs0 ys0-  where-    go !k !xs !ys-      | k == lenxs = True-      | (# x #) <- index# xs k-      , (# y #) <- index# ys k-      = eq x y && go (k + 1) xs ys--    !lenxs = length xs0-    !lenys = length ys0--length :: Array a -> Int-length ary = I# (sizeofArray# (unArray ary))-{-# INLINE length #-}---- | Smart constructor-array :: Array# a -> Int -> Array a-array ary _n = Array ary-{-# INLINE array #-}--data MArray s a = MArray {-      unMArray :: !(MutableArray# s a)-    }--lengthM :: MArray s a -> Int-lengthM mary = I# (sizeofMutableArray# (unMArray mary))-{-# INLINE lengthM #-}---- | Smart constructor-marray :: MutableArray# s a -> Int -> MArray s a-marray mary _n = MArray mary-{-# INLINE marray #-}----------------------------------------------------------------------------instance NFData a => NFData (Array a) where-    rnf = rnfArray--rnfArray :: NFData a => Array a -> ()-rnfArray ary0 = go ary0 n0 0-  where-    n0 = length ary0-    go !ary !n !i-        | i >= n = ()-        | (# x #) <- index# ary i-        = rnf x `seq` go ary n (i+1)--- We use index# just in case GHC can't see that the--- relevant rnf is strict, or in case it actually isn't.-{-# INLINE rnfArray #-}---- | Create a new mutable array of specified size, in the specified--- state thread, with each element containing the specified initial--- value.-new :: Int -> a -> ST s (MArray s a)-new n@(I# n#) b =-    CHECK_GT("new",n,(0 :: Int))-    ST $ \s ->-        case newArray# n# b s of-            (# s', ary #) -> (# s', marray ary n #)-{-# INLINE new #-}--new_ :: Int -> ST s (MArray s a)-new_ n = new n undefinedElem--singleton :: a -> Array a-singleton x = runST (singletonM x)-{-# INLINE singleton #-}--singletonM :: a -> ST s (Array a)-singletonM x = new 1 x >>= unsafeFreeze-{-# INLINE singletonM #-}--pair :: a -> a -> Array a-pair x y = run $ do-    ary <- new 2 x-    write ary 1 y-    return ary-{-# INLINE pair #-}--read :: MArray s a -> Int -> ST s a-read ary _i@(I# i#) = ST $ \ s ->-    CHECK_BOUNDS("read", lengthM ary, _i)-        readArray# (unMArray ary) i# s-{-# INLINE read #-}--write :: MArray s a -> Int -> a -> ST s ()-write ary _i@(I# i#) b = ST $ \ s ->-    CHECK_BOUNDS("write", lengthM ary, _i)-        case writeArray# (unMArray ary) i# b s of-            s' -> (# s' , () #)-{-# INLINE write #-}--index :: Array a -> Int -> a-index ary _i@(I# i#) =-    CHECK_BOUNDS("index", length ary, _i)-        case indexArray# (unArray ary) i# of (# b #) -> b-{-# INLINE index #-}--index# :: Array a -> Int -> (# a #)-index# ary _i@(I# i#) =-    CHECK_BOUNDS("index#", length ary, _i)-        indexArray# (unArray ary) i#-{-# INLINE index# #-}--indexM :: Array a -> Int -> ST s a-indexM ary _i@(I# i#) =-    CHECK_BOUNDS("indexM", length ary, _i)-        case indexArray# (unArray ary) i# of (# b #) -> return b-{-# INLINE indexM #-}--unsafeFreeze :: MArray s a -> ST s (Array a)-unsafeFreeze mary-    = ST $ \s -> case unsafeFreezeArray# (unMArray mary) s of-                   (# s', ary #) -> (# s', array ary (lengthM mary) #)-{-# INLINE unsafeFreeze #-}--unsafeThaw :: Array a -> ST s (MArray s a)-unsafeThaw ary-    = ST $ \s -> case unsafeThawArray# (unArray ary) s of-                   (# s', mary #) -> (# s', marray mary (length ary) #)-{-# INLINE unsafeThaw #-}--run :: (forall s . ST s (MArray s e)) -> Array e-run act = runST $ act >>= unsafeFreeze-{-# INLINE run #-}--run2 :: (forall s. ST s (MArray s e, a)) -> (Array e, a)-run2 k = runST (do-                 (marr,b) <- k-                 arr <- unsafeFreeze marr-                 return (arr,b))---- | Unsafely copy the elements of an array. Array bounds are not checked.-copy :: Array e -> Int -> MArray s e -> Int -> Int -> ST s ()-copy !src !_sidx@(I# sidx#) !dst !_didx@(I# didx#) _n@(I# n#) =-    CHECK_LE("copy", _sidx + _n, length src)-    CHECK_LE("copy", _didx + _n, lengthM dst)-        ST $ \ s# ->-        case copyArray# (unArray src) sidx# (unMArray dst) didx# n# s# of-            s2 -> (# s2, () #)---- | Unsafely copy the elements of an array. Array bounds are not checked.-copyM :: MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()-copyM !src !_sidx@(I# sidx#) !dst !_didx@(I# didx#) _n@(I# n#) =-    CHECK_BOUNDS("copyM: src", lengthM src, _sidx + _n - 1)-    CHECK_BOUNDS("copyM: dst", lengthM dst, _didx + _n - 1)-    ST $ \ s# ->-    case copyMutableArray# (unMArray src) sidx# (unMArray dst) didx# n# s# of-        s2 -> (# s2, () #)--cloneM :: MArray s a -> Int -> Int -> ST s (MArray s a)-cloneM _mary@(MArray mary#) _off@(I# off#) _len@(I# len#) =-    CHECK_BOUNDS("cloneM_off", lengthM _mary, _off - 1)-    CHECK_BOUNDS("cloneM_end", lengthM _mary, _off + _len - 1)-    ST $ \ s ->-    case cloneMutableArray# mary# off# len# s of-      (# s', mary'# #) -> (# s', MArray mary'# #)---- | Create a new array of the @n@ first elements of @mary@.-trim :: MArray s a -> Int -> ST s (Array a)-trim mary n = cloneM mary 0 n >>= unsafeFreeze-{-# INLINE trim #-}---- | /O(n)/ Insert an element at the given position in this array,--- increasing its size by one.-insert :: Array e -> Int -> e -> Array e-insert ary idx b = runST (insertM ary idx b)-{-# INLINE insert #-}---- | /O(n)/ Insert an element at the given position in this array,--- increasing its size by one.-insertM :: Array e -> Int -> e -> ST s (Array e)-insertM ary idx b =-    CHECK_BOUNDS("insertM", count + 1, idx)-        do mary <- new_ (count+1)-           copy ary 0 mary 0 idx-           write mary idx b-           copy ary idx mary (idx+1) (count-idx)-           unsafeFreeze mary-  where !count = length ary-{-# INLINE insertM #-}---- | /O(n)/ Update the element at the given position in this array.-update :: Array e -> Int -> e -> Array e-update ary idx b = runST (updateM ary idx b)-{-# INLINE update #-}---- | /O(n)/ Update the element at the given position in this array.-updateM :: Array e -> Int -> e -> ST s (Array e)-updateM ary idx b =-    CHECK_BOUNDS("updateM", count, idx)-        do mary <- thaw ary 0 count-           write mary idx b-           unsafeFreeze mary-  where !count = length ary-{-# INLINE updateM #-}---- | /O(n)/ Update the element at the given positio in this array, by--- applying a function to it.  Evaluates the element to WHNF before--- inserting it into the array.-updateWith' :: Array e -> Int -> (e -> e) -> Array e-updateWith' ary idx f-  | (# x #) <- index# ary idx-  = update ary idx $! f x-{-# INLINE updateWith' #-}---- | /O(1)/ Update the element at the given position in this array,--- without copying.-unsafeUpdateM :: Array e -> Int -> e -> ST s ()-unsafeUpdateM ary idx b =-    CHECK_BOUNDS("unsafeUpdateM", length ary, idx)-        do mary <- unsafeThaw ary-           write mary idx b-           _ <- unsafeFreeze mary-           return ()-{-# INLINE unsafeUpdateM #-}--foldl' :: (b -> a -> b) -> b -> Array a -> b-foldl' f = \ z0 ary0 -> go ary0 (length ary0) 0 z0-  where-    go ary n i !z-        | i >= n = z-        | otherwise-        = case index# ary i of-            (# x #) -> go ary n (i+1) (f z x)-{-# INLINE foldl' #-}--foldr' :: (a -> b -> b) -> b -> Array a -> b-foldr' f = \ z0 ary0 -> go ary0 (length ary0 - 1) z0-  where-    go !_ary (-1) z = z-    go !ary i !z-      | (# x #) <- index# ary i-      = go ary (i - 1) (f x z)-{-# INLINE foldr' #-}--foldr :: (a -> b -> b) -> b -> Array a -> b-foldr f = \ z0 ary0 -> go ary0 (length ary0) 0 z0-  where-    go ary n i z-        | i >= n = z-        | otherwise-        = case index# ary i of-            (# x #) -> f x (go ary n (i+1) z)-{-# INLINE foldr #-}--foldl :: (b -> a -> b) -> b -> Array a -> b-foldl f = \ z0 ary0 -> go ary0 (length ary0 - 1) z0-  where-    go _ary (-1) z = z-    go ary i z-      | (# x #) <- index# ary i-      = f (go ary (i - 1) z) x-{-# INLINE foldl #-}---- We go to a bit of trouble here to avoid appending an extra mempty.--- The below implementation is by Mateusz Kowalczyk, who indicates that--- benchmarks show it to be faster than one that avoids lifting out--- lst.-foldMap :: Monoid m => (a -> m) -> Array a -> m-foldMap f = \ary0 -> case length ary0 of-  0 -> mempty-  len ->-    let !lst = len - 1-        go i | (# x #) <- index# ary0 i, let fx = f x =-          if i == lst then fx else fx `mappend` go (i + 1)-    in go 0-{-# INLINE foldMap #-}--undefinedElem :: a-undefinedElem = error "Data.HashMap.Array: Undefined element"-{-# NOINLINE undefinedElem #-}--thaw :: Array e -> Int -> Int -> ST s (MArray s e)-thaw !ary !_o@(I# o#) !n@(I# n#) =-    CHECK_LE("thaw", _o + n, length ary)-        ST $ \ s -> case thawArray# (unArray ary) o# n# s of-            (# s2, mary# #) -> (# s2, marray mary# n #)-{-# INLINE thaw #-}---- | /O(n)/ Delete an element at the given position in this array,--- decreasing its size by one.-delete :: Array e -> Int -> Array e-delete ary idx = runST (deleteM ary idx)-{-# INLINE delete #-}---- | /O(n)/ Delete an element at the given position in this array,--- decreasing its size by one.-deleteM :: Array e -> Int -> ST s (Array e)-deleteM ary idx = do-    CHECK_BOUNDS("deleteM", count, idx)-        do mary <- new_ (count-1)-           copy ary 0 mary 0 idx-           copy ary (idx+1) mary idx (count-(idx+1))-           unsafeFreeze mary-  where !count = length ary-{-# INLINE deleteM #-}--map :: (a -> b) -> Array a -> Array b-map f = \ ary ->-    let !n = length ary-    in run $ do-        mary <- new_ n-        go ary mary 0 n-  where-    go ary mary i n-        | i >= n    = return mary-        | otherwise = do-             x <- indexM ary i-             write mary i $ f x-             go ary mary (i+1) n-{-# INLINE map #-}---- | Strict version of 'map'.-map' :: (a -> b) -> Array a -> Array b-map' f = \ ary ->-    let !n = length ary-    in run $ do-        mary <- new_ n-        go ary mary 0 n-  where-    go ary mary i n-        | i >= n    = return mary-        | otherwise = do-             x <- indexM ary i-             write mary i $! f x-             go ary mary (i+1) n-{-# INLINE map' #-}--fromList :: Int -> [a] -> Array a-fromList n xs0 =-    CHECK_EQ("fromList", n, Prelude.length xs0)-        run $ do-            mary <- new_ n-            go xs0 mary 0-  where-    go [] !mary !_   = return mary-    go (x:xs) mary i = do write mary i x-                          go xs mary (i+1)--toList :: Array a -> [a]-toList = foldr (:) []--newtype STA a = STA {_runSTA :: forall s. MutableArray# s a -> ST s (Array a)}--runSTA :: Int -> STA a -> Array a-runSTA !n (STA m) = runST $ new_ n >>= \ (MArray ar) -> m ar--traverse :: Applicative f => (a -> f b) -> Array a -> f (Array b)-traverse f = \ !ary ->-  let-    !len = length ary-    go !i-      | i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)-      | (# x #) <- index# ary i-      = liftA2 (\b (STA m) -> STA $ \mary ->-                  write (MArray mary) i b >> m mary)-               (f x) (go (i + 1))-  in runSTA len <$> go 0-{-# INLINE [1] traverse #-}---- TODO: Would it be better to just use a lazy traversal--- and then force the elements of the result? My guess is--- yes.-traverse' :: Applicative f => (a -> f b) -> Array a -> f (Array b)-traverse' f = \ !ary ->-  let-    !len = length ary-    go !i-      | i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)-      | (# x #) <- index# ary i-      = liftA2 (\ !b (STA m) -> STA $ \mary ->-                    write (MArray mary) i b >> m mary)-               (f x) (go (i + 1))-  in runSTA len <$> go 0-{-# INLINE [1] traverse' #-}---- Traversing in ST, we don't need to get fancy; we--- can just do it directly.-traverseST :: (a -> ST s b) -> Array a -> ST s (Array b)-traverseST f = \ ary0 ->-  let-    !len = length ary0-    go k !mary-      | k == len = return mary-      | otherwise = do-          x <- indexM ary0 k-          y <- f x-          write mary k y-          go (k + 1) mary-  in new_ len >>= (go 0 >=> unsafeFreeze)-{-# INLINE traverseST #-}--traverseIO :: (a -> IO b) -> Array a -> IO (Array b)-traverseIO f = \ ary0 ->-  let-    !len = length ary0-    go k !mary-      | k == len = return mary-      | otherwise = do-          x <- stToIO $ indexM ary0 k-          y <- f x-          stToIO $ write mary k y-          go (k + 1) mary-  in stToIO (new_ len) >>= (go 0 >=> stToIO . unsafeFreeze)-{-# INLINE traverseIO #-}----- Why don't we have similar RULES for traverse'? The efficient--- way to traverse strictly in IO or ST is to force results as--- they come in, which leads to different semantics. In particular,--- we need to ensure that------  traverse' (\x -> print x *> pure undefined) xs------ will actually print all the values and then return undefined.--- We could add a strict mapMWithIndex, operating in an arbitrary--- Monad, that supported such rules, but we don't have that right now.-{-# RULES-"traverse/ST" forall f. traverse f = traverseST f-"traverse/IO" forall f. traverse f = traverseIO f- #-}
− Data/HashMap/Base.hs
@@ -1,2132 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, MagicHash #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PatternGuards #-}-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UnboxedTuples #-}-{-# LANGUAGE LambdaCase #-}-#if __GLASGOW_HASKELL__ >= 802-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE UnboxedSums #-}-#endif-{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}--module Data.HashMap.Base-    (-      HashMap(..)-    , Leaf(..)--      -- * Construction-    , empty-    , singleton--      -- * Basic interface-    , null-    , size-    , member-    , lookup-    , (!?)-    , findWithDefault-    , lookupDefault-    , (!)-    , insert-    , insertWith-    , unsafeInsert-    , delete-    , adjust-    , update-    , alter-    , alterF--      -- * Combine-      -- ** Union-    , union-    , unionWith-    , unionWithKey-    , unions--      -- * Transformations-    , map-    , mapWithKey-    , traverseWithKey--      -- * Difference and intersection-    , difference-    , differenceWith-    , intersection-    , intersectionWith-    , intersectionWithKey--      -- * Folds-    , foldr'-    , foldl'-    , foldrWithKey'-    , foldlWithKey'-    , foldr-    , foldl-    , foldrWithKey-    , foldlWithKey-    , foldMapWithKey--      -- * Filter-    , mapMaybe-    , mapMaybeWithKey-    , filter-    , filterWithKey--      -- * Conversions-    , keys-    , elems--      -- ** Lists-    , toList-    , fromList-    , fromListWith-    , fromListWithKey--      -- Internals used by the strict version-    , Hash-    , Bitmap-    , bitmapIndexedOrFull-    , collision-    , hash-    , mask-    , index-    , bitsPerSubkey-    , fullNodeMask-    , sparseIndex-    , two-    , unionArrayBy-    , update16-    , update16M-    , update16With'-    , updateOrConcatWith-    , updateOrConcatWithKey-    , filterMapAux-    , equalKeys-    , equalKeys1-    , lookupRecordCollision-    , LookupRes(..)-    , insert'-    , delete'-    , lookup'-    , insertNewKey-    , insertKeyExists-    , deleteKeyExists-    , insertModifying-    , ptrEq-    , adjust#-    ) where--#if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>), Applicative(pure))-import Data.Monoid (Monoid(mempty, mappend))-import Data.Traversable (Traversable(..))-import Data.Word (Word)-#endif-#if __GLASGOW_HASKELL__ >= 711-import Data.Semigroup (Semigroup((<>)))-#endif-import Control.DeepSeq (NFData(rnf))-import Control.Monad.ST (ST)-import Data.Bits ((.&.), (.|.), complement, popCount)-import Data.Data hiding (Typeable)-import qualified Data.Foldable as Foldable-#if MIN_VERSION_base(4,10,0)-import Data.Bifoldable-#endif-import qualified Data.List as L-import GHC.Exts ((==#), build, reallyUnsafePtrEquality#)-import Prelude hiding (filter, foldl, foldr, lookup, map, null, pred)-import Text.Read hiding (step)--import qualified Data.HashMap.Array as A-import qualified Data.Hashable as H-import Data.Hashable (Hashable)-import Data.HashMap.Unsafe (runST)-import Data.HashMap.UnsafeShift (unsafeShiftL, unsafeShiftR)-import Data.HashMap.List (isPermutationBy, unorderedCompare)-import Data.Typeable (Typeable)--import GHC.Exts (isTrue#)-import qualified GHC.Exts as Exts--#if MIN_VERSION_base(4,9,0)-import Data.Functor.Classes-import GHC.Stack-#endif--#if MIN_VERSION_hashable(1,2,5)-import qualified Data.Hashable.Lifted as H-#endif--#if __GLASGOW_HASKELL__ >= 802-import GHC.Exts (TYPE, Int (..), Int#)-#endif--#if MIN_VERSION_base(4,8,0)-import Data.Functor.Identity (Identity (..))-#endif-import Control.Applicative (Const (..))-import Data.Coerce (coerce)---- | A set of values.  A set cannot contain duplicate values.----------------------------------------------------------------------------- | Convenience function.  Compute a hash value for the given value.-hash :: H.Hashable a => a -> Hash-hash = fromIntegral . H.hash--data Leaf k v = L !k v-  deriving (Eq)--instance (NFData k, NFData v) => NFData (Leaf k v) where-    rnf (L k v) = rnf k `seq` rnf v---- Invariant: The length of the 1st argument to 'Full' is--- 2^bitsPerSubkey---- | A map from keys to values.  A map cannot contain duplicate keys;--- each key can map to at most one value.-data HashMap k v-    = Empty-    | BitmapIndexed !Bitmap !(A.Array (HashMap k v))-    | Leaf !Hash !(Leaf k v)-    | Full !(A.Array (HashMap k v))-    | Collision !Hash !(A.Array (Leaf k v))-      deriving (Typeable)--type role HashMap nominal representational--instance (NFData k, NFData v) => NFData (HashMap k v) where-    rnf Empty                 = ()-    rnf (BitmapIndexed _ ary) = rnf ary-    rnf (Leaf _ l)            = rnf l-    rnf (Full ary)            = rnf ary-    rnf (Collision _ ary)     = rnf ary--instance Functor (HashMap k) where-    fmap = map--instance Foldable.Foldable (HashMap k) where-    foldMap f = foldMapWithKey (\ _k v -> f v)-    {-# INLINE foldMap #-}-    foldr = foldr-    {-# INLINE foldr #-}-    foldl = foldl-    {-# INLINE foldl #-}-    foldr' = foldr'-    {-# INLINE foldr' #-}-    foldl' = foldl'-    {-# INLINE foldl' #-}-#if MIN_VERSION_base(4,8,0)-    null = null-    {-# INLINE null #-}-    length = size-    {-# INLINE length #-}-#endif--#if MIN_VERSION_base(4,10,0)--- | @since 0.2.11-instance Bifoldable HashMap where-    bifoldMap f g = foldMapWithKey (\ k v -> f k `mappend` g v)-    {-# INLINE bifoldMap #-}-    bifoldr f g = foldrWithKey (\ k v acc -> k `f` (v `g` acc))-    {-# INLINE bifoldr #-}-    bifoldl f g = foldlWithKey (\ acc k v -> (acc `f` k) `g` v)-    {-# INLINE bifoldl #-}-#endif--#if __GLASGOW_HASKELL__ >= 711--- | '<>' = 'union'------ If a key occurs in both maps, the mapping from the first will be the mapping in the result.------ ==== __Examples__------ >>> fromList [(1,'a'),(2,'b')] <> fromList [(2,'c'),(3,'d')]--- fromList [(1,'a'),(2,'b'),(3,'d')]-instance (Eq k, Hashable k) => Semigroup (HashMap k v) where-  (<>) = union-  {-# INLINE (<>) #-}-#endif---- | 'mempty' = 'empty'------ 'mappend' = 'union'------ If a key occurs in both maps, the mapping from the first will be the mapping in the result.------ ==== __Examples__------ >>> mappend (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])--- fromList [(1,'a'),(2,'b'),(3,'d')]-instance (Eq k, Hashable k) => Monoid (HashMap k v) where-  mempty = empty-  {-# INLINE mempty #-}-#if __GLASGOW_HASKELL__ >= 711-  mappend = (<>)-#else-  mappend = union-#endif-  {-# INLINE mappend #-}--instance (Data k, Data v, Eq k, Hashable k) => Data (HashMap k v) where-    gfoldl f z m   = z fromList `f` toList m-    toConstr _     = fromListConstr-    gunfold k z c  = case constrIndex c of-        1 -> k (z fromList)-        _ -> error "gunfold"-    dataTypeOf _   = hashMapDataType-    dataCast2 f    = gcast2 f--fromListConstr :: Constr-fromListConstr = mkConstr hashMapDataType "fromList" [] Prefix--hashMapDataType :: DataType-hashMapDataType = mkDataType "Data.HashMap.Base.HashMap" [fromListConstr]--type Hash   = Word-type Bitmap = Word-type Shift  = Int--#if MIN_VERSION_base(4,9,0)-instance Show2 HashMap where-    liftShowsPrec2 spk slk spv slv d m =-        showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)-      where-        sp = liftShowsPrec2 spk slk spv slv-        sl = liftShowList2 spk slk spv slv--instance Show k => Show1 (HashMap k) where-    liftShowsPrec = liftShowsPrec2 showsPrec showList--instance (Eq k, Hashable k, Read k) => Read1 (HashMap k) where-    liftReadsPrec rp rl = readsData $-        readsUnaryWith (liftReadsPrec rp' rl') "fromList" fromList-      where-        rp' = liftReadsPrec rp rl-        rl' = liftReadList rp rl-#endif--instance (Eq k, Hashable k, Read k, Read e) => Read (HashMap k e) where-    readPrec = parens $ prec 10 $ do-      Ident "fromList" <- lexP-      xs <- readPrec-      return (fromList xs)--    readListPrec = readListPrecDefault--instance (Show k, Show v) => Show (HashMap k v) where-    showsPrec d m = showParen (d > 10) $-      showString "fromList " . shows (toList m)--instance Traversable (HashMap k) where-    traverse f = traverseWithKey (const f)-    {-# INLINABLE traverse #-}--#if MIN_VERSION_base(4,9,0)-instance Eq2 HashMap where-    liftEq2 = equal2--instance Eq k => Eq1 (HashMap k) where-    liftEq = equal1-#endif---- | Note that, in the presence of hash collisions, equal @HashMap@s may--- behave differently, i.e. substitutivity may be violated:------ >>> data D = A | B deriving (Eq, Show)--- >>> instance Hashable D where hashWithSalt salt _d = salt------ >>> x = fromList [(A,1), (B,2)]--- >>> y = fromList [(B,2), (A,1)]------ >>> x == y--- True--- >>> toList x--- [(A,1),(B,2)]--- >>> toList y--- [(B,2),(A,1)]------ In general, the lack of substitutivity can be observed with any function--- that depends on the key ordering, such as folds and traversals.-instance (Eq k, Eq v) => Eq (HashMap k v) where-    (==) = equal1 (==)---- We rely on there being no Empty constructors in the tree!--- This ensures that two equal HashMaps will have the same--- shape, modulo the order of entries in Collisions.-equal1 :: Eq k-       => (v -> v' -> Bool)-       -> HashMap k v -> HashMap k v' -> Bool-equal1 eq = go-  where-    go Empty Empty = True-    go (BitmapIndexed bm1 ary1) (BitmapIndexed bm2 ary2)-      = bm1 == bm2 && A.sameArray1 go ary1 ary2-    go (Leaf h1 l1) (Leaf h2 l2) = h1 == h2 && leafEq l1 l2-    go (Full ary1) (Full ary2) = A.sameArray1 go ary1 ary2-    go (Collision h1 ary1) (Collision h2 ary2)-      = h1 == h2 && isPermutationBy leafEq (A.toList ary1) (A.toList ary2)-    go _ _ = False--    leafEq (L k1 v1) (L k2 v2) = k1 == k2 && eq v1 v2--equal2 :: (k -> k' -> Bool) -> (v -> v' -> Bool)-      -> HashMap k v -> HashMap k' v' -> Bool-equal2 eqk eqv t1 t2 = go (toList' t1 []) (toList' t2 [])-  where-    -- If the two trees are the same, then their lists of 'Leaf's and-    -- 'Collision's read from left to right should be the same (modulo the-    -- order of elements in 'Collision').--    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)-      | k1 == k2 &&-        leafEq l1 l2-      = go tl1 tl2-    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)-      | k1 == k2 &&-        A.length ary1 == A.length ary2 &&-        isPermutationBy leafEq (A.toList ary1) (A.toList ary2)-      = go tl1 tl2-    go [] [] = True-    go _  _  = False--    leafEq (L k v) (L k' v') = eqk k k' && eqv v v'--#if MIN_VERSION_base(4,9,0)-instance Ord2 HashMap where-    liftCompare2 = cmp--instance Ord k => Ord1 (HashMap k) where-    liftCompare = cmp compare-#endif---- | The ordering is total and consistent with the `Eq` instance. However,--- nothing else about the ordering is specified, and it may change from --- version to version of either this package or of hashable.-instance (Ord k, Ord v) => Ord (HashMap k v) where-    compare = cmp compare compare--cmp :: (k -> k' -> Ordering) -> (v -> v' -> Ordering)-    -> HashMap k v -> HashMap k' v' -> Ordering-cmp cmpk cmpv t1 t2 = go (toList' t1 []) (toList' t2 [])-  where-    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)-      = compare k1 k2 `mappend`-        leafCompare l1 l2 `mappend`-        go tl1 tl2-    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)-      = compare k1 k2 `mappend`-        compare (A.length ary1) (A.length ary2) `mappend`-        unorderedCompare leafCompare (A.toList ary1) (A.toList ary2) `mappend`-        go tl1 tl2-    go (Leaf _ _ : _) (Collision _ _ : _) = LT-    go (Collision _ _ : _) (Leaf _ _ : _) = GT-    go [] [] = EQ-    go [] _  = LT-    go _  [] = GT-    go _ _ = error "cmp: Should never happen, toList' includes non Leaf / Collision"--    leafCompare (L k v) (L k' v') = cmpk k k' `mappend` cmpv v v'---- Same as 'equal' but doesn't compare the values.-equalKeys1 :: (k -> k' -> Bool) -> HashMap k v -> HashMap k' v' -> Bool-equalKeys1 eq t1 t2 = go (toList' t1 []) (toList' t2 [])-  where-    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)-      | k1 == k2 && leafEq l1 l2-      = go tl1 tl2-    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)-      | k1 == k2 && A.length ary1 == A.length ary2 &&-        isPermutationBy leafEq (A.toList ary1) (A.toList ary2)-      = go tl1 tl2-    go [] [] = True-    go _  _  = False--    leafEq (L k _) (L k' _) = eq k k'---- Same as 'equal1' but doesn't compare the values.-equalKeys :: Eq k => HashMap k v -> HashMap k v' -> Bool-equalKeys = go-  where-    go :: Eq k => HashMap k v -> HashMap k v' -> Bool-    go Empty Empty = True-    go (BitmapIndexed bm1 ary1) (BitmapIndexed bm2 ary2)-      = bm1 == bm2 && A.sameArray1 go ary1 ary2-    go (Leaf h1 l1) (Leaf h2 l2) = h1 == h2 && leafEq l1 l2-    go (Full ary1) (Full ary2) = A.sameArray1 go ary1 ary2-    go (Collision h1 ary1) (Collision h2 ary2)-      = h1 == h2 && isPermutationBy leafEq (A.toList ary1) (A.toList ary2)-    go _ _ = False--    leafEq (L k1 _) (L k2 _) = k1 == k2--#if MIN_VERSION_hashable(1,2,5)-instance H.Hashable2 HashMap where-    liftHashWithSalt2 hk hv salt hm = go salt (toList' hm [])-      where-        -- go :: Int -> [HashMap k v] -> Int-        go s [] = s-        go s (Leaf _ l : tl)-          = s `hashLeafWithSalt` l `go` tl-        -- For collisions we hashmix hash value-        -- and then array of values' hashes sorted-        go s (Collision h a : tl)-          = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a `go` tl-        go s (_ : tl) = s `go` tl--        -- hashLeafWithSalt :: Int -> Leaf k v -> Int-        hashLeafWithSalt s (L k v) = (s `hk` k) `hv` v--        -- hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int-        hashCollisionWithSalt s-          = L.foldl' H.hashWithSalt s . arrayHashesSorted s--        -- arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]-        arrayHashesSorted s = L.sort . L.map (hashLeafWithSalt s) . A.toList--instance (Hashable k) => H.Hashable1 (HashMap k) where-    liftHashWithSalt = H.liftHashWithSalt2 H.hashWithSalt-#endif--instance (Hashable k, Hashable v) => Hashable (HashMap k v) where-    hashWithSalt salt hm = go salt hm-      where-        go :: Int -> HashMap k v -> Int-        go s Empty = s-        go s (BitmapIndexed _ a) = A.foldl' go s a-        go s (Leaf h (L _ v))-          = s `H.hashWithSalt` h `H.hashWithSalt` v-        -- For collisions we hashmix hash value-        -- and then array of values' hashes sorted-        go s (Full a) = A.foldl' go s a-        go s (Collision h a)-          = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a--        hashLeafWithSalt :: Int -> Leaf k v -> Int-        hashLeafWithSalt s (L k v) = s `H.hashWithSalt` k `H.hashWithSalt` v--        hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int-        hashCollisionWithSalt s-          = L.foldl' H.hashWithSalt s . arrayHashesSorted s--        arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]-        arrayHashesSorted s = L.sort . L.map (hashLeafWithSalt s) . A.toList--  -- Helper to get 'Leaf's and 'Collision's as a list.-toList' :: HashMap k v -> [HashMap k v] -> [HashMap k v]-toList' (BitmapIndexed _ ary) a = A.foldr toList' a ary-toList' (Full ary)            a = A.foldr toList' a ary-toList' l@(Leaf _ _)          a = l : a-toList' c@(Collision _ _)     a = c : a-toList' Empty                 a = a---- Helper function to detect 'Leaf's and 'Collision's.-isLeafOrCollision :: HashMap k v -> Bool-isLeafOrCollision (Leaf _ _)      = True-isLeafOrCollision (Collision _ _) = True-isLeafOrCollision _               = False----------------------------------------------------------------------------- * Construction---- | /O(1)/ Construct an empty map.-empty :: HashMap k v-empty = Empty---- | /O(1)/ Construct a map with a single element.-singleton :: (Hashable k) => k -> v -> HashMap k v-singleton k v = Leaf (hash k) (L k v)----------------------------------------------------------------------------- * Basic interface---- | /O(1)/ Return 'True' if this map is empty, 'False' otherwise.-null :: HashMap k v -> Bool-null Empty = True-null _   = False---- | /O(n)/ Return the number of key-value mappings in this map.-size :: HashMap k v -> Int-size t = go t 0-  where-    go Empty                !n = n-    go (Leaf _ _)            n = n + 1-    go (BitmapIndexed _ ary) n = A.foldl' (flip go) n ary-    go (Full ary)            n = A.foldl' (flip go) n ary-    go (Collision _ ary)     n = n + A.length ary---- | /O(log n)/ Return 'True' if the specified key is present in the--- map, 'False' otherwise.-member :: (Eq k, Hashable k) => k -> HashMap k a -> Bool-member k m = case lookup k m of-    Nothing -> False-    Just _  -> True-{-# INLINABLE member #-}---- | /O(log n)/ Return the value to which the specified key is mapped,--- or 'Nothing' if this map contains no mapping for the key.-lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v-#if __GLASGOW_HASKELL__ >= 802--- GHC does not yet perform a worker-wrapper transformation on--- unboxed sums automatically. That seems likely to happen at some--- point (possibly as early as GHC 8.6) but for now we do it manually.-lookup k m = case lookup# k m of-  (# (# #) | #) -> Nothing-  (# | a #) -> Just a-{-# INLINE lookup #-}--lookup# :: (Eq k, Hashable k) => k -> HashMap k v -> (# (# #) | v #)-lookup# k m = lookupCont (\_ -> (# (# #) | #)) (\v _i -> (# | v #)) (hash k) k m-{-# INLINABLE lookup# #-}--#else--lookup k m = lookupCont (\_ -> Nothing) (\v _i -> Just v) (hash k) k m-{-# INLINABLE lookup #-}-#endif---- | lookup' is a version of lookup that takes the hash separately.--- It is used to implement alterF.-lookup' :: Eq k => Hash -> k -> HashMap k v -> Maybe v-#if __GLASGOW_HASKELL__ >= 802--- GHC does not yet perform a worker-wrapper transformation on--- unboxed sums automatically. That seems likely to happen at some--- point (possibly as early as GHC 8.6) but for now we do it manually.--- lookup' would probably prefer to be implemented in terms of its own--- lookup'#, but it's not important enough and we don't want too much--- code.-lookup' h k m = case lookupRecordCollision# h k m of-  (# (# #) | #) -> Nothing-  (# | (# a, _i #) #) -> Just a-{-# INLINE lookup' #-}-#else-lookup' h k m = lookupCont (\_ -> Nothing) (\v _i -> Just v) h k m-{-# INLINABLE lookup' #-}-#endif---- The result of a lookup, keeping track of if a hash collision occured.--- If a collision did not occur then it will have the Int value (-1).-data LookupRes a = Absent | Present a !Int---- Internal helper for lookup. This version takes the precomputed hash so--- that functions that make multiple calls to lookup and related functions--- (insert, delete) only need to calculate the hash once.------ It is used by 'alterF' so that hash computation and key comparison only needs--- to be performed once. With this information you can use the more optimized--- versions of insert ('insertNewKey', 'insertKeyExists') and delete--- ('deleteKeyExists')------ Outcomes:---   Key not in map           => Absent---   Key in map, no collision => Present v (-1)---   Key in map, collision    => Present v position-lookupRecordCollision :: Eq k => Hash -> k -> HashMap k v -> LookupRes v-#if __GLASGOW_HASKELL__ >= 802-lookupRecordCollision h k m = case lookupRecordCollision# h k m of-  (# (# #) | #) -> Absent-  (# | (# a, i #) #) -> Present a (I# i) -- GHC will eliminate the I#-{-# INLINE lookupRecordCollision #-}---- Why do we produce an Int# instead of an Int? Unfortunately, GHC is not--- yet any good at unboxing things *inside* products, let alone sums. That--- may be changing in GHC 8.6 or so (there is some work in progress), but--- for now we use Int# explicitly here. We don't need to push the Int#--- into lookupCont because inlining takes care of that.-lookupRecordCollision# :: Eq k => Hash -> k -> HashMap k v -> (# (# #) | (# v, Int# #) #)-lookupRecordCollision# h k m =-    lookupCont (\_ -> (# (# #) | #)) (\v (I# i) -> (# | (# v, i #) #)) h k m--- INLINABLE to specialize to the Eq instance.-{-# INLINABLE lookupRecordCollision# #-}--#else /* GHC < 8.2 so there are no unboxed sums */--lookupRecordCollision h k m = lookupCont (\_ -> Absent) Present h k m-{-# INLINABLE lookupRecordCollision #-}-#endif---- A two-continuation version of lookupRecordCollision. This lets us--- share source code between lookup and lookupRecordCollision without--- risking any performance degradation.------ The absent continuation has type @((# #) -> r)@ instead of just @r@--- so we can be representation-polymorphic in the result type. Since--- this whole thing is always inlined, we don't have to worry about--- any extra CPS overhead.-lookupCont ::-#if __GLASGOW_HASKELL__ >= 802-  forall rep (r :: TYPE rep) k v.-#else-  forall r k v.-#endif-     Eq k-  => ((# #) -> r)    -- Absent continuation-  -> (v -> Int -> r) -- Present continuation-  -> Hash -- The hash of the key-  -> k -> HashMap k v -> r-lookupCont absent present !h0 !k0 !m0 = go h0 k0 0 m0-  where-    go :: Eq k => Hash -> k -> Int -> HashMap k v -> r-    go !_ !_ !_ Empty = absent (# #)-    go h k _ (Leaf hx (L kx x))-        | h == hx && k == kx = present x (-1)-        | otherwise          = absent (# #)-    go h k s (BitmapIndexed b v)-        | b .&. m == 0 = absent (# #)-        | otherwise    =-            go h k (s+bitsPerSubkey) (A.index v (sparseIndex b m))-      where m = mask h s-    go h k s (Full v) =-      go h k (s+bitsPerSubkey) (A.index v (index h s))-    go h k _ (Collision hx v)-        | h == hx   = lookupInArrayCont absent present k v-        | otherwise = absent (# #)-{-# INLINE lookupCont #-}---- | /O(log n)/ Return the value to which the specified key is mapped,--- or 'Nothing' if this map contains no mapping for the key.------ This is a flipped version of 'lookup'.------ @since 0.2.11-(!?) :: (Eq k, Hashable k) => HashMap k v -> k -> Maybe v-(!?) m k = lookup k m-{-# INLINE (!?) #-}----- | /O(log n)/ Return the value to which the specified key is mapped,--- or the default value if this map contains no mapping for the key.------ @since 0.2.11-findWithDefault :: (Eq k, Hashable k)-              => v          -- ^ Default value to return.-              -> k -> HashMap k v -> v-findWithDefault def k t = case lookup k t of-    Just v -> v-    _      -> def-{-# INLINABLE findWithDefault #-}----- | /O(log n)/ Return the value to which the specified key is mapped,--- or the default value if this map contains no mapping for the key.------ DEPRECATED: lookupDefault is deprecated as of version 0.2.10, replaced--- by 'findWithDefault'.-lookupDefault :: (Eq k, Hashable k)-              => v          -- ^ Default value to return.-              -> k -> HashMap k v -> v-lookupDefault def k t = findWithDefault def k t-{-# INLINE lookupDefault #-}---- | /O(log n)/ Return the value to which the specified key is mapped.--- Calls 'error' if this map contains no mapping for the key.-#if MIN_VERSION_base(4,9,0)-(!) :: (Eq k, Hashable k, HasCallStack) => HashMap k v -> k -> v-#else-(!) :: (Eq k, Hashable k) => HashMap k v -> k -> v-#endif-(!) m k = case lookup k m of-    Just v  -> v-    Nothing -> error "Data.HashMap.Base.(!): key not found"-{-# INLINABLE (!) #-}--infixl 9 !---- | Create a 'Collision' value with two 'Leaf' values.-collision :: Hash -> Leaf k v -> Leaf k v -> HashMap k v-collision h !e1 !e2 =-    let v = A.run $ do mary <- A.new 2 e1-                       A.write mary 1 e2-                       return mary-    in Collision h v-{-# INLINE collision #-}---- | Create a 'BitmapIndexed' or 'Full' node.-bitmapIndexedOrFull :: Bitmap -> A.Array (HashMap k v) -> HashMap k v-bitmapIndexedOrFull b ary-    | b == fullNodeMask = Full ary-    | otherwise         = BitmapIndexed b ary-{-# INLINE bitmapIndexedOrFull #-}---- | /O(log n)/ Associate the specified value with the specified--- key in this map.  If this map previously contained a mapping for--- the key, the old value is replaced.-insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v-insert k v m = insert' (hash k) k v m-{-# INLINABLE insert #-}--insert' :: Eq k => Hash -> k -> v -> HashMap k v -> HashMap k v-insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0-  where-    go !h !k x !_ Empty = Leaf h (L k x)-    go h k x s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then if x `ptrEq` y-                         then t-                         else Leaf h (L k x)-                    else collision h l (L k x)-        | otherwise = runST (two s h k x hy t)-    go h k x s t@(BitmapIndexed b ary)-        | b .&. m == 0 =-            let !ary' = A.insert ary i $! Leaf h (L k x)-            in bitmapIndexedOrFull (b .|. m) ary'-        | otherwise =-            let !st  = A.index ary i-                !st' = go h k x (s+bitsPerSubkey) st-            in if st' `ptrEq` st-               then t-               else BitmapIndexed b (A.update ary i st')-      where m = mask h s-            i = sparseIndex b m-    go h k x s t@(Full ary) =-        let !st  = A.index ary i-            !st' = go h k x (s+bitsPerSubkey) st-        in if st' `ptrEq` st-            then t-            else Full (update16 ary i st')-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v)-        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE insert' #-}---- Insert optimized for the case when we know the key is not in the map.------ It is only valid to call this when the key does not exist in the map.------ We can skip:---  - the key equality check on a Leaf---  - check for its existence in the array for a hash collision-insertNewKey :: Hash -> k -> v -> HashMap k v -> HashMap k v-insertNewKey !h0 !k0 x0 !m0 = go h0 k0 x0 0 m0-  where-    go !h !k x !_ Empty = Leaf h (L k x)-    go h k x s t@(Leaf hy l)-      | hy == h = collision h l (L k x)-      | otherwise = runST (two s h k x hy t)-    go h k x s (BitmapIndexed b ary)-        | b .&. m == 0 =-            let !ary' = A.insert ary i $! Leaf h (L k x)-            in bitmapIndexedOrFull (b .|. m) ary'-        | otherwise =-            let !st  = A.index ary i-                !st' = go h k x (s+bitsPerSubkey) st-            in BitmapIndexed b (A.update ary i st')-      where m = mask h s-            i = sparseIndex b m-    go h k x s (Full ary) =-        let !st  = A.index ary i-            !st' = go h k x (s+bitsPerSubkey) st-        in Full (update16 ary i st')-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = Collision h (snocNewLeaf (L k x) v)-        | otherwise =-            go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-      where-        snocNewLeaf :: Leaf k v -> A.Array (Leaf k v) -> A.Array (Leaf k v)-        snocNewLeaf leaf ary = A.run $ do-          let n = A.length ary-          mary <- A.new_ (n + 1)-          A.copy ary 0 mary 0 n-          A.write mary n leaf-          return mary-{-# NOINLINE insertNewKey #-}----- Insert optimized for the case when we know the key is in the map.------ It is only valid to call this when the key exists in the map and you know the--- hash collision position if there was one. This information can be obtained--- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos--- (first argument).------ We can skip the key equality check on a Leaf because we know the leaf must be--- for this key.-insertKeyExists :: Int -> Hash -> k -> v -> HashMap k v -> HashMap k v-insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 0 m0-  where-    go !_collPos !h !k x !_s (Leaf _hy _kx)-        = Leaf h (L k x)-    go collPos h k x s (BitmapIndexed b ary)-        | b .&. m == 0 =-            let !ary' = A.insert ary i $ Leaf h (L k x)-            in bitmapIndexedOrFull (b .|. m) ary'-        | otherwise =-            let !st  = A.index ary i-                !st' = go collPos h k x (s+bitsPerSubkey) st-            in BitmapIndexed b (A.update ary i st')-      where m = mask h s-            i = sparseIndex b m-    go collPos h k x s (Full ary) =-        let !st  = A.index ary i-            !st' = go collPos h k x (s+bitsPerSubkey) st-        in Full (update16 ary i st')-      where i = index h s-    go collPos h k x _s (Collision _hy v)-        | collPos >= 0 = Collision h (setAtPosition collPos k x v)-        | otherwise = Empty -- error "Internal error: go {collPos negative}"-    go _ _ _ _ _ Empty = Empty -- error "Internal error: go Empty"--{-# NOINLINE insertKeyExists #-}---- Replace the ith Leaf with Leaf k v.------ This does not check that @i@ is within bounds of the array.-setAtPosition :: Int -> k -> v -> A.Array (Leaf k v) -> A.Array (Leaf k v)-setAtPosition i k x ary = A.update ary i (L k x)-{-# INLINE setAtPosition #-}----- | In-place update version of insert-unsafeInsert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v-unsafeInsert k0 v0 m0 = runST (go h0 k0 v0 0 m0)-  where-    h0 = hash k0-    go !h !k x !_ Empty = return $! Leaf h (L k x)-    go h k x s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then if x `ptrEq` y-                         then return t-                         else return $! Leaf h (L k x)-                    else return $! collision h l (L k x)-        | otherwise = two s h k x hy t-    go h k x s t@(BitmapIndexed b ary)-        | b .&. m == 0 = do-            ary' <- A.insertM ary i $! Leaf h (L k x)-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.indexM ary i-            st' <- go h k x (s+bitsPerSubkey) st-            A.unsafeUpdateM ary i st'-            return t-      where m = mask h s-            i = sparseIndex b m-    go h k x s t@(Full ary) = do-        st <- A.indexM ary i-        st' <- go h k x (s+bitsPerSubkey) st-        A.unsafeUpdateM ary i st'-        return t-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v)-        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE unsafeInsert #-}---- | Create a map from two key-value pairs which hashes don't collide. To--- enhance sharing, the second key-value pair is represented by the hash of its--- key and a singleton HashMap pairing its key with its value.------ Note: to avoid silly thunks, this function must be strict in the--- key. See issue #232. We don't need to force the HashMap argument--- because it's already in WHNF (having just been matched) and we--- just put it directly in an array.-two :: Shift -> Hash -> k -> v -> Hash -> HashMap k v -> ST s (HashMap k v)-two = go-  where-    go s h1 k1 v1 h2 t2-        | bp1 == bp2 = do-            st <- go (s+bitsPerSubkey) h1 k1 v1 h2 t2-            ary <- A.singletonM st-            return $ BitmapIndexed bp1 ary-        | otherwise  = do-            mary <- A.new 2 $! Leaf h1 (L k1 v1)-            A.write mary idx2 t2-            ary <- A.unsafeFreeze mary-            return $ BitmapIndexed (bp1 .|. bp2) ary-      where-        bp1  = mask h1 s-        bp2  = mask h2 s-        idx2 | index h1 s < index h2 s = 1-             | otherwise               = 0-{-# INLINE two #-}---- | /O(log n)/ Associate the value with the key in this map.  If--- this map previously contained a mapping for the key, the old value--- is replaced by the result of applying the given function to the new--- and old value.  Example:------ > insertWith f k v map--- >   where f new old = new + old-insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v-            -> HashMap k v--- We're not going to worry about allocating a function closure--- to pass to insertModifying. See comments at 'adjust'.-insertWith f k new m = insertModifying new (\old -> (# f new old #)) k m-{-# INLINE insertWith #-}---- | @insertModifying@ is a lot like insertWith; we use it to implement alterF.--- It takes a value to insert when the key is absent and a function--- to apply to calculate a new value when the key is present. Thanks--- to the unboxed unary tuple, we avoid introducing any unnecessary--- thunks in the tree.-insertModifying :: (Eq k, Hashable k) => v -> (v -> (# v #)) -> k -> HashMap k v-            -> HashMap k v-insertModifying x f k0 m0 = go h0 k0 0 m0-  where-    !h0 = hash k0-    go !h !k !_ Empty = Leaf h (L k x)-    go h k s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then case f y of-                      (# v' #) | ptrEq y v' -> t-                               | otherwise -> Leaf h (L k (v'))-                    else collision h l (L k x)-        | otherwise = runST (two s h k x hy t)-    go h k s t@(BitmapIndexed b ary)-        | b .&. m == 0 =-            let ary' = A.insert ary i $! Leaf h (L k x)-            in bitmapIndexedOrFull (b .|. m) ary'-        | otherwise =-            let !st   = A.index ary i-                !st'  = go h k (s+bitsPerSubkey) st-                ary'  = A.update ary i $! st'-            in if ptrEq st st'-               then t-               else BitmapIndexed b ary'-      where m = mask h s-            i = sparseIndex b m-    go h k s t@(Full ary) =-        let !st   = A.index ary i-            !st'  = go h k (s+bitsPerSubkey) st-            ary' = update16 ary i $! st'-        in if ptrEq st st'-           then t-           else Full ary'-      where i = index h s-    go h k s t@(Collision hy v)-        | h == hy   =-            let !v' = insertModifyingArr x f k v-            in if A.unsafeSameArray v v'-               then t-               else Collision h v'-        | otherwise = go h k s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE insertModifying #-}---- Like insertModifying for arrays; used to implement insertModifying-insertModifyingArr :: Eq k => v -> (v -> (# v #)) -> k -> A.Array (Leaf k v)-                 -> A.Array (Leaf k v)-insertModifyingArr x f k0 ary0 = go k0 ary0 0 (A.length ary0)-  where-    go !k !ary !i !n-        | i >= n = A.run $ do-            -- Not found, append to the end.-            mary <- A.new_ (n + 1)-            A.copy ary 0 mary 0 n-            A.write mary n (L k x)-            return mary-        | otherwise = case A.index ary i of-            (L kx y) | k == kx   -> case f y of-                                      (# y' #) -> if ptrEq y y'-                                                  then ary-                                                  else A.update ary i (L k y')-                     | otherwise -> go k ary (i+1) n-{-# INLINE insertModifyingArr #-}---- | In-place update version of insertWith-unsafeInsertWith :: forall k v. (Eq k, Hashable k)-                 => (v -> v -> v) -> k -> v -> HashMap k v-                 -> HashMap k v-unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0-{-# INLINABLE unsafeInsertWith #-}--unsafeInsertWithKey :: forall k v. (Eq k, Hashable k)-                 => (k -> v -> v -> v) -> k -> v -> HashMap k v-                 -> HashMap k v-unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)-  where-    h0 = hash k0-    go :: Hash -> k -> v -> Shift -> HashMap k v -> ST s (HashMap k v)-    go !h !k x !_ Empty = return $! Leaf h (L k x)-    go h k x s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then return $! Leaf h (L k (f k x y))-                    else return $! collision h l (L k x)-        | otherwise = two s h k x hy t-    go h k x s t@(BitmapIndexed b ary)-        | b .&. m == 0 = do-            ary' <- A.insertM ary i $! Leaf h (L k x)-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.indexM ary i-            st' <- go h k x (s+bitsPerSubkey) st-            A.unsafeUpdateM ary i st'-            return t-      where m = mask h s-            i = sparseIndex b m-    go h k x s t@(Full ary) = do-        st <- A.indexM ary i-        st' <- go h k x (s+bitsPerSubkey) st-        A.unsafeUpdateM ary i st'-        return t-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWithKey (\key a b -> (# f key a b #) ) k x v)-        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE unsafeInsertWithKey #-}---- | /O(log n)/ Remove the mapping for the specified key from this map--- if present.-delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v-delete k m = delete' (hash k) k m-{-# INLINABLE delete #-}--delete' :: Eq k => Hash -> k -> HashMap k v -> HashMap k v-delete' h0 k0 m0 = go h0 k0 0 m0-  where-    go !_ !_ !_ Empty = Empty-    go h k _ t@(Leaf hy (L ky _))-        | hy == h && ky == k = Empty-        | otherwise          = t-    go h k s t@(BitmapIndexed b ary)-        | b .&. m == 0 = t-        | otherwise =-            let !st = A.index ary i-                !st' = go h k (s+bitsPerSubkey) st-            in if st' `ptrEq` st-                then t-                else case st' of-                Empty | A.length ary == 1 -> Empty-                      | A.length ary == 2 ->-                          case (i, A.index ary 0, A.index ary 1) of-                          (0, _, l) | isLeafOrCollision l -> l-                          (1, l, _) | isLeafOrCollision l -> l-                          _                               -> bIndexed-                      | otherwise -> bIndexed-                    where-                      bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)-                l | isLeafOrCollision l && A.length ary == 1 -> l-                _ -> BitmapIndexed b (A.update ary i st')-      where m = mask h s-            i = sparseIndex b m-    go h k s t@(Full ary) =-        let !st   = A.index ary i-            !st' = go h k (s+bitsPerSubkey) st-        in if st' `ptrEq` st-            then t-            else case st' of-            Empty ->-                let ary' = A.delete ary i-                    bm   = fullNodeMask .&. complement (1 `unsafeShiftL` i)-                in BitmapIndexed bm ary'-            _ -> Full (A.update ary i st')-      where i = index h s-    go h k _ t@(Collision hy v)-        | h == hy = case indexOf k v of-            Just i-                | A.length v == 2 ->-                    if i == 0-                    then Leaf h (A.index v 1)-                    else Leaf h (A.index v 0)-                | otherwise -> Collision h (A.delete v i)-            Nothing -> t-        | otherwise = t-{-# INLINABLE delete' #-}---- | Delete optimized for the case when we know the key is in the map.------ It is only valid to call this when the key exists in the map and you know the--- hash collision position if there was one. This information can be obtained--- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos.------ We can skip:---  - the key equality check on the leaf, if we reach a leaf it must be the key-deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v-deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 0 m0-  where-    go :: Int -> Hash -> k -> Int -> HashMap k v -> HashMap k v-    go !_collPos !_h !_k !_s (Leaf _ _) = Empty-    go collPos h k s (BitmapIndexed b ary) =-            let !st = A.index ary i-                !st' = go collPos h k (s+bitsPerSubkey) st-            in case st' of-                Empty | A.length ary == 1 -> Empty-                      | A.length ary == 2 ->-                          case (i, A.index ary 0, A.index ary 1) of-                          (0, _, l) | isLeafOrCollision l -> l-                          (1, l, _) | isLeafOrCollision l -> l-                          _                               -> bIndexed-                      | otherwise -> bIndexed-                    where-                      bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)-                l | isLeafOrCollision l && A.length ary == 1 -> l-                _ -> BitmapIndexed b (A.update ary i st')-      where m = mask h s-            i = sparseIndex b m-    go collPos h k s (Full ary) =-        let !st   = A.index ary i-            !st' = go collPos h k (s+bitsPerSubkey) st-        in case st' of-            Empty ->-                let ary' = A.delete ary i-                    bm   = fullNodeMask .&. complement (1 `unsafeShiftL` i)-                in BitmapIndexed bm ary'-            _ -> Full (A.update ary i st')-      where i = index h s-    go collPos h _ _ (Collision _hy v)-      | A.length v == 2-      = if collPos == 0-        then Leaf h (A.index v 1)-        else Leaf h (A.index v 0)-      | otherwise = Collision h (A.delete v collPos)-    go !_ !_ !_ !_ Empty = Empty -- error "Internal error: deleteKeyExists empty"-{-# NOINLINE deleteKeyExists #-}---- | /O(log n)/ Adjust the value tied to a given key in this map only--- if it is present. Otherwise, leave the map alone.-adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v--- This operation really likes to leak memory, so using this--- indirect implementation shouldn't hurt much. Furthermore, it allows--- GHC to avoid a leak when the function is lazy. In particular,------     adjust (const x) k m--- ==> adjust# (\v -> (# const x v #)) k m--- ==> adjust# (\_ -> (# x #)) k m-adjust f k m = adjust# (\v -> (# f v #)) k m-{-# INLINE adjust #-}---- | Much like 'adjust', but not inherently leaky.-adjust# :: (Eq k, Hashable k) => (v -> (# v #)) -> k -> HashMap k v -> HashMap k v-adjust# f k0 m0 = go h0 k0 0 m0-  where-    h0 = hash k0-    go !_ !_ !_ Empty = Empty-    go h k _ t@(Leaf hy (L ky y))-        | hy == h && ky == k = case f y of-            (# y' #) | ptrEq y y' -> t-                     | otherwise -> Leaf h (L k y')-        | otherwise          = t-    go h k s t@(BitmapIndexed b ary)-        | b .&. m == 0 = t-        | otherwise = let !st   = A.index ary i-                          !st'  = go h k (s+bitsPerSubkey) st-                          ary' = A.update ary i $! st'-                      in if ptrEq st st'-                         then t-                         else BitmapIndexed b ary'-      where m = mask h s-            i = sparseIndex b m-    go h k s t@(Full ary) =-        let i    = index h s-            !st   = A.index ary i-            !st'  = go h k (s+bitsPerSubkey) st-            ary' = update16 ary i $! st'-        in if ptrEq st st'-           then t-           else Full ary'-    go h k _ t@(Collision hy v)-        | h == hy   = let !v' = updateWith# f k v-                      in if A.unsafeSameArray v v'-                         then t-                         else Collision h v'-        | otherwise = t-{-# INLINABLE adjust# #-}---- | /O(log n)/  The expression @('update' f k map)@ updates the value @x@ at @k@--- (if it is in the map). If @(f x)@ is 'Nothing', the element is deleted.--- If it is @('Just' y)@, the key @k@ is bound to the new value @y@.-update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a-update f = alter (>>= f)-{-# INLINABLE update #-}----- | /O(log n)/  The expression (@'alter' f k map@) alters the value @x@ at @k@, or--- absence thereof. @alter@ can be used to insert, delete, or update a value in a--- map. In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@.-alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v--- TODO(m-renaud): Consider using specialized insert and delete for alter.-alter f k m =-  case f (lookup k m) of-    Nothing -> delete k m-    Just v  -> insert k v m-{-# INLINABLE alter #-}---- | /O(log n)/  The expression (@'alterF' f k map@) alters the value @x@ at--- @k@, or absence thereof. @alterF@ can be used to insert, delete, or update--- a value in a map.------ Note: 'alterF' is a flipped version of the 'at' combinator from--- <https://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-At.html#v:at Control.Lens.At>.------ @since 0.2.10-alterF :: (Functor f, Eq k, Hashable k)-       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)--- We only calculate the hash once, but unless this is rewritten--- by rules we may test for key equality multiple times.--- We force the value of the map for consistency with the rewritten--- version; otherwise someone could tell the difference using a lazy--- @f@ and a functor that is similar to Const but not actually Const.-alterF f = \ !k !m ->-  let-    !h = hash k-    mv = lookup' h k m-  in (<$> f mv) $ \fres ->-    case fres of-      Nothing -> delete' h k m-      Just v' -> insert' h k v' m---- We unconditionally rewrite alterF in RULES, but we expose an--- unfolding just in case it's used in some way that prevents the--- rule from firing.-{-# INLINABLE [0] alterF #-}--#if MIN_VERSION_base(4,8,0)--- This is just a bottom value. See the comment on the "alterFWeird"--- rule.-test_bottom :: a-test_bottom = error "Data.HashMap.alterF internal error: hit test_bottom"---- We use this as an error result in RULES to ensure we don't get--- any useless CallStack nonsense.-bogus# :: (# #) -> (# a #)-bogus# _ = error "Data.HashMap.alterF internal error: hit bogus#"--{-# RULES--- We probe the behavior of @f@ by applying it to Nothing and to--- Just test_bottom. Based on the results, and how they relate to--- each other, we choose the best implementation.--"alterFWeird" forall f. alterF f =-   alterFWeird (f Nothing) (f (Just test_bottom)) f---- This rule covers situations where alterF is used to simply insert or--- delete in Identity (most likely via Control.Lens.At). We recognize here--- (through the repeated @x@ on the LHS) that------ @f Nothing = f (Just bottom)@,------ which guarantees that @f@ doesn't care what its argument is, so--- we don't have to either.------ Why only Identity? A variant of this rule is actually valid regardless of--- the functor, but for some functors (e.g., []), it can lead to the--- same keys being compared multiple times, which is bad if they're--- ugly things like strings. This is unfortunate, since the rule is likely--- a good idea for almost all realistic uses, but I don't like nasty--- edge cases.-"alterFconstant" forall (f :: Maybe a -> Identity (Maybe a)) x.-  alterFWeird x x f = \ !k !m ->-    Identity (case runIdentity x of {Nothing -> delete k m; Just a -> insert k a m})---- This rule handles the case where 'alterF' is used to do 'insertWith'-like--- things. Whenever possible, GHC will get rid of the Maybe nonsense for us.--- We delay this rule to stage 1 so alterFconstant has a chance to fire.-"alterFinsertWith" [1] forall (f :: Maybe a -> Identity (Maybe a)) x y.-  alterFWeird (coerce (Just x)) (coerce (Just y)) f =-    coerce (insertModifying x (\mold -> case runIdentity (f (Just mold)) of-                                            Nothing -> bogus# (# #)-                                            Just new -> (# new #)))---- Handle the case where someone uses 'alterF' instead of 'adjust'. This--- rule is kind of picky; it will only work if the function doesn't--- do anything between case matching on the Maybe and producing a result.-"alterFadjust" forall (f :: Maybe a -> Identity (Maybe a)) _y.-  alterFWeird (coerce Nothing) (coerce (Just _y)) f =-    coerce (adjust# (\x -> case runIdentity (f (Just x)) of-                               Just x' -> (# x' #)-                               Nothing -> bogus# (# #)))---- The simple specialization to Const; in this case we can look up--- the key without caring what position it's in. This is only a tiny--- optimization.-"alterFlookup" forall _ign1 _ign2 (f :: Maybe a -> Const r (Maybe a)).-  alterFWeird _ign1 _ign2 f = \ !k !m -> Const (getConst (f (lookup k m)))- #-}---- This is a very unsafe version of alterF used for RULES. When calling--- alterFWeird x y f, the following *must* hold:------ x = f Nothing--- y = f (Just _|_)------ Failure to abide by these laws will make demons come out of your nose.-alterFWeird-       :: (Functor f, Eq k, Hashable k)-       => f (Maybe v)-       -> f (Maybe v)-       -> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)-alterFWeird _ _ f = alterFEager f-{-# INLINE [0] alterFWeird #-}---- | This is the default version of alterF that we use in most non-trivial--- cases. It's called "eager" because it looks up the given key in the map--- eagerly, whether or not the given function requires that information.-alterFEager :: (Functor f, Eq k, Hashable k)-       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)-alterFEager f !k m = (<$> f mv) $ \fres ->-  case fres of--    -------------------------------    -- Delete the key from the map.-    Nothing -> case lookupRes of--      -- Key did not exist in the map to begin with, no-op-      Absent -> m--      -- Key did exist-      Present _ collPos -> deleteKeyExists collPos h k m--    -------------------------------    -- Update value-    Just v' -> case lookupRes of--      -- Key did not exist before, insert v' under a new key-      Absent -> insertNewKey h k v' m--      -- Key existed before-      Present v collPos ->-        if v `ptrEq` v'-        -- If the value is identical, no-op-        then m-        -- If the value changed, update the value.-        else insertKeyExists collPos h k v' m--  where !h = hash k-        !lookupRes = lookupRecordCollision h k m-        !mv = case lookupRes of-           Absent -> Nothing-           Present v _ -> Just v-{-# INLINABLE alterFEager #-}-#endif------------------------------------------------------------------------------ * Combine---- | /O(n+m)/ The union of two maps. If a key occurs in both maps, the--- mapping from the first will be the mapping in the result.------ ==== __Examples__------ >>> union (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])--- fromList [(1,'a'),(2,'b'),(3,'d')]-union :: (Eq k, Hashable k) => HashMap k v -> HashMap k v -> HashMap k v-union = unionWith const-{-# INLINABLE union #-}---- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,--- the provided function (first argument) will be used to compute the--- result.-unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v-          -> HashMap k v-unionWith f = unionWithKey (const f)-{-# INLINE unionWith #-}---- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,--- the provided function (first argument) will be used to compute the--- result.-unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v-          -> HashMap k v-unionWithKey f = go 0-  where-    -- empty vs. anything-    go !_ t1 Empty = t1-    go _ Empty t2 = t2-    -- leaf vs. leaf-    go s t1@(Leaf h1 l1@(L k1 v1)) t2@(Leaf h2 l2@(L k2 v2))-        | h1 == h2  = if k1 == k2-                      then Leaf h1 (L k1 (f k1 v1 v2))-                      else collision h1 l1 l2-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Leaf h1 (L k1 v1)) t2@(Collision h2 ls2)-        | h1 == h2  = Collision h1 (updateOrSnocWithKey (\k a b -> (# f k a b #)) k1 v1 ls2)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Collision h1 ls1) t2@(Leaf h2 (L k2 v2))-        | h1 == h2  = Collision h1 (updateOrSnocWithKey (\k a b -> (# f k b a #)) k2 v2 ls1)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Collision h1 ls1) t2@(Collision h2 ls2)-        | h1 == h2  = Collision h1 (updateOrConcatWithKey f ls1 ls2)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    -- branch vs. branch-    go s (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =-        let b'   = b1 .|. b2-            ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 b2 ary1 ary2-        in bitmapIndexedOrFull b' ary'-    go s (BitmapIndexed b1 ary1) (Full ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 fullNodeMask ary1 ary2-        in Full ary'-    go s (Full ary1) (BitmapIndexed b2 ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask b2 ary1 ary2-        in Full ary'-    go s (Full ary1) (Full ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask fullNodeMask-                   ary1 ary2-        in Full ary'-    -- leaf vs. branch-    go s (BitmapIndexed b1 ary1) t2-        | b1 .&. m2 == 0 = let ary' = A.insert ary1 i t2-                               b'   = b1 .|. m2-                           in bitmapIndexedOrFull b' ary'-        | otherwise      = let ary' = A.updateWith' ary1 i $ \st1 ->-                                   go (s+bitsPerSubkey) st1 t2-                           in BitmapIndexed b1 ary'-        where-          h2 = leafHashCode t2-          m2 = mask h2 s-          i = sparseIndex b1 m2-    go s t1 (BitmapIndexed b2 ary2)-        | b2 .&. m1 == 0 = let ary' = A.insert ary2 i $! t1-                               b'   = b2 .|. m1-                           in bitmapIndexedOrFull b' ary'-        | otherwise      = let ary' = A.updateWith' ary2 i $ \st2 ->-                                   go (s+bitsPerSubkey) t1 st2-                           in BitmapIndexed b2 ary'-      where-        h1 = leafHashCode t1-        m1 = mask h1 s-        i = sparseIndex b2 m1-    go s (Full ary1) t2 =-        let h2   = leafHashCode t2-            i    = index h2 s-            ary' = update16With' ary1 i $ \st1 -> go (s+bitsPerSubkey) st1 t2-        in Full ary'-    go s t1 (Full ary2) =-        let h1   = leafHashCode t1-            i    = index h1 s-            ary' = update16With' ary2 i $ \st2 -> go (s+bitsPerSubkey) t1 st2-        in Full ary'--    leafHashCode (Leaf h _) = h-    leafHashCode (Collision h _) = h-    leafHashCode _ = error "leafHashCode"--    goDifferentHash s h1 h2 t1 t2-        | m1 == m2  = BitmapIndexed m1 (A.singleton $! go (s+bitsPerSubkey) t1 t2)-        | m1 <  m2  = BitmapIndexed (m1 .|. m2) (A.pair t1 t2)-        | otherwise = BitmapIndexed (m1 .|. m2) (A.pair t2 t1)-      where-        m1 = mask h1 s-        m2 = mask h2 s-{-# INLINE unionWithKey #-}---- | Strict in the result of @f@.-unionArrayBy :: (a -> a -> a) -> Bitmap -> Bitmap -> A.Array a -> A.Array a-             -> A.Array a-unionArrayBy f b1 b2 ary1 ary2 = A.run $ do-    let b' = b1 .|. b2-    mary <- A.new_ (popCount b')-    -- iterate over nonzero bits of b1 .|. b2-    -- it would be nice if we could shift m by more than 1 each time-    let ba = b1 .&. b2-        go !i !i1 !i2 !m-            | m > b'        = return ()-            | b' .&. m == 0 = go i i1 i2 (m `unsafeShiftL` 1)-            | ba .&. m /= 0 = do-                x1 <- A.indexM ary1 i1-                x2 <- A.indexM ary2 i2-                A.write mary i $! f x1 x2-                go (i+1) (i1+1) (i2+1) (m `unsafeShiftL` 1)-            | b1 .&. m /= 0 = do-                A.write mary i =<< A.indexM ary1 i1-                go (i+1) (i1+1) (i2  ) (m `unsafeShiftL` 1)-            | otherwise     = do-                A.write mary i =<< A.indexM ary2 i2-                go (i+1) (i1  ) (i2+1) (m `unsafeShiftL` 1)-    go 0 0 0 (b' .&. negate b') -- XXX: b' must be non-zero-    return mary-    -- TODO: For the case where b1 .&. b2 == b1, i.e. when one is a-    -- subset of the other, we could use a slightly simpler algorithm,-    -- where we copy one array, and then update.-{-# INLINE unionArrayBy #-}---- TODO: Figure out the time complexity of 'unions'.---- | Construct a set containing all elements from a list of sets.-unions :: (Eq k, Hashable k) => [HashMap k v] -> HashMap k v-unions = L.foldl' union empty-{-# INLINE unions #-}----------------------------------------------------------------------------- * Transformations---- | /O(n)/ Transform this map by applying a function to every value.-mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2-mapWithKey f = go-  where-    go Empty = Empty-    go (Leaf h (L k v)) = Leaf h $ L k (f k v)-    go (BitmapIndexed b ary) = BitmapIndexed b $ A.map go ary-    go (Full ary) = Full $ A.map go ary-    -- Why map strictly over collision arrays? Because there's no-    -- point suspending the O(1) work this does for each leaf.-    go (Collision h ary) = Collision h $-                           A.map' (\ (L k v) -> L k (f k v)) ary-{-# INLINE mapWithKey #-}---- | /O(n)/ Transform this map by applying a function to every value.-map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2-map f = mapWithKey (const f)-{-# INLINE map #-}---- TODO: We should be able to use mutation to create the new--- 'HashMap'.---- | /O(n)/ Perform an 'Applicative' action for each key-value pair--- in a 'HashMap' and produce a 'HashMap' of all the results.------ Note: the order in which the actions occur is unspecified. In particular,--- when the map contains hash collisions, the order in which the actions--- associated with the keys involved will depend in an unspecified way on--- their insertion order.-traverseWithKey-  :: Applicative f-  => (k -> v1 -> f v2)-  -> HashMap k v1 -> f (HashMap k v2)-traverseWithKey f = go-  where-    go Empty                 = pure Empty-    go (Leaf h (L k v))      = Leaf h . L k <$> f k v-    go (BitmapIndexed b ary) = BitmapIndexed b <$> A.traverse go ary-    go (Full ary)            = Full <$> A.traverse go ary-    go (Collision h ary)     =-        Collision h <$> A.traverse' (\ (L k v) -> L k <$> f k v) ary-{-# INLINE traverseWithKey #-}----------------------------------------------------------------------------- * Difference and intersection---- | /O(n*log m)/ Difference of two maps. Return elements of the first map--- not existing in the second.-difference :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v-difference a b = foldlWithKey' go empty a-  where-    go m k v = case lookup k b of-                 Nothing -> insert k v m-                 _       -> m-{-# INLINABLE difference #-}---- | /O(n*log m)/ Difference with a combining function. When two equal keys are--- encountered, the combining function is applied to the values of these keys.--- If it returns 'Nothing', the element is discarded (proper set difference). If--- it returns (@'Just' y@), the element is updated with a new value @y@.-differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v-differenceWith f a b = foldlWithKey' go empty a-  where-    go m k v = case lookup k b of-                 Nothing -> insert k v m-                 Just w  -> maybe m (\y -> insert k y m) (f v w)-{-# INLINABLE differenceWith #-}---- | /O(n*log m)/ Intersection of two maps. Return elements of the first--- map for keys existing in the second.-intersection :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v-intersection a b = foldlWithKey' go empty a-  where-    go m k v = case lookup k b of-                 Just _ -> insert k v m-                 _      -> m-{-# INLINABLE intersection #-}---- | /O(n*log m)/ Intersection of two maps. If a key occurs in both maps--- the provided function is used to combine the values from the two--- maps.-intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1-                 -> HashMap k v2 -> HashMap k v3-intersectionWith f a b = foldlWithKey' go empty a-  where-    go m k v = case lookup k b of-                 Just w -> insert k (f v w) m-                 _      -> m-{-# INLINABLE intersectionWith #-}---- | /O(n*log m)/ Intersection of two maps. If a key occurs in both maps--- the provided function is used to combine the values from the two--- maps.-intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)-                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3-intersectionWithKey f a b = foldlWithKey' go empty a-  where-    go m k v = case lookup k b of-                 Just w -> insert k (f k v w) m-                 _      -> m-{-# INLINABLE intersectionWithKey #-}----------------------------------------------------------------------------- * Folds---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).  Each application of the operator--- is evaluated before using the result in the next application.--- This function is strict in the starting value.-foldl' :: (a -> v -> a) -> a -> HashMap k v -> a-foldl' f = foldlWithKey' (\ z _ v -> f z v)-{-# INLINE foldl' #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator).  Each application of the operator--- is evaluated before using the result in the next application.--- This function is strict in the starting value.-foldr' :: (v -> a -> a) -> a -> HashMap k v -> a-foldr' f = foldrWithKey' (\ _ v z -> f v z)-{-# INLINE foldr' #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).  Each application of the operator--- is evaluated before using the result in the next application.--- This function is strict in the starting value.-foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a-foldlWithKey' f = go-  where-    go !z Empty                = z-    go z (Leaf _ (L k v))      = f z k v-    go z (BitmapIndexed _ ary) = A.foldl' go z ary-    go z (Full ary)            = A.foldl' go z ary-    go z (Collision _ ary)     = A.foldl' (\ z' (L k v) -> f z' k v) z ary-{-# INLINE foldlWithKey' #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator).  Each application of the operator--- is evaluated before using the result in the next application.--- This function is strict in the starting value.-foldrWithKey' :: (k -> v -> a -> a) -> a -> HashMap k v -> a-foldrWithKey' f = flip go-  where-    go Empty z                 = z-    go (Leaf _ (L k v)) !z     = f k v z-    go (BitmapIndexed _ ary) !z = A.foldr' go z ary-    go (Full ary) !z           = A.foldr' go z ary-    go (Collision _ ary) !z    = A.foldr' (\ (L k v) z' -> f k v z') z ary-{-# INLINE foldrWithKey' #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator).-foldr :: (v -> a -> a) -> a -> HashMap k v -> a-foldr f = foldrWithKey (const f)-{-# INLINE foldr #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).-foldl :: (a -> v -> a) -> a -> HashMap k v -> a-foldl f = foldlWithKey (\a _k v -> f a v)-{-# INLINE foldl #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator).-foldrWithKey :: (k -> v -> a -> a) -> a -> HashMap k v -> a-foldrWithKey f = flip go-  where-    go Empty z                 = z-    go (Leaf _ (L k v)) z      = f k v z-    go (BitmapIndexed _ ary) z = A.foldr go z ary-    go (Full ary) z            = A.foldr go z ary-    go (Collision _ ary) z     = A.foldr (\ (L k v) z' -> f k v z') z ary-{-# INLINE foldrWithKey #-}---- | /O(n)/ Reduce this map by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).-foldlWithKey :: (a -> k -> v -> a) -> a -> HashMap k v -> a-foldlWithKey f = go-  where-    go z Empty                 = z-    go z (Leaf _ (L k v))      = f z k v-    go z (BitmapIndexed _ ary) = A.foldl go z ary-    go z (Full ary)            = A.foldl go z ary-    go z (Collision _ ary)     = A.foldl (\ z' (L k v) -> f z' k v) z ary-{-# INLINE foldlWithKey #-}---- | /O(n)/ Reduce the map by applying a function to each element--- and combining the results with a monoid operation.-foldMapWithKey :: Monoid m => (k -> v -> m) -> HashMap k v -> m-foldMapWithKey f = go-  where-    go Empty = mempty-    go (Leaf _ (L k v)) = f k v-    go (BitmapIndexed _ ary) = A.foldMap go ary-    go (Full ary) = A.foldMap go ary-    go (Collision _ ary) = A.foldMap (\ (L k v) -> f k v) ary-{-# INLINE foldMapWithKey #-}----------------------------------------------------------------------------- * Filter---- | /O(n)/ Transform this map by applying a function to every value---   and retaining only some of them.-mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2-mapMaybeWithKey f = filterMapAux onLeaf onColl-  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (Leaf h (L k v'))-        onLeaf _ = Nothing--        onColl (L k v) | Just v' <- f k v = Just (L k v')-                       | otherwise = Nothing-{-# INLINE mapMaybeWithKey #-}---- | /O(n)/ Transform this map by applying a function to every value---   and retaining only some of them.-mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2-mapMaybe f = mapMaybeWithKey (const f)-{-# INLINE mapMaybe #-}---- | /O(n)/ Filter this map by retaining only elements satisfying a--- predicate.-filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v-filterWithKey pred = filterMapAux onLeaf onColl-  where onLeaf t@(Leaf _ (L k v)) | pred k v = Just t-        onLeaf _ = Nothing--        onColl el@(L k v) | pred k v = Just el-        onColl _ = Nothing-{-# INLINE filterWithKey #-}----- | Common implementation for 'filterWithKey' and 'mapMaybeWithKey',---   allowing the former to former to reuse terms.-filterMapAux :: forall k v1 v2-              . (HashMap k v1 -> Maybe (HashMap k v2))-             -> (Leaf k v1 -> Maybe (Leaf k v2))-             -> HashMap k v1-             -> HashMap k v2-filterMapAux onLeaf onColl = go-  where-    go Empty = Empty-    go t@Leaf{}-        | Just t' <- onLeaf t = t'-        | otherwise = Empty-    go (BitmapIndexed b ary) = filterA ary b-    go (Full ary) = filterA ary fullNodeMask-    go (Collision h ary) = filterC ary h--    filterA ary0 b0 =-        let !n = A.length ary0-        in runST $ do-            mary <- A.new_ n-            step ary0 mary b0 0 0 1 n-      where-        step :: A.Array (HashMap k v1) -> A.MArray s (HashMap k v2)-             -> Bitmap -> Int -> Int -> Bitmap -> Int-             -> ST s (HashMap k v2)-        step !ary !mary !b i !j !bi n-            | i >= n = case j of-                0 -> return Empty-                1 -> do-                    ch <- A.read mary 0-                    case ch of-                      t | isLeafOrCollision t -> return t-                      _                       -> BitmapIndexed b <$> A.trim mary 1-                _ -> do-                    ary2 <- A.trim mary j-                    return $! if j == maxChildren-                              then Full ary2-                              else BitmapIndexed b ary2-            | bi .&. b == 0 = step ary mary b i j (bi `unsafeShiftL` 1) n-            | otherwise = case go (A.index ary i) of-                Empty -> step ary mary (b .&. complement bi) (i+1) j-                         (bi `unsafeShiftL` 1) n-                t     -> do A.write mary j t-                            step ary mary b (i+1) (j+1) (bi `unsafeShiftL` 1) n--    filterC ary0 h =-        let !n = A.length ary0-        in runST $ do-            mary <- A.new_ n-            step ary0 mary 0 0 n-      where-        step :: A.Array (Leaf k v1) -> A.MArray s (Leaf k v2)-             -> Int -> Int -> Int-             -> ST s (HashMap k v2)-        step !ary !mary i !j n-            | i >= n    = case j of-                0 -> return Empty-                1 -> do l <- A.read mary 0-                        return $! Leaf h l-                _ | i == j -> do ary2 <- A.unsafeFreeze mary-                                 return $! Collision h ary2-                  | otherwise -> do ary2 <- A.trim mary j-                                    return $! Collision h ary2-            | Just el <- onColl $! A.index ary i-                = A.write mary j el >> step ary mary (i+1) (j+1) n-            | otherwise = step ary mary (i+1) j n-{-# INLINE filterMapAux #-}---- | /O(n)/ Filter this map by retaining only elements which values--- satisfy a predicate.-filter :: (v -> Bool) -> HashMap k v -> HashMap k v-filter p = filterWithKey (\_ v -> p v)-{-# INLINE filter #-}----------------------------------------------------------------------------- * Conversions---- TODO: Improve fusion rules by modelled them after the Prelude ones--- on lists.---- | /O(n)/ Return a list of this map's keys.  The list is produced--- lazily.-keys :: HashMap k v -> [k]-keys = L.map fst . toList-{-# INLINE keys #-}---- | /O(n)/ Return a list of this map's values.  The list is produced--- lazily.-elems :: HashMap k v -> [v]-elems = L.map snd . toList-{-# INLINE elems #-}----------------------------------------------------------------------------- ** Lists---- | /O(n)/ Return a list of this map's elements.  The list is--- produced lazily. The order of its elements is unspecified.-toList :: HashMap k v -> [(k, v)]-toList t = build (\ c z -> foldrWithKey (curry c) z t)-{-# INLINE toList #-}---- | /O(n)/ Construct a map with the supplied mappings.  If the list--- contains duplicate mappings, the later mappings take precedence.-fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v-fromList = L.foldl' (\ m (k, v) -> unsafeInsert k v m) empty-{-# INLINABLE fromList #-}---- | /O(n*log n)/ Construct a map from a list of elements.  Uses--- the provided function @f@ to merge duplicate entries with--- @(f newVal oldVal)@.------ === Examples------ Given a list @xs@, create a map with the number of occurrences of each--- element in @xs@:------ > let xs = ['a', 'b', 'a']--- > in fromListWith (+) [ (x, 1) | x <- xs ]--- >--- > = fromList [('a', 2), ('b', 1)]------ Given a list of key-value pairs @xs :: [(k, v)]@, group all values by their--- keys and return a @HashMap k [v]@.------ > let xs = [('a', 1), ('b', 2), ('a', 3)]--- > in fromListWith (++) [ (k, [v]) | (k, v) <- xs ]--- >--- > = fromList [('a', [3, 1]), ('b', [2])]------ Note that the lists in the resulting map contain elements in reverse order--- from their occurences in the original list.------ More generally, duplicate entries are accumulated as follows;--- this matters when @f@ is not commutative or not associative.------ > fromListWith f [(k, a), (k, b), (k, c), (k, d)]--- > = fromList [(k, f d (f c (f b a)))]-fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v-fromListWith f = L.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty-{-# INLINE fromListWith #-}---- | /O(n*log n)/ Construct a map from a list of elements.  Uses--- the provided function to merge duplicate entries.------ === Examples------ Given a list of key-value pairs where the keys are of different flavours, e.g:------ > data Key = Div | Sub------ and the values need to be combined differently when there are duplicates,--- depending on the key:------ > combine Div = div--- > combine Sub = (-)------ then @fromListWithKey@ can be used as follows:------ > fromListWithKey combine [(Div, 2), (Div, 6), (Sub, 2), (Sub, 3)]--- > = fromList [(Div, 3), (Sub, 1)]------ More generally, duplicate entries are accumulated as follows;------ > fromListWith f [(k, a), (k, b), (k, c), (k, d)]--- > = fromList [(k, f k d (f k c (f k b a)))]------ @since 0.2.11-fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v-fromListWithKey f = L.foldl' (\ m (k, v) -> unsafeInsertWithKey f k v m) empty-{-# INLINE fromListWithKey #-}----------------------------------------------------------------------------- Array operations---- | /O(n)/ Look up the value associated with the given key in an--- array.-lookupInArrayCont ::-#if __GLASGOW_HASKELL__ >= 802-  forall rep (r :: TYPE rep) k v.-#else-  forall r k v.-#endif-  Eq k => ((# #) -> r) -> (v -> Int -> r) -> k -> A.Array (Leaf k v) -> r-lookupInArrayCont absent present k0 ary0 = go k0 ary0 0 (A.length ary0)-  where-    go :: Eq k => k -> A.Array (Leaf k v) -> Int -> Int -> r-    go !k !ary !i !n-        | i >= n    = absent (# #)-        | otherwise = case A.index ary i of-            (L kx v)-                | k == kx   -> present v i-                | otherwise -> go k ary (i+1) n-{-# INLINE lookupInArrayCont #-}---- | /O(n)/ Lookup the value associated with the given key in this--- array.  Returns 'Nothing' if the key wasn't found.-indexOf :: Eq k => k -> A.Array (Leaf k v) -> Maybe Int-indexOf k0 ary0 = go k0 ary0 0 (A.length ary0)-  where-    go !k !ary !i !n-        | i >= n    = Nothing-        | otherwise = case A.index ary i of-            (L kx _)-                | k == kx   -> Just i-                | otherwise -> go k ary (i+1) n-{-# INLINABLE indexOf #-}--updateWith# :: Eq k => (v -> (# v #)) -> k -> A.Array (Leaf k v) -> A.Array (Leaf k v)-updateWith# f k0 ary0 = go k0 ary0 0 (A.length ary0)-  where-    go !k !ary !i !n-        | i >= n    = ary-        | otherwise = case A.index ary i of-            (L kx y) | k == kx -> case f y of-                          (# y' #)-                             | ptrEq y y' -> ary-                             | otherwise -> A.update ary i (L k y')-                     | otherwise -> go k ary (i+1) n-{-# INLINABLE updateWith# #-}--updateOrSnocWith :: Eq k => (v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)-                 -> A.Array (Leaf k v)-updateOrSnocWith f = updateOrSnocWithKey (const f)-{-# INLINABLE updateOrSnocWith #-}--updateOrSnocWithKey :: Eq k => (k -> v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)-                 -> A.Array (Leaf k v)-updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)-  where-    go !k v !ary !i !n-        | i >= n = A.run $ do-            -- Not found, append to the end.-            mary <- A.new_ (n + 1)-            A.copy ary 0 mary 0 n-            A.write mary n (L k v)-            return mary-        | L kx y <- A.index ary i-        , k == kx-        , (# v2 #) <- f k v y-            = A.update ary i (L k v2)-        | otherwise-            = go k v ary (i+1) n-{-# INLINABLE updateOrSnocWithKey #-}--updateOrConcatWith :: Eq k => (v -> v -> v) -> A.Array (Leaf k v) -> A.Array (Leaf k v) -> A.Array (Leaf k v)-updateOrConcatWith f = updateOrConcatWithKey (const f)-{-# INLINABLE updateOrConcatWith #-}--updateOrConcatWithKey :: Eq k => (k -> v -> v -> v) -> A.Array (Leaf k v) -> A.Array (Leaf k v) -> A.Array (Leaf k v)-updateOrConcatWithKey f ary1 ary2 = A.run $ do-    -- TODO: instead of mapping and then folding, should we traverse?-    -- We'll have to be careful to avoid allocating pairs or similar.--    -- first: look up the position of each element of ary2 in ary1-    let indices = A.map' (\(L k _) -> indexOf k ary1) ary2-    -- that tells us how large the overlap is:-    -- count number of Nothing constructors-    let nOnly2 = A.foldl' (\n -> maybe (n+1) (const n)) 0 indices-    let n1 = A.length ary1-    let n2 = A.length ary2-    -- copy over all elements from ary1-    mary <- A.new_ (n1 + nOnly2)-    A.copy ary1 0 mary 0 n1-    -- append or update all elements from ary2-    let go !iEnd !i2-          | i2 >= n2 = return ()-          | otherwise = case A.index indices i2 of-               Just i1 -> do -- key occurs in both arrays, store combination in position i1-                             L k v1 <- A.indexM ary1 i1-                             L _ v2 <- A.indexM ary2 i2-                             A.write mary i1 (L k (f k v1 v2))-                             go iEnd (i2+1)-               Nothing -> do -- key is only in ary2, append to end-                             A.write mary iEnd =<< A.indexM ary2 i2-                             go (iEnd+1) (i2+1)-    go n1 0-    return mary-{-# INLINABLE updateOrConcatWithKey #-}----------------------------------------------------------------------------- Manually unrolled loops---- | /O(n)/ Update the element at the given position in this array.-update16 :: A.Array e -> Int -> e -> A.Array e-update16 ary idx b = runST (update16M ary idx b)-{-# INLINE update16 #-}---- | /O(n)/ Update the element at the given position in this array.-update16M :: A.Array e -> Int -> e -> ST s (A.Array e)-update16M ary idx b = do-    mary <- clone16 ary-    A.write mary idx b-    A.unsafeFreeze mary-{-# INLINE update16M #-}---- | /O(n)/ Update the element at the given position in this array, by applying a function to it.-update16With' :: A.Array e -> Int -> (e -> e) -> A.Array e-update16With' ary idx f-  | (# x #) <- A.index# ary idx-  = update16 ary idx $! f x-{-# INLINE update16With' #-}---- | Unsafely clone an array of 16 elements.  The length of the input--- array is not checked.-clone16 :: A.Array e -> ST s (A.MArray s e)-clone16 ary =-    A.thaw ary 0 16----------------------------------------------------------------------------- Bit twiddling--bitsPerSubkey :: Int-bitsPerSubkey = 4--maxChildren :: Int-maxChildren = fromIntegral $ 1 `unsafeShiftL` bitsPerSubkey--subkeyMask :: Bitmap-subkeyMask = 1 `unsafeShiftL` bitsPerSubkey - 1--sparseIndex :: Bitmap -> Bitmap -> Int-sparseIndex b m = popCount (b .&. (m - 1))--mask :: Word -> Shift -> Bitmap-mask w s = 1 `unsafeShiftL` index w s-{-# INLINE mask #-}---- | Mask out the 'bitsPerSubkey' bits used for indexing at this level--- of the tree.-index :: Hash -> Shift -> Int-index w s = fromIntegral $ (unsafeShiftR w s) .&. subkeyMask-{-# INLINE index #-}---- | A bitmask with the 'bitsPerSubkey' least significant bits set.-fullNodeMask :: Bitmap-fullNodeMask = complement (complement 0 `unsafeShiftL` maxChildren)-{-# INLINE fullNodeMask #-}---- | Check if two the two arguments are the same value.  N.B. This--- function might give false negatives (due to GC moving objects.)-ptrEq :: a -> a -> Bool-ptrEq x y = isTrue# (reallyUnsafePtrEquality# x y ==# 1#)-{-# INLINE ptrEq #-}----------------------------------------------------------------------------- IsList instance-instance (Eq k, Hashable k) => Exts.IsList (HashMap k v) where-    type Item (HashMap k v) = (k, v)-    fromList = fromList-    toList   = toList
+ Data/HashMap/Internal.hs view
@@ -0,0 +1,2279 @@+{-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, MagicHash #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE LambdaCase #-}+#if __GLASGOW_HASKELL__ >= 802+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE UnboxedSums #-}+#endif+{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}+{-# OPTIONS_HADDOCK not-home #-}++-- | = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.++module Data.HashMap.Internal+    (+      HashMap(..)+    , Leaf(..)++      -- * Construction+    , empty+    , singleton++      -- * Basic interface+    , null+    , size+    , member+    , lookup+    , (!?)+    , findWithDefault+    , lookupDefault+    , (!)+    , insert+    , insertWith+    , unsafeInsert+    , delete+    , adjust+    , update+    , alter+    , alterF+    , isSubmapOf+    , isSubmapOfBy++      -- * Combine+      -- ** Union+    , union+    , unionWith+    , unionWithKey+    , unions++      -- * Transformations+    , map+    , mapWithKey+    , traverseWithKey++      -- * Difference and intersection+    , difference+    , differenceWith+    , intersection+    , intersectionWith+    , intersectionWithKey++      -- * Folds+    , foldr'+    , foldl'+    , foldrWithKey'+    , foldlWithKey'+    , foldr+    , foldl+    , foldrWithKey+    , foldlWithKey+    , foldMapWithKey++      -- * Filter+    , mapMaybe+    , mapMaybeWithKey+    , filter+    , filterWithKey++      -- * Conversions+    , keys+    , elems++      -- ** Lists+    , toList+    , fromList+    , fromListWith+    , fromListWithKey++      -- Internals used by the strict version+    , Hash+    , Bitmap+    , bitmapIndexedOrFull+    , collision+    , hash+    , mask+    , index+    , bitsPerSubkey+    , fullNodeMask+    , sparseIndex+    , two+    , unionArrayBy+    , update16+    , update16M+    , update16With'+    , updateOrConcatWith+    , updateOrConcatWithKey+    , filterMapAux+    , equalKeys+    , equalKeys1+    , lookupRecordCollision+    , LookupRes(..)+    , insert'+    , delete'+    , lookup'+    , insertNewKey+    , insertKeyExists+    , deleteKeyExists+    , insertModifying+    , ptrEq+    , adjust#+    ) where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>), Applicative(pure))+import Data.Monoid (Monoid(mempty, mappend))+import Data.Traversable (Traversable(..))+import Data.Word (Word)+#endif+#if __GLASGOW_HASKELL__ >= 711+import Data.Semigroup (Semigroup((<>)))+#endif+import Control.DeepSeq (NFData(rnf))+import Control.Monad.ST (ST)+import Data.Bits ((.&.), (.|.), complement, popCount, unsafeShiftL, unsafeShiftR)+import Data.Data hiding (Typeable)+import qualified Data.Foldable as Foldable+#if MIN_VERSION_base(4,10,0)+import Data.Bifoldable+#endif+import qualified Data.List as L+import GHC.Exts ((==#), build, reallyUnsafePtrEquality#, inline)+import Prelude hiding (filter, foldl, foldr, lookup, map, null, pred)+import Text.Read hiding (step)++import qualified Data.HashMap.Internal.Array as A+import qualified Data.Hashable as H+import Data.Hashable (Hashable)+import Data.HashMap.Internal.Unsafe (runST)+import Data.HashMap.Internal.List (isPermutationBy, unorderedCompare)+import Data.Typeable (Typeable)++import GHC.Exts (isTrue#)+import qualified GHC.Exts as Exts++#if MIN_VERSION_base(4,9,0)+import Data.Functor.Classes+import GHC.Stack+#endif++#if MIN_VERSION_hashable(1,2,5)+import qualified Data.Hashable.Lifted as H+#endif++#if __GLASGOW_HASKELL__ >= 802+import GHC.Exts (TYPE, Int (..), Int#)+#endif++#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity (Identity (..))+#endif+import Control.Applicative (Const (..))+import Data.Coerce (coerce)++-- | A set of values.  A set cannot contain duplicate values.+------------------------------------------------------------------------++-- | Convenience function.  Compute a hash value for the given value.+hash :: H.Hashable a => a -> Hash+hash = fromIntegral . H.hash++data Leaf k v = L !k v+  deriving (Eq)++instance (NFData k, NFData v) => NFData (Leaf k v) where+    rnf (L k v) = rnf k `seq` rnf v++-- Invariant: The length of the 1st argument to 'Full' is+-- 2^bitsPerSubkey++-- | A map from keys to values.  A map cannot contain duplicate keys;+-- each key can map to at most one value.+data HashMap k v+    = Empty+    | BitmapIndexed !Bitmap !(A.Array (HashMap k v))+    | Leaf !Hash !(Leaf k v)+    | Full !(A.Array (HashMap k v))+    | Collision !Hash !(A.Array (Leaf k v))+      deriving (Typeable)++type role HashMap nominal representational++instance (NFData k, NFData v) => NFData (HashMap k v) where+    rnf Empty                 = ()+    rnf (BitmapIndexed _ ary) = rnf ary+    rnf (Leaf _ l)            = rnf l+    rnf (Full ary)            = rnf ary+    rnf (Collision _ ary)     = rnf ary++instance Functor (HashMap k) where+    fmap = map++instance Foldable.Foldable (HashMap k) where+    foldMap f = foldMapWithKey (\ _k v -> f v)+    {-# INLINE foldMap #-}+    foldr = foldr+    {-# INLINE foldr #-}+    foldl = foldl+    {-# INLINE foldl #-}+    foldr' = foldr'+    {-# INLINE foldr' #-}+    foldl' = foldl'+    {-# INLINE foldl' #-}+#if MIN_VERSION_base(4,8,0)+    null = null+    {-# INLINE null #-}+    length = size+    {-# INLINE length #-}+#endif++#if MIN_VERSION_base(4,10,0)+-- | @since 0.2.11+instance Bifoldable HashMap where+    bifoldMap f g = foldMapWithKey (\ k v -> f k `mappend` g v)+    {-# INLINE bifoldMap #-}+    bifoldr f g = foldrWithKey (\ k v acc -> k `f` (v `g` acc))+    {-# INLINE bifoldr #-}+    bifoldl f g = foldlWithKey (\ acc k v -> (acc `f` k) `g` v)+    {-# INLINE bifoldl #-}+#endif++#if __GLASGOW_HASKELL__ >= 711+-- | '<>' = 'union'+--+-- If a key occurs in both maps, the mapping from the first will be the mapping in the result.+--+-- ==== __Examples__+--+-- >>> fromList [(1,'a'),(2,'b')] <> fromList [(2,'c'),(3,'d')]+-- fromList [(1,'a'),(2,'b'),(3,'d')]+instance (Eq k, Hashable k) => Semigroup (HashMap k v) where+  (<>) = union+  {-# INLINE (<>) #-}+#endif++-- | 'mempty' = 'empty'+--+-- 'mappend' = 'union'+--+-- If a key occurs in both maps, the mapping from the first will be the mapping in the result.+--+-- ==== __Examples__+--+-- >>> mappend (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])+-- fromList [(1,'a'),(2,'b'),(3,'d')]+instance (Eq k, Hashable k) => Monoid (HashMap k v) where+  mempty = empty+  {-# INLINE mempty #-}+#if __GLASGOW_HASKELL__ >= 711+  mappend = (<>)+#else+  mappend = union+#endif+  {-# INLINE mappend #-}++instance (Data k, Data v, Eq k, Hashable k) => Data (HashMap k v) where+    gfoldl f z m   = z fromList `f` toList m+    toConstr _     = fromListConstr+    gunfold k z c  = case constrIndex c of+        1 -> k (z fromList)+        _ -> error "gunfold"+    dataTypeOf _   = hashMapDataType+    dataCast2 f    = gcast2 f++fromListConstr :: Constr+fromListConstr = mkConstr hashMapDataType "fromList" [] Prefix++hashMapDataType :: DataType+hashMapDataType = mkDataType "Data.HashMap.Internal.HashMap" [fromListConstr]++type Hash   = Word+type Bitmap = Word+type Shift  = Int++#if MIN_VERSION_base(4,9,0)+instance Show2 HashMap where+    liftShowsPrec2 spk slk spv slv d m =+        showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)+      where+        sp = liftShowsPrec2 spk slk spv slv+        sl = liftShowList2 spk slk spv slv++instance Show k => Show1 (HashMap k) where+    liftShowsPrec = liftShowsPrec2 showsPrec showList++instance (Eq k, Hashable k, Read k) => Read1 (HashMap k) where+    liftReadsPrec rp rl = readsData $+        readsUnaryWith (liftReadsPrec rp' rl') "fromList" fromList+      where+        rp' = liftReadsPrec rp rl+        rl' = liftReadList rp rl+#endif++instance (Eq k, Hashable k, Read k, Read e) => Read (HashMap k e) where+    readPrec = parens $ prec 10 $ do+      Ident "fromList" <- lexP+      xs <- readPrec+      return (fromList xs)++    readListPrec = readListPrecDefault++instance (Show k, Show v) => Show (HashMap k v) where+    showsPrec d m = showParen (d > 10) $+      showString "fromList " . shows (toList m)++instance Traversable (HashMap k) where+    traverse f = traverseWithKey (const f)+    {-# INLINABLE traverse #-}++#if MIN_VERSION_base(4,9,0)+instance Eq2 HashMap where+    liftEq2 = equal2++instance Eq k => Eq1 (HashMap k) where+    liftEq = equal1+#endif++-- | Note that, in the presence of hash collisions, equal @HashMap@s may+-- behave differently, i.e. substitutivity may be violated:+--+-- >>> data D = A | B deriving (Eq, Show)+-- >>> instance Hashable D where hashWithSalt salt _d = salt+--+-- >>> x = fromList [(A,1), (B,2)]+-- >>> y = fromList [(B,2), (A,1)]+--+-- >>> x == y+-- True+-- >>> toList x+-- [(A,1),(B,2)]+-- >>> toList y+-- [(B,2),(A,1)]+--+-- In general, the lack of substitutivity can be observed with any function+-- that depends on the key ordering, such as folds and traversals.+instance (Eq k, Eq v) => Eq (HashMap k v) where+    (==) = equal1 (==)++-- We rely on there being no Empty constructors in the tree!+-- This ensures that two equal HashMaps will have the same+-- shape, modulo the order of entries in Collisions.+equal1 :: Eq k+       => (v -> v' -> Bool)+       -> HashMap k v -> HashMap k v' -> Bool+equal1 eq = go+  where+    go Empty Empty = True+    go (BitmapIndexed bm1 ary1) (BitmapIndexed bm2 ary2)+      = bm1 == bm2 && A.sameArray1 go ary1 ary2+    go (Leaf h1 l1) (Leaf h2 l2) = h1 == h2 && leafEq l1 l2+    go (Full ary1) (Full ary2) = A.sameArray1 go ary1 ary2+    go (Collision h1 ary1) (Collision h2 ary2)+      = h1 == h2 && isPermutationBy leafEq (A.toList ary1) (A.toList ary2)+    go _ _ = False++    leafEq (L k1 v1) (L k2 v2) = k1 == k2 && eq v1 v2++equal2 :: (k -> k' -> Bool) -> (v -> v' -> Bool)+      -> HashMap k v -> HashMap k' v' -> Bool+equal2 eqk eqv t1 t2 = go (toList' t1 []) (toList' t2 [])+  where+    -- If the two trees are the same, then their lists of 'Leaf's and+    -- 'Collision's read from left to right should be the same (modulo the+    -- order of elements in 'Collision').++    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)+      | k1 == k2 &&+        leafEq l1 l2+      = go tl1 tl2+    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)+      | k1 == k2 &&+        A.length ary1 == A.length ary2 &&+        isPermutationBy leafEq (A.toList ary1) (A.toList ary2)+      = go tl1 tl2+    go [] [] = True+    go _  _  = False++    leafEq (L k v) (L k' v') = eqk k k' && eqv v v'++#if MIN_VERSION_base(4,9,0)+instance Ord2 HashMap where+    liftCompare2 = cmp++instance Ord k => Ord1 (HashMap k) where+    liftCompare = cmp compare+#endif++-- | The ordering is total and consistent with the `Eq` instance. However,+-- nothing else about the ordering is specified, and it may change from +-- version to version of either this package or of hashable.+instance (Ord k, Ord v) => Ord (HashMap k v) where+    compare = cmp compare compare++cmp :: (k -> k' -> Ordering) -> (v -> v' -> Ordering)+    -> HashMap k v -> HashMap k' v' -> Ordering+cmp cmpk cmpv t1 t2 = go (toList' t1 []) (toList' t2 [])+  where+    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)+      = compare k1 k2 `mappend`+        leafCompare l1 l2 `mappend`+        go tl1 tl2+    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)+      = compare k1 k2 `mappend`+        compare (A.length ary1) (A.length ary2) `mappend`+        unorderedCompare leafCompare (A.toList ary1) (A.toList ary2) `mappend`+        go tl1 tl2+    go (Leaf _ _ : _) (Collision _ _ : _) = LT+    go (Collision _ _ : _) (Leaf _ _ : _) = GT+    go [] [] = EQ+    go [] _  = LT+    go _  [] = GT+    go _ _ = error "cmp: Should never happen, toList' includes non Leaf / Collision"++    leafCompare (L k v) (L k' v') = cmpk k k' `mappend` cmpv v v'++-- Same as 'equal' but doesn't compare the values.+equalKeys1 :: (k -> k' -> Bool) -> HashMap k v -> HashMap k' v' -> Bool+equalKeys1 eq t1 t2 = go (toList' t1 []) (toList' t2 [])+  where+    go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)+      | k1 == k2 && leafEq l1 l2+      = go tl1 tl2+    go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)+      | k1 == k2 && A.length ary1 == A.length ary2 &&+        isPermutationBy leafEq (A.toList ary1) (A.toList ary2)+      = go tl1 tl2+    go [] [] = True+    go _  _  = False++    leafEq (L k _) (L k' _) = eq k k'++-- Same as 'equal1' but doesn't compare the values.+equalKeys :: Eq k => HashMap k v -> HashMap k v' -> Bool+equalKeys = go+  where+    go :: Eq k => HashMap k v -> HashMap k v' -> Bool+    go Empty Empty = True+    go (BitmapIndexed bm1 ary1) (BitmapIndexed bm2 ary2)+      = bm1 == bm2 && A.sameArray1 go ary1 ary2+    go (Leaf h1 l1) (Leaf h2 l2) = h1 == h2 && leafEq l1 l2+    go (Full ary1) (Full ary2) = A.sameArray1 go ary1 ary2+    go (Collision h1 ary1) (Collision h2 ary2)+      = h1 == h2 && isPermutationBy leafEq (A.toList ary1) (A.toList ary2)+    go _ _ = False++    leafEq (L k1 _) (L k2 _) = k1 == k2++#if MIN_VERSION_hashable(1,2,5)+instance H.Hashable2 HashMap where+    liftHashWithSalt2 hk hv salt hm = go salt (toList' hm [])+      where+        -- go :: Int -> [HashMap k v] -> Int+        go s [] = s+        go s (Leaf _ l : tl)+          = s `hashLeafWithSalt` l `go` tl+        -- For collisions we hashmix hash value+        -- and then array of values' hashes sorted+        go s (Collision h a : tl)+          = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a `go` tl+        go s (_ : tl) = s `go` tl++        -- hashLeafWithSalt :: Int -> Leaf k v -> Int+        hashLeafWithSalt s (L k v) = (s `hk` k) `hv` v++        -- hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int+        hashCollisionWithSalt s+          = L.foldl' H.hashWithSalt s . arrayHashesSorted s++        -- arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]+        arrayHashesSorted s = L.sort . L.map (hashLeafWithSalt s) . A.toList++instance (Hashable k) => H.Hashable1 (HashMap k) where+    liftHashWithSalt = H.liftHashWithSalt2 H.hashWithSalt+#endif++instance (Hashable k, Hashable v) => Hashable (HashMap k v) where+    hashWithSalt salt hm = go salt hm+      where+        go :: Int -> HashMap k v -> Int+        go s Empty = s+        go s (BitmapIndexed _ a) = A.foldl' go s a+        go s (Leaf h (L _ v))+          = s `H.hashWithSalt` h `H.hashWithSalt` v+        -- For collisions we hashmix hash value+        -- and then array of values' hashes sorted+        go s (Full a) = A.foldl' go s a+        go s (Collision h a)+          = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a++        hashLeafWithSalt :: Int -> Leaf k v -> Int+        hashLeafWithSalt s (L k v) = s `H.hashWithSalt` k `H.hashWithSalt` v++        hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int+        hashCollisionWithSalt s+          = L.foldl' H.hashWithSalt s . arrayHashesSorted s++        arrayHashesSorted :: Int -> A.Array (Leaf k v) -> [Int]+        arrayHashesSorted s = L.sort . L.map (hashLeafWithSalt s) . A.toList++  -- Helper to get 'Leaf's and 'Collision's as a list.+toList' :: HashMap k v -> [HashMap k v] -> [HashMap k v]+toList' (BitmapIndexed _ ary) a = A.foldr toList' a ary+toList' (Full ary)            a = A.foldr toList' a ary+toList' l@(Leaf _ _)          a = l : a+toList' c@(Collision _ _)     a = c : a+toList' Empty                 a = a++-- Helper function to detect 'Leaf's and 'Collision's.+isLeafOrCollision :: HashMap k v -> Bool+isLeafOrCollision (Leaf _ _)      = True+isLeafOrCollision (Collision _ _) = True+isLeafOrCollision _               = False++------------------------------------------------------------------------+-- * Construction++-- | /O(1)/ Construct an empty map.+empty :: HashMap k v+empty = Empty++-- | /O(1)/ Construct a map with a single element.+singleton :: (Hashable k) => k -> v -> HashMap k v+singleton k v = Leaf (hash k) (L k v)++------------------------------------------------------------------------+-- * Basic interface++-- | /O(1)/ Return 'True' if this map is empty, 'False' otherwise.+null :: HashMap k v -> Bool+null Empty = True+null _   = False++-- | /O(n)/ Return the number of key-value mappings in this map.+size :: HashMap k v -> Int+size t = go t 0+  where+    go Empty                !n = n+    go (Leaf _ _)            n = n + 1+    go (BitmapIndexed _ ary) n = A.foldl' (flip go) n ary+    go (Full ary)            n = A.foldl' (flip go) n ary+    go (Collision _ ary)     n = n + A.length ary++-- | /O(log n)/ Return 'True' if the specified key is present in the+-- map, 'False' otherwise.+member :: (Eq k, Hashable k) => k -> HashMap k a -> Bool+member k m = case lookup k m of+    Nothing -> False+    Just _  -> True+{-# INLINABLE member #-}++-- | /O(log n)/ Return the value to which the specified key is mapped,+-- or 'Nothing' if this map contains no mapping for the key.+lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v+#if __GLASGOW_HASKELL__ >= 802+-- GHC does not yet perform a worker-wrapper transformation on+-- unboxed sums automatically. That seems likely to happen at some+-- point (possibly as early as GHC 8.6) but for now we do it manually.+lookup k m = case lookup# k m of+  (# (# #) | #) -> Nothing+  (# | a #) -> Just a+{-# INLINE lookup #-}++lookup# :: (Eq k, Hashable k) => k -> HashMap k v -> (# (# #) | v #)+lookup# k m = lookupCont (\_ -> (# (# #) | #)) (\v _i -> (# | v #)) (hash k) k 0 m+{-# INLINABLE lookup# #-}++#else++lookup k m = lookupCont (\_ -> Nothing) (\v _i -> Just v) (hash k) k 0 m+{-# INLINABLE lookup #-}+#endif++-- | lookup' is a version of lookup that takes the hash separately.+-- It is used to implement alterF.+lookup' :: Eq k => Hash -> k -> HashMap k v -> Maybe v+#if __GLASGOW_HASKELL__ >= 802+-- GHC does not yet perform a worker-wrapper transformation on+-- unboxed sums automatically. That seems likely to happen at some+-- point (possibly as early as GHC 8.6) but for now we do it manually.+-- lookup' would probably prefer to be implemented in terms of its own+-- lookup'#, but it's not important enough and we don't want too much+-- code.+lookup' h k m = case lookupRecordCollision# h k m of+  (# (# #) | #) -> Nothing+  (# | (# a, _i #) #) -> Just a+{-# INLINE lookup' #-}+#else+lookup' h k m = lookupCont (\_ -> Nothing) (\v _i -> Just v) h k 0 m+{-# INLINABLE lookup' #-}+#endif++-- The result of a lookup, keeping track of if a hash collision occured.+-- If a collision did not occur then it will have the Int value (-1).+data LookupRes a = Absent | Present a !Int++-- Internal helper for lookup. This version takes the precomputed hash so+-- that functions that make multiple calls to lookup and related functions+-- (insert, delete) only need to calculate the hash once.+--+-- It is used by 'alterF' so that hash computation and key comparison only needs+-- to be performed once. With this information you can use the more optimized+-- versions of insert ('insertNewKey', 'insertKeyExists') and delete+-- ('deleteKeyExists')+--+-- Outcomes:+--   Key not in map           => Absent+--   Key in map, no collision => Present v (-1)+--   Key in map, collision    => Present v position+lookupRecordCollision :: Eq k => Hash -> k -> HashMap k v -> LookupRes v+#if __GLASGOW_HASKELL__ >= 802+lookupRecordCollision h k m = case lookupRecordCollision# h k m of+  (# (# #) | #) -> Absent+  (# | (# a, i #) #) -> Present a (I# i) -- GHC will eliminate the I#+{-# INLINE lookupRecordCollision #-}++-- Why do we produce an Int# instead of an Int? Unfortunately, GHC is not+-- yet any good at unboxing things *inside* products, let alone sums. That+-- may be changing in GHC 8.6 or so (there is some work in progress), but+-- for now we use Int# explicitly here. We don't need to push the Int#+-- into lookupCont because inlining takes care of that.+lookupRecordCollision# :: Eq k => Hash -> k -> HashMap k v -> (# (# #) | (# v, Int# #) #)+lookupRecordCollision# h k m =+    lookupCont (\_ -> (# (# #) | #)) (\v (I# i) -> (# | (# v, i #) #)) h k 0 m+-- INLINABLE to specialize to the Eq instance.+{-# INLINABLE lookupRecordCollision# #-}++#else /* GHC < 8.2 so there are no unboxed sums */++lookupRecordCollision h k m = lookupCont (\_ -> Absent) Present h k 0 m+{-# INLINABLE lookupRecordCollision #-}+#endif++-- A two-continuation version of lookupRecordCollision. This lets us+-- share source code between lookup and lookupRecordCollision without+-- risking any performance degradation.+--+-- The absent continuation has type @((# #) -> r)@ instead of just @r@+-- so we can be representation-polymorphic in the result type. Since+-- this whole thing is always inlined, we don't have to worry about+-- any extra CPS overhead.+--+-- The @Int@ argument is the offset of the subkey in the hash. When looking up+-- keys at the top-level of a hashmap, the offset should be 0. When looking up+-- keys at level @n@ of a hashmap, the offset should be @n * bitsPerSubkey@.+lookupCont ::+#if __GLASGOW_HASKELL__ >= 802+  forall rep (r :: TYPE rep) k v.+#else+  forall r k v.+#endif+     Eq k+  => ((# #) -> r)    -- Absent continuation+  -> (v -> Int -> r) -- Present continuation+  -> Hash -- The hash of the key+  -> k+  -> Int -- The offset of the subkey in the hash.+  -> HashMap k v -> r+lookupCont absent present !h0 !k0 !s0 !m0 = go h0 k0 s0 m0+  where+    go :: Eq k => Hash -> k -> Int -> HashMap k v -> r+    go !_ !_ !_ Empty = absent (# #)+    go h k _ (Leaf hx (L kx x))+        | h == hx && k == kx = present x (-1)+        | otherwise          = absent (# #)+    go h k s (BitmapIndexed b v)+        | b .&. m == 0 = absent (# #)+        | otherwise    =+            go h k (s+bitsPerSubkey) (A.index v (sparseIndex b m))+      where m = mask h s+    go h k s (Full v) =+      go h k (s+bitsPerSubkey) (A.index v (index h s))+    go h k _ (Collision hx v)+        | h == hx   = lookupInArrayCont absent present k v+        | otherwise = absent (# #)+{-# INLINE lookupCont #-}++-- | /O(log n)/ Return the value to which the specified key is mapped,+-- or 'Nothing' if this map contains no mapping for the key.+--+-- This is a flipped version of 'lookup'.+--+-- @since 0.2.11+(!?) :: (Eq k, Hashable k) => HashMap k v -> k -> Maybe v+(!?) m k = lookup k m+{-# INLINE (!?) #-}+++-- | /O(log n)/ Return the value to which the specified key is mapped,+-- or the default value if this map contains no mapping for the key.+--+-- @since 0.2.11+findWithDefault :: (Eq k, Hashable k)+              => v          -- ^ Default value to return.+              -> k -> HashMap k v -> v+findWithDefault def k t = case lookup k t of+    Just v -> v+    _      -> def+{-# INLINABLE findWithDefault #-}+++-- | /O(log n)/ Return the value to which the specified key is mapped,+-- or the default value if this map contains no mapping for the key.+--+-- DEPRECATED: lookupDefault is deprecated as of version 0.2.11, replaced+-- by 'findWithDefault'.+lookupDefault :: (Eq k, Hashable k)+              => v          -- ^ Default value to return.+              -> k -> HashMap k v -> v+lookupDefault def k t = findWithDefault def k t+{-# INLINE lookupDefault #-}++-- | /O(log n)/ Return the value to which the specified key is mapped.+-- Calls 'error' if this map contains no mapping for the key.+#if MIN_VERSION_base(4,9,0)+(!) :: (Eq k, Hashable k, HasCallStack) => HashMap k v -> k -> v+#else+(!) :: (Eq k, Hashable k) => HashMap k v -> k -> v+#endif+(!) m k = case lookup k m of+    Just v  -> v+    Nothing -> error "Data.HashMap.Internal.(!): key not found"+{-# INLINABLE (!) #-}++infixl 9 !++-- | Create a 'Collision' value with two 'Leaf' values.+collision :: Hash -> Leaf k v -> Leaf k v -> HashMap k v+collision h !e1 !e2 =+    let v = A.run $ do mary <- A.new 2 e1+                       A.write mary 1 e2+                       return mary+    in Collision h v+{-# INLINE collision #-}++-- | Create a 'BitmapIndexed' or 'Full' node.+bitmapIndexedOrFull :: Bitmap -> A.Array (HashMap k v) -> HashMap k v+bitmapIndexedOrFull b ary+    | b == fullNodeMask = Full ary+    | otherwise         = BitmapIndexed b ary+{-# INLINE bitmapIndexedOrFull #-}++-- | /O(log n)/ Associate the specified value with the specified+-- key in this map.  If this map previously contained a mapping for+-- the key, the old value is replaced.+insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v+insert k v m = insert' (hash k) k v m+{-# INLINABLE insert #-}++insert' :: Eq k => Hash -> k -> v -> HashMap k v -> HashMap k v+insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0+  where+    go !h !k x !_ Empty = Leaf h (L k x)+    go h k x s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then if x `ptrEq` y+                         then t+                         else Leaf h (L k x)+                    else collision h l (L k x)+        | otherwise = runST (two s h k x hy t)+    go h k x s t@(BitmapIndexed b ary)+        | b .&. m == 0 =+            let !ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let !st  = A.index ary i+                !st' = go h k x (s+bitsPerSubkey) st+            in if st' `ptrEq` st+               then t+               else BitmapIndexed b (A.update ary i st')+      where m = mask h s+            i = sparseIndex b m+    go h k x s t@(Full ary) =+        let !st  = A.index ary i+            !st' = go h k x (s+bitsPerSubkey) st+        in if st' `ptrEq` st+            then t+            else Full (update16 ary i st')+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v)+        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE insert' #-}++-- Insert optimized for the case when we know the key is not in the map.+--+-- It is only valid to call this when the key does not exist in the map.+--+-- We can skip:+--  - the key equality check on a Leaf+--  - check for its existence in the array for a hash collision+insertNewKey :: Hash -> k -> v -> HashMap k v -> HashMap k v+insertNewKey !h0 !k0 x0 !m0 = go h0 k0 x0 0 m0+  where+    go !h !k x !_ Empty = Leaf h (L k x)+    go h k x s t@(Leaf hy l)+      | hy == h = collision h l (L k x)+      | otherwise = runST (two s h k x hy t)+    go h k x s (BitmapIndexed b ary)+        | b .&. m == 0 =+            let !ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let !st  = A.index ary i+                !st' = go h k x (s+bitsPerSubkey) st+            in BitmapIndexed b (A.update ary i st')+      where m = mask h s+            i = sparseIndex b m+    go h k x s (Full ary) =+        let !st  = A.index ary i+            !st' = go h k x (s+bitsPerSubkey) st+        in Full (update16 ary i st')+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = Collision h (snocNewLeaf (L k x) v)+        | otherwise =+            go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+      where+        snocNewLeaf :: Leaf k v -> A.Array (Leaf k v) -> A.Array (Leaf k v)+        snocNewLeaf leaf ary = A.run $ do+          let n = A.length ary+          mary <- A.new_ (n + 1)+          A.copy ary 0 mary 0 n+          A.write mary n leaf+          return mary+{-# NOINLINE insertNewKey #-}+++-- Insert optimized for the case when we know the key is in the map.+--+-- It is only valid to call this when the key exists in the map and you know the+-- hash collision position if there was one. This information can be obtained+-- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos+-- (first argument).+--+-- We can skip the key equality check on a Leaf because we know the leaf must be+-- for this key.+insertKeyExists :: Int -> Hash -> k -> v -> HashMap k v -> HashMap k v+insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 0 m0+  where+    go !_collPos !h !k x !_s (Leaf _hy _kx)+        = Leaf h (L k x)+    go collPos h k x s (BitmapIndexed b ary)+        | b .&. m == 0 =+            let !ary' = A.insert ary i $ Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let !st  = A.index ary i+                !st' = go collPos h k x (s+bitsPerSubkey) st+            in BitmapIndexed b (A.update ary i st')+      where m = mask h s+            i = sparseIndex b m+    go collPos h k x s (Full ary) =+        let !st  = A.index ary i+            !st' = go collPos h k x (s+bitsPerSubkey) st+        in Full (update16 ary i st')+      where i = index h s+    go collPos h k x _s (Collision _hy v)+        | collPos >= 0 = Collision h (setAtPosition collPos k x v)+        | otherwise = Empty -- error "Internal error: go {collPos negative}"+    go _ _ _ _ _ Empty = Empty -- error "Internal error: go Empty"++{-# NOINLINE insertKeyExists #-}++-- Replace the ith Leaf with Leaf k v.+--+-- This does not check that @i@ is within bounds of the array.+setAtPosition :: Int -> k -> v -> A.Array (Leaf k v) -> A.Array (Leaf k v)+setAtPosition i k x ary = A.update ary i (L k x)+{-# INLINE setAtPosition #-}+++-- | In-place update version of insert+unsafeInsert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v+unsafeInsert k0 v0 m0 = runST (go h0 k0 v0 0 m0)+  where+    h0 = hash k0+    go !h !k x !_ Empty = return $! Leaf h (L k x)+    go h k x s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then if x `ptrEq` y+                         then return t+                         else return $! Leaf h (L k x)+                    else return $! collision h l (L k x)+        | otherwise = two s h k x hy t+    go h k x s t@(BitmapIndexed b ary)+        | b .&. m == 0 = do+            ary' <- A.insertM ary i $! Leaf h (L k x)+            return $! bitmapIndexedOrFull (b .|. m) ary'+        | otherwise = do+            st <- A.indexM ary i+            st' <- go h k x (s+bitsPerSubkey) st+            A.unsafeUpdateM ary i st'+            return t+      where m = mask h s+            i = sparseIndex b m+    go h k x s t@(Full ary) = do+        st <- A.indexM ary i+        st' <- go h k x (s+bitsPerSubkey) st+        A.unsafeUpdateM ary i st'+        return t+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = return $! Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v)+        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE unsafeInsert #-}++-- | Create a map from two key-value pairs which hashes don't collide. To+-- enhance sharing, the second key-value pair is represented by the hash of its+-- key and a singleton HashMap pairing its key with its value.+--+-- Note: to avoid silly thunks, this function must be strict in the+-- key. See issue #232. We don't need to force the HashMap argument+-- because it's already in WHNF (having just been matched) and we+-- just put it directly in an array.+two :: Shift -> Hash -> k -> v -> Hash -> HashMap k v -> ST s (HashMap k v)+two = go+  where+    go s h1 k1 v1 h2 t2+        | bp1 == bp2 = do+            st <- go (s+bitsPerSubkey) h1 k1 v1 h2 t2+            ary <- A.singletonM st+            return $ BitmapIndexed bp1 ary+        | otherwise  = do+            mary <- A.new 2 $! Leaf h1 (L k1 v1)+            A.write mary idx2 t2+            ary <- A.unsafeFreeze mary+            return $ BitmapIndexed (bp1 .|. bp2) ary+      where+        bp1  = mask h1 s+        bp2  = mask h2 s+        idx2 | index h1 s < index h2 s = 1+             | otherwise               = 0+{-# INLINE two #-}++-- | /O(log n)/ Associate the value with the key in this map.  If+-- this map previously contained a mapping for the key, the old value+-- is replaced by the result of applying the given function to the new+-- and old value.  Example:+--+-- > insertWith f k v map+-- >   where f new old = new + old+insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v+            -> HashMap k v+-- We're not going to worry about allocating a function closure+-- to pass to insertModifying. See comments at 'adjust'.+insertWith f k new m = insertModifying new (\old -> (# f new old #)) k m+{-# INLINE insertWith #-}++-- | @insertModifying@ is a lot like insertWith; we use it to implement alterF.+-- It takes a value to insert when the key is absent and a function+-- to apply to calculate a new value when the key is present. Thanks+-- to the unboxed unary tuple, we avoid introducing any unnecessary+-- thunks in the tree.+insertModifying :: (Eq k, Hashable k) => v -> (v -> (# v #)) -> k -> HashMap k v+            -> HashMap k v+insertModifying x f k0 m0 = go h0 k0 0 m0+  where+    !h0 = hash k0+    go !h !k !_ Empty = Leaf h (L k x)+    go h k s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then case f y of+                      (# v' #) | ptrEq y v' -> t+                               | otherwise -> Leaf h (L k (v'))+                    else collision h l (L k x)+        | otherwise = runST (two s h k x hy t)+    go h k s t@(BitmapIndexed b ary)+        | b .&. m == 0 =+            let ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let !st   = A.index ary i+                !st'  = go h k (s+bitsPerSubkey) st+                ary'  = A.update ary i $! st'+            in if ptrEq st st'+               then t+               else BitmapIndexed b ary'+      where m = mask h s+            i = sparseIndex b m+    go h k s t@(Full ary) =+        let !st   = A.index ary i+            !st'  = go h k (s+bitsPerSubkey) st+            ary' = update16 ary i $! st'+        in if ptrEq st st'+           then t+           else Full ary'+      where i = index h s+    go h k s t@(Collision hy v)+        | h == hy   =+            let !v' = insertModifyingArr x f k v+            in if A.unsafeSameArray v v'+               then t+               else Collision h v'+        | otherwise = go h k s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE insertModifying #-}++-- Like insertModifying for arrays; used to implement insertModifying+insertModifyingArr :: Eq k => v -> (v -> (# v #)) -> k -> A.Array (Leaf k v)+                 -> A.Array (Leaf k v)+insertModifyingArr x f k0 ary0 = go k0 ary0 0 (A.length ary0)+  where+    go !k !ary !i !n+        | i >= n = A.run $ do+            -- Not found, append to the end.+            mary <- A.new_ (n + 1)+            A.copy ary 0 mary 0 n+            A.write mary n (L k x)+            return mary+        | otherwise = case A.index ary i of+            (L kx y) | k == kx   -> case f y of+                                      (# y' #) -> if ptrEq y y'+                                                  then ary+                                                  else A.update ary i (L k y')+                     | otherwise -> go k ary (i+1) n+{-# INLINE insertModifyingArr #-}++-- | In-place update version of insertWith+unsafeInsertWith :: forall k v. (Eq k, Hashable k)+                 => (v -> v -> v) -> k -> v -> HashMap k v+                 -> HashMap k v+unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0+{-# INLINABLE unsafeInsertWith #-}++unsafeInsertWithKey :: forall k v. (Eq k, Hashable k)+                 => (k -> v -> v -> v) -> k -> v -> HashMap k v+                 -> HashMap k v+unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)+  where+    h0 = hash k0+    go :: Hash -> k -> v -> Shift -> HashMap k v -> ST s (HashMap k v)+    go !h !k x !_ Empty = return $! Leaf h (L k x)+    go h k x s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then return $! Leaf h (L k (f k x y))+                    else return $! collision h l (L k x)+        | otherwise = two s h k x hy t+    go h k x s t@(BitmapIndexed b ary)+        | b .&. m == 0 = do+            ary' <- A.insertM ary i $! Leaf h (L k x)+            return $! bitmapIndexedOrFull (b .|. m) ary'+        | otherwise = do+            st <- A.indexM ary i+            st' <- go h k x (s+bitsPerSubkey) st+            A.unsafeUpdateM ary i st'+            return t+      where m = mask h s+            i = sparseIndex b m+    go h k x s t@(Full ary) = do+        st <- A.indexM ary i+        st' <- go h k x (s+bitsPerSubkey) st+        A.unsafeUpdateM ary i st'+        return t+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = return $! Collision h (updateOrSnocWithKey (\key a b -> (# f key a b #) ) k x v)+        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE unsafeInsertWithKey #-}++-- | /O(log n)/ Remove the mapping for the specified key from this map+-- if present.+delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v+delete k m = delete' (hash k) k m+{-# INLINABLE delete #-}++delete' :: Eq k => Hash -> k -> HashMap k v -> HashMap k v+delete' h0 k0 m0 = go h0 k0 0 m0+  where+    go !_ !_ !_ Empty = Empty+    go h k _ t@(Leaf hy (L ky _))+        | hy == h && ky == k = Empty+        | otherwise          = t+    go h k s t@(BitmapIndexed b ary)+        | b .&. m == 0 = t+        | otherwise =+            let !st = A.index ary i+                !st' = go h k (s+bitsPerSubkey) st+            in if st' `ptrEq` st+                then t+                else case st' of+                Empty | A.length ary == 1 -> Empty+                      | A.length ary == 2 ->+                          case (i, A.index ary 0, A.index ary 1) of+                          (0, _, l) | isLeafOrCollision l -> l+                          (1, l, _) | isLeafOrCollision l -> l+                          _                               -> bIndexed+                      | otherwise -> bIndexed+                    where+                      bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)+                l | isLeafOrCollision l && A.length ary == 1 -> l+                _ -> BitmapIndexed b (A.update ary i st')+      where m = mask h s+            i = sparseIndex b m+    go h k s t@(Full ary) =+        let !st   = A.index ary i+            !st' = go h k (s+bitsPerSubkey) st+        in if st' `ptrEq` st+            then t+            else case st' of+            Empty ->+                let ary' = A.delete ary i+                    bm   = fullNodeMask .&. complement (1 `unsafeShiftL` i)+                in BitmapIndexed bm ary'+            _ -> Full (A.update ary i st')+      where i = index h s+    go h k _ t@(Collision hy v)+        | h == hy = case indexOf k v of+            Just i+                | A.length v == 2 ->+                    if i == 0+                    then Leaf h (A.index v 1)+                    else Leaf h (A.index v 0)+                | otherwise -> Collision h (A.delete v i)+            Nothing -> t+        | otherwise = t+{-# INLINABLE delete' #-}++-- | Delete optimized for the case when we know the key is in the map.+--+-- It is only valid to call this when the key exists in the map and you know the+-- hash collision position if there was one. This information can be obtained+-- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos.+--+-- We can skip:+--  - the key equality check on the leaf, if we reach a leaf it must be the key+deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v+deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 0 m0+  where+    go :: Int -> Hash -> k -> Int -> HashMap k v -> HashMap k v+    go !_collPos !_h !_k !_s (Leaf _ _) = Empty+    go collPos h k s (BitmapIndexed b ary) =+            let !st = A.index ary i+                !st' = go collPos h k (s+bitsPerSubkey) st+            in case st' of+                Empty | A.length ary == 1 -> Empty+                      | A.length ary == 2 ->+                          case (i, A.index ary 0, A.index ary 1) of+                          (0, _, l) | isLeafOrCollision l -> l+                          (1, l, _) | isLeafOrCollision l -> l+                          _                               -> bIndexed+                      | otherwise -> bIndexed+                    where+                      bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)+                l | isLeafOrCollision l && A.length ary == 1 -> l+                _ -> BitmapIndexed b (A.update ary i st')+      where m = mask h s+            i = sparseIndex b m+    go collPos h k s (Full ary) =+        let !st   = A.index ary i+            !st' = go collPos h k (s+bitsPerSubkey) st+        in case st' of+            Empty ->+                let ary' = A.delete ary i+                    bm   = fullNodeMask .&. complement (1 `unsafeShiftL` i)+                in BitmapIndexed bm ary'+            _ -> Full (A.update ary i st')+      where i = index h s+    go collPos h _ _ (Collision _hy v)+      | A.length v == 2+      = if collPos == 0+        then Leaf h (A.index v 1)+        else Leaf h (A.index v 0)+      | otherwise = Collision h (A.delete v collPos)+    go !_ !_ !_ !_ Empty = Empty -- error "Internal error: deleteKeyExists empty"+{-# NOINLINE deleteKeyExists #-}++-- | /O(log n)/ Adjust the value tied to a given key in this map only+-- if it is present. Otherwise, leave the map alone.+adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v+-- This operation really likes to leak memory, so using this+-- indirect implementation shouldn't hurt much. Furthermore, it allows+-- GHC to avoid a leak when the function is lazy. In particular,+--+--     adjust (const x) k m+-- ==> adjust# (\v -> (# const x v #)) k m+-- ==> adjust# (\_ -> (# x #)) k m+adjust f k m = adjust# (\v -> (# f v #)) k m+{-# INLINE adjust #-}++-- | Much like 'adjust', but not inherently leaky.+adjust# :: (Eq k, Hashable k) => (v -> (# v #)) -> k -> HashMap k v -> HashMap k v+adjust# f k0 m0 = go h0 k0 0 m0+  where+    h0 = hash k0+    go !_ !_ !_ Empty = Empty+    go h k _ t@(Leaf hy (L ky y))+        | hy == h && ky == k = case f y of+            (# y' #) | ptrEq y y' -> t+                     | otherwise -> Leaf h (L k y')+        | otherwise          = t+    go h k s t@(BitmapIndexed b ary)+        | b .&. m == 0 = t+        | otherwise = let !st   = A.index ary i+                          !st'  = go h k (s+bitsPerSubkey) st+                          ary' = A.update ary i $! st'+                      in if ptrEq st st'+                         then t+                         else BitmapIndexed b ary'+      where m = mask h s+            i = sparseIndex b m+    go h k s t@(Full ary) =+        let i    = index h s+            !st   = A.index ary i+            !st'  = go h k (s+bitsPerSubkey) st+            ary' = update16 ary i $! st'+        in if ptrEq st st'+           then t+           else Full ary'+    go h k _ t@(Collision hy v)+        | h == hy   = let !v' = updateWith# f k v+                      in if A.unsafeSameArray v v'+                         then t+                         else Collision h v'+        | otherwise = t+{-# INLINABLE adjust# #-}++-- | /O(log n)/  The expression @('update' f k map)@ updates the value @x@ at @k@+-- (if it is in the map). If @(f x)@ is 'Nothing', the element is deleted.+-- If it is @('Just' y)@, the key @k@ is bound to the new value @y@.+update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a+update f = alter (>>= f)+{-# INLINABLE update #-}+++-- | /O(log n)/  The expression @('alter' f k map)@ alters the value @x@ at @k@, or+-- absence thereof.+--+-- 'alter' can be used to insert, delete, or update a value in a map. In short:+--+-- @+-- 'lookup' k ('alter' f k m) = f ('lookup' k m)+-- @+alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v+-- TODO(m-renaud): Consider using specialized insert and delete for alter.+alter f k m =+  case f (lookup k m) of+    Nothing -> delete k m+    Just v  -> insert k v m+{-# INLINABLE alter #-}++-- | /O(log n)/  The expression @('alterF' f k map)@ alters the value @x@ at+-- @k@, or absence thereof.+--+--  'alterF' can be used to insert, delete, or update a value in a map.+--+-- Note: 'alterF' is a flipped version of the 'at' combinator from+-- <https://hackage.haskell.org/package/lens/docs/Control-Lens-At.html#v:at Control.Lens.At>.+--+-- @since 0.2.10+alterF :: (Functor f, Eq k, Hashable k)+       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+-- We only calculate the hash once, but unless this is rewritten+-- by rules we may test for key equality multiple times.+-- We force the value of the map for consistency with the rewritten+-- version; otherwise someone could tell the difference using a lazy+-- @f@ and a functor that is similar to Const but not actually Const.+alterF f = \ !k !m ->+  let+    !h = hash k+    mv = lookup' h k m+  in (<$> f mv) $ \fres ->+    case fres of+      Nothing -> maybe m (const (delete' h k m)) mv+      Just v' -> insert' h k v' m++-- We unconditionally rewrite alterF in RULES, but we expose an+-- unfolding just in case it's used in some way that prevents the+-- rule from firing.+{-# INLINABLE [0] alterF #-}++#if MIN_VERSION_base(4,8,0)+-- This is just a bottom value. See the comment on the "alterFWeird"+-- rule.+test_bottom :: a+test_bottom = error "Data.HashMap.alterF internal error: hit test_bottom"++-- We use this as an error result in RULES to ensure we don't get+-- any useless CallStack nonsense.+bogus# :: (# #) -> (# a #)+bogus# _ = error "Data.HashMap.alterF internal error: hit bogus#"++{-# RULES+-- We probe the behavior of @f@ by applying it to Nothing and to+-- Just test_bottom. Based on the results, and how they relate to+-- each other, we choose the best implementation.++"alterFWeird" forall f. alterF f =+   alterFWeird (f Nothing) (f (Just test_bottom)) f++-- This rule covers situations where alterF is used to simply insert or+-- delete in Identity (most likely via Control.Lens.At). We recognize here+-- (through the repeated @x@ on the LHS) that+--+-- @f Nothing = f (Just bottom)@,+--+-- which guarantees that @f@ doesn't care what its argument is, so+-- we don't have to either.+--+-- Why only Identity? A variant of this rule is actually valid regardless of+-- the functor, but for some functors (e.g., []), it can lead to the+-- same keys being compared multiple times, which is bad if they're+-- ugly things like strings. This is unfortunate, since the rule is likely+-- a good idea for almost all realistic uses, but I don't like nasty+-- edge cases.+"alterFconstant" forall (f :: Maybe a -> Identity (Maybe a)) x.+  alterFWeird x x f = \ !k !m ->+    Identity (case runIdentity x of {Nothing -> delete k m; Just a -> insert k a m})++-- This rule handles the case where 'alterF' is used to do 'insertWith'-like+-- things. Whenever possible, GHC will get rid of the Maybe nonsense for us.+-- We delay this rule to stage 1 so alterFconstant has a chance to fire.+"alterFinsertWith" [1] forall (f :: Maybe a -> Identity (Maybe a)) x y.+  alterFWeird (coerce (Just x)) (coerce (Just y)) f =+    coerce (insertModifying x (\mold -> case runIdentity (f (Just mold)) of+                                            Nothing -> bogus# (# #)+                                            Just new -> (# new #)))++-- Handle the case where someone uses 'alterF' instead of 'adjust'. This+-- rule is kind of picky; it will only work if the function doesn't+-- do anything between case matching on the Maybe and producing a result.+"alterFadjust" forall (f :: Maybe a -> Identity (Maybe a)) _y.+  alterFWeird (coerce Nothing) (coerce (Just _y)) f =+    coerce (adjust# (\x -> case runIdentity (f (Just x)) of+                               Just x' -> (# x' #)+                               Nothing -> bogus# (# #)))++-- The simple specialization to Const; in this case we can look up+-- the key without caring what position it's in. This is only a tiny+-- optimization.+"alterFlookup" forall _ign1 _ign2 (f :: Maybe a -> Const r (Maybe a)).+  alterFWeird _ign1 _ign2 f = \ !k !m -> Const (getConst (f (lookup k m)))+ #-}++-- This is a very unsafe version of alterF used for RULES. When calling+-- alterFWeird x y f, the following *must* hold:+--+-- x = f Nothing+-- y = f (Just _|_)+--+-- Failure to abide by these laws will make demons come out of your nose.+alterFWeird+       :: (Functor f, Eq k, Hashable k)+       => f (Maybe v)+       -> f (Maybe v)+       -> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+alterFWeird _ _ f = alterFEager f+{-# INLINE [0] alterFWeird #-}++-- | This is the default version of alterF that we use in most non-trivial+-- cases. It's called "eager" because it looks up the given key in the map+-- eagerly, whether or not the given function requires that information.+alterFEager :: (Functor f, Eq k, Hashable k)+       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+alterFEager f !k m = (<$> f mv) $ \fres ->+  case fres of++    ------------------------------+    -- Delete the key from the map.+    Nothing -> case lookupRes of++      -- Key did not exist in the map to begin with, no-op+      Absent -> m++      -- Key did exist+      Present _ collPos -> deleteKeyExists collPos h k m++    ------------------------------+    -- Update value+    Just v' -> case lookupRes of++      -- Key did not exist before, insert v' under a new key+      Absent -> insertNewKey h k v' m++      -- Key existed before+      Present v collPos ->+        if v `ptrEq` v'+        -- If the value is identical, no-op+        then m+        -- If the value changed, update the value.+        else insertKeyExists collPos h k v' m++  where !h = hash k+        !lookupRes = lookupRecordCollision h k m+        !mv = case lookupRes of+           Absent -> Nothing+           Present v _ -> Just v+{-# INLINABLE alterFEager #-}+#endif++-- | /O(n*log m)/ Inclusion of maps. A map is included in another map if the keys+-- are subsets and the corresponding values are equal:+--+-- > isSubmapOf m1 m2 = keys m1 `isSubsetOf` keys m2 &&+-- >                    and [ v1 == v2 | (k1,v1) <- toList m1; let v2 = m2 ! k1 ]+--+-- ==== __Examples__+--+-- >>> fromList [(1,'a')] `isSubmapOf` fromList [(1,'a'),(2,'b')]+-- True+--+-- >>> fromList [(1,'a'),(2,'b')] `isSubmapOf` fromList [(1,'a')]+-- False+--+-- @since 0.2.12+isSubmapOf :: (Eq k, Hashable k, Eq v) => HashMap k v -> HashMap k v -> Bool+isSubmapOf = (inline isSubmapOfBy) (==)+{-# INLINABLE isSubmapOf #-}++-- | /O(n*log m)/ Inclusion of maps with value comparison. A map is included in+-- another map if the keys are subsets and if the comparison function is true+-- for the corresponding values:+--+-- > isSubmapOfBy cmpV m1 m2 = keys m1 `isSubsetOf` keys m2 &&+-- >                           and [ v1 `cmpV` v2 | (k1,v1) <- toList m1; let v2 = m2 ! k1 ]+--+-- ==== __Examples__+--+-- >>> isSubmapOfBy (<=) (fromList [(1,'a')]) (fromList [(1,'b'),(2,'c')])+-- True+--+-- >>> isSubmapOfBy (<=) (fromList [(1,'b')]) (fromList [(1,'a'),(2,'c')])+-- False+--+-- @since 0.2.12+isSubmapOfBy :: (Eq k, Hashable k) => (v1 -> v2 -> Bool) -> HashMap k v1 -> HashMap k v2 -> Bool+-- For maps without collisions the complexity is O(n*log m), where n is the size+-- of m1 and m the size of m2: the inclusion operation visits every leaf in m1 at least once.+-- For each leaf in m1, it looks up the key in m2.+--+-- The worst case complexity is O(n*m). The worst case is when both hashmaps m1+-- and m2 are collision nodes for the same hash. Since collision nodes are+-- unsorted arrays, it requires for every key in m1 a linear search to to find a+-- matching key in m2, hence O(n*m).+isSubmapOfBy comp !m1 !m2 = go 0 m1 m2+  where+    -- An empty map is always a submap of any other map.+    go _ Empty _ = True++    -- If the second map is empty and the first is not, it cannot be a submap.+    go _ _ Empty = False++    -- If the first map contains only one entry, lookup the key in the second map.+    go s (Leaf h1 (L k1 v1)) t2 = lookupCont (\_ -> False) (\v2 _ -> comp v1 v2) h1 k1 s t2++    -- In this case, we need to check that for each x in ls1, there is a y in+    -- ls2 such that x `comp` y. This is the worst case complexity-wise since it+    -- requires a O(m*n) check.+    go _ (Collision h1 ls1) (Collision h2 ls2) =+      h1 == h2 && subsetArray comp ls1 ls2++    -- In this case, we only need to check the entries in ls2 with the hash h1.+    go s t1@(Collision h1 _) (BitmapIndexed b ls2)+        | b .&. m == 0 = False+        | otherwise    =+            go (s+bitsPerSubkey) t1 (A.index ls2 (sparseIndex b m))+      where m = mask h1 s++    -- Similar to the previous case we need to traverse l2 at the index for the hash h1.+    go s t1@(Collision h1 _) (Full ls2) =+      go (s+bitsPerSubkey) t1 (A.index ls2 (index h1 s))++    -- In cases where the first and second map are BitmapIndexed or Full,+    -- traverse down the tree at the appropriate indices.+    go s (BitmapIndexed b1 ls1) (BitmapIndexed b2 ls2) =+      submapBitmapIndexed (go (s+bitsPerSubkey)) b1 ls1 b2 ls2+    go s (BitmapIndexed b1 ls1) (Full ls2) =+      submapBitmapIndexed (go (s+bitsPerSubkey)) b1 ls1 fullNodeMask ls2+    go s (Full ls1) (Full ls2) =+      submapBitmapIndexed (go (s+bitsPerSubkey)) fullNodeMask ls1 fullNodeMask ls2++    -- Collision and Full nodes always contain at least two entries. Hence it+    -- cannot be a map of a leaf.+    go _ (Collision {}) (Leaf {}) = False+    go _ (BitmapIndexed {}) (Leaf {}) = False+    go _ (Full {}) (Leaf {}) = False+    go _ (BitmapIndexed {}) (Collision {}) = False+    go _ (Full {}) (Collision {}) = False+    go _ (Full {}) (BitmapIndexed {}) = False+{-# INLINABLE isSubmapOfBy #-}++-- | /O(min n m))/ Checks if a bitmap indexed node is a submap of another.+submapBitmapIndexed :: (HashMap k v1 -> HashMap k v2 -> Bool) -> Bitmap -> A.Array (HashMap k v1) -> Bitmap -> A.Array (HashMap k v2) -> Bool+submapBitmapIndexed comp !b1 !ary1 !b2 !ary2 = subsetBitmaps && go 0 0 (b1Orb2 .&. negate b1Orb2)+  where+    go :: Int -> Int -> Bitmap -> Bool+    go !i !j !m+      | m > b1Orb2 = True++      -- In case a key is both in ary1 and ary2, check ary1[i] <= ary2[j] and+      -- increment the indices i and j.+      | b1Andb2 .&. m /= 0 = comp (A.index ary1 i) (A.index ary2 j) &&+                             go (i+1) (j+1) (m `unsafeShiftL` 1)++      -- In case a key occurs in ary1, but not ary2, only increment index j.+      | b2 .&. m /= 0 = go i (j+1) (m `unsafeShiftL` 1)++      -- In case a key neither occurs in ary1 nor ary2, continue.+      | otherwise = go i j (m `unsafeShiftL` 1)++    b1Andb2 = b1 .&. b2+    b1Orb2  = b1 .|. b2+    subsetBitmaps = b1Orb2 == b2+{-# INLINABLE submapBitmapIndexed #-}++------------------------------------------------------------------------+-- * Combine++-- | /O(n+m)/ The union of two maps. If a key occurs in both maps, the+-- mapping from the first will be the mapping in the result.+--+-- ==== __Examples__+--+-- >>> union (fromList [(1,'a'),(2,'b')]) (fromList [(2,'c'),(3,'d')])+-- fromList [(1,'a'),(2,'b'),(3,'d')]+union :: (Eq k, Hashable k) => HashMap k v -> HashMap k v -> HashMap k v+union = unionWith const+{-# INLINABLE union #-}++-- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,+-- the provided function (first argument) will be used to compute the+-- result.+unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v+          -> HashMap k v+unionWith f = unionWithKey (const f)+{-# INLINE unionWith #-}++-- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,+-- the provided function (first argument) will be used to compute the+-- result.+unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v+          -> HashMap k v+unionWithKey f = go 0+  where+    -- empty vs. anything+    go !_ t1 Empty = t1+    go _ Empty t2 = t2+    -- leaf vs. leaf+    go s t1@(Leaf h1 l1@(L k1 v1)) t2@(Leaf h2 l2@(L k2 v2))+        | h1 == h2  = if k1 == k2+                      then Leaf h1 (L k1 (f k1 v1 v2))+                      else collision h1 l1 l2+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Leaf h1 (L k1 v1)) t2@(Collision h2 ls2)+        | h1 == h2  = Collision h1 (updateOrSnocWithKey (\k a b -> (# f k a b #)) k1 v1 ls2)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Collision h1 ls1) t2@(Leaf h2 (L k2 v2))+        | h1 == h2  = Collision h1 (updateOrSnocWithKey (\k a b -> (# f k b a #)) k2 v2 ls1)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Collision h1 ls1) t2@(Collision h2 ls2)+        | h1 == h2  = Collision h1 (updateOrConcatWithKey f ls1 ls2)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    -- branch vs. branch+    go s (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =+        let b'   = b1 .|. b2+            ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 b2 ary1 ary2+        in bitmapIndexedOrFull b' ary'+    go s (BitmapIndexed b1 ary1) (Full ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 fullNodeMask ary1 ary2+        in Full ary'+    go s (Full ary1) (BitmapIndexed b2 ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask b2 ary1 ary2+        in Full ary'+    go s (Full ary1) (Full ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask fullNodeMask+                   ary1 ary2+        in Full ary'+    -- leaf vs. branch+    go s (BitmapIndexed b1 ary1) t2+        | b1 .&. m2 == 0 = let ary' = A.insert ary1 i t2+                               b'   = b1 .|. m2+                           in bitmapIndexedOrFull b' ary'+        | otherwise      = let ary' = A.updateWith' ary1 i $ \st1 ->+                                   go (s+bitsPerSubkey) st1 t2+                           in BitmapIndexed b1 ary'+        where+          h2 = leafHashCode t2+          m2 = mask h2 s+          i = sparseIndex b1 m2+    go s t1 (BitmapIndexed b2 ary2)+        | b2 .&. m1 == 0 = let ary' = A.insert ary2 i $! t1+                               b'   = b2 .|. m1+                           in bitmapIndexedOrFull b' ary'+        | otherwise      = let ary' = A.updateWith' ary2 i $ \st2 ->+                                   go (s+bitsPerSubkey) t1 st2+                           in BitmapIndexed b2 ary'+      where+        h1 = leafHashCode t1+        m1 = mask h1 s+        i = sparseIndex b2 m1+    go s (Full ary1) t2 =+        let h2   = leafHashCode t2+            i    = index h2 s+            ary' = update16With' ary1 i $ \st1 -> go (s+bitsPerSubkey) st1 t2+        in Full ary'+    go s t1 (Full ary2) =+        let h1   = leafHashCode t1+            i    = index h1 s+            ary' = update16With' ary2 i $ \st2 -> go (s+bitsPerSubkey) t1 st2+        in Full ary'++    leafHashCode (Leaf h _) = h+    leafHashCode (Collision h _) = h+    leafHashCode _ = error "leafHashCode"++    goDifferentHash s h1 h2 t1 t2+        | m1 == m2  = BitmapIndexed m1 (A.singleton $! go (s+bitsPerSubkey) t1 t2)+        | m1 <  m2  = BitmapIndexed (m1 .|. m2) (A.pair t1 t2)+        | otherwise = BitmapIndexed (m1 .|. m2) (A.pair t2 t1)+      where+        m1 = mask h1 s+        m2 = mask h2 s+{-# INLINE unionWithKey #-}++-- | Strict in the result of @f@.+unionArrayBy :: (a -> a -> a) -> Bitmap -> Bitmap -> A.Array a -> A.Array a+             -> A.Array a+unionArrayBy f b1 b2 ary1 ary2 = A.run $ do+    let b' = b1 .|. b2+    mary <- A.new_ (popCount b')+    -- iterate over nonzero bits of b1 .|. b2+    -- it would be nice if we could shift m by more than 1 each time+    let ba = b1 .&. b2+        go !i !i1 !i2 !m+            | m > b'        = return ()+            | b' .&. m == 0 = go i i1 i2 (m `unsafeShiftL` 1)+            | ba .&. m /= 0 = do+                x1 <- A.indexM ary1 i1+                x2 <- A.indexM ary2 i2+                A.write mary i $! f x1 x2+                go (i+1) (i1+1) (i2+1) (m `unsafeShiftL` 1)+            | b1 .&. m /= 0 = do+                A.write mary i =<< A.indexM ary1 i1+                go (i+1) (i1+1) (i2  ) (m `unsafeShiftL` 1)+            | otherwise     = do+                A.write mary i =<< A.indexM ary2 i2+                go (i+1) (i1  ) (i2+1) (m `unsafeShiftL` 1)+    go 0 0 0 (b' .&. negate b') -- XXX: b' must be non-zero+    return mary+    -- TODO: For the case where b1 .&. b2 == b1, i.e. when one is a+    -- subset of the other, we could use a slightly simpler algorithm,+    -- where we copy one array, and then update.+{-# INLINE unionArrayBy #-}++-- TODO: Figure out the time complexity of 'unions'.++-- | Construct a set containing all elements from a list of sets.+unions :: (Eq k, Hashable k) => [HashMap k v] -> HashMap k v+unions = L.foldl' union empty+{-# INLINE unions #-}++------------------------------------------------------------------------+-- * Transformations++-- | /O(n)/ Transform this map by applying a function to every value.+mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2+mapWithKey f = go+  where+    go Empty = Empty+    go (Leaf h (L k v)) = Leaf h $ L k (f k v)+    go (BitmapIndexed b ary) = BitmapIndexed b $ A.map go ary+    go (Full ary) = Full $ A.map go ary+    -- Why map strictly over collision arrays? Because there's no+    -- point suspending the O(1) work this does for each leaf.+    go (Collision h ary) = Collision h $+                           A.map' (\ (L k v) -> L k (f k v)) ary+{-# INLINE mapWithKey #-}++-- | /O(n)/ Transform this map by applying a function to every value.+map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2+map f = mapWithKey (const f)+{-# INLINE map #-}++-- TODO: We should be able to use mutation to create the new+-- 'HashMap'.++-- | /O(n)/ Perform an 'Applicative' action for each key-value pair+-- in a 'HashMap' and produce a 'HashMap' of all the results.+--+-- Note: the order in which the actions occur is unspecified. In particular,+-- when the map contains hash collisions, the order in which the actions+-- associated with the keys involved will depend in an unspecified way on+-- their insertion order.+traverseWithKey+  :: Applicative f+  => (k -> v1 -> f v2)+  -> HashMap k v1 -> f (HashMap k v2)+traverseWithKey f = go+  where+    go Empty                 = pure Empty+    go (Leaf h (L k v))      = Leaf h . L k <$> f k v+    go (BitmapIndexed b ary) = BitmapIndexed b <$> A.traverse go ary+    go (Full ary)            = Full <$> A.traverse go ary+    go (Collision h ary)     =+        Collision h <$> A.traverse' (\ (L k v) -> L k <$> f k v) ary+{-# INLINE traverseWithKey #-}++------------------------------------------------------------------------+-- * Difference and intersection++-- | /O(n*log m)/ Difference of two maps. Return elements of the first map+-- not existing in the second.+difference :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v+difference a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Nothing -> insert k v m+                 _       -> m+{-# INLINABLE difference #-}++-- | /O(n*log m)/ Difference with a combining function. When two equal keys are+-- encountered, the combining function is applied to the values of these keys.+-- If it returns 'Nothing', the element is discarded (proper set difference). If+-- it returns (@'Just' y@), the element is updated with a new value @y@.+differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v+differenceWith f a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Nothing -> insert k v m+                 Just w  -> maybe m (\y -> insert k y m) (f v w)+{-# INLINABLE differenceWith #-}++-- | /O(n*log m)/ Intersection of two maps. Return elements of the first+-- map for keys existing in the second.+intersection :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v+intersection a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Just _ -> insert k v m+                 _      -> m+{-# INLINABLE intersection #-}++-- | /O(n*log m)/ Intersection of two maps. If a key occurs in both maps+-- the provided function is used to combine the values from the two+-- maps.+intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1+                 -> HashMap k v2 -> HashMap k v3+intersectionWith f a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Just w -> insert k (f v w) m+                 _      -> m+{-# INLINABLE intersectionWith #-}++-- | /O(n*log m)/ Intersection of two maps. If a key occurs in both maps+-- the provided function is used to combine the values from the two+-- maps.+intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)+                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3+intersectionWithKey f a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Just w -> insert k (f k v w) m+                 _      -> m+{-# INLINABLE intersectionWithKey #-}++------------------------------------------------------------------------+-- * Folds++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).  Each application of the operator+-- is evaluated before using the result in the next application.+-- This function is strict in the starting value.+foldl' :: (a -> v -> a) -> a -> HashMap k v -> a+foldl' f = foldlWithKey' (\ z _ v -> f z v)+{-# INLINE foldl' #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator).  Each application of the operator+-- is evaluated before using the result in the next application.+-- This function is strict in the starting value.+foldr' :: (v -> a -> a) -> a -> HashMap k v -> a+foldr' f = foldrWithKey' (\ _ v z -> f v z)+{-# INLINE foldr' #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).  Each application of the operator+-- is evaluated before using the result in the next application.+-- This function is strict in the starting value.+foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a+foldlWithKey' f = go+  where+    go !z Empty                = z+    go z (Leaf _ (L k v))      = f z k v+    go z (BitmapIndexed _ ary) = A.foldl' go z ary+    go z (Full ary)            = A.foldl' go z ary+    go z (Collision _ ary)     = A.foldl' (\ z' (L k v) -> f z' k v) z ary+{-# INLINE foldlWithKey' #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator).  Each application of the operator+-- is evaluated before using the result in the next application.+-- This function is strict in the starting value.+foldrWithKey' :: (k -> v -> a -> a) -> a -> HashMap k v -> a+foldrWithKey' f = flip go+  where+    go Empty z                 = z+    go (Leaf _ (L k v)) !z     = f k v z+    go (BitmapIndexed _ ary) !z = A.foldr' go z ary+    go (Full ary) !z           = A.foldr' go z ary+    go (Collision _ ary) !z    = A.foldr' (\ (L k v) z' -> f k v z') z ary+{-# INLINE foldrWithKey' #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator).+foldr :: (v -> a -> a) -> a -> HashMap k v -> a+foldr f = foldrWithKey (const f)+{-# INLINE foldr #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).+foldl :: (a -> v -> a) -> a -> HashMap k v -> a+foldl f = foldlWithKey (\a _k v -> f a v)+{-# INLINE foldl #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator).+foldrWithKey :: (k -> v -> a -> a) -> a -> HashMap k v -> a+foldrWithKey f = flip go+  where+    go Empty z                 = z+    go (Leaf _ (L k v)) z      = f k v z+    go (BitmapIndexed _ ary) z = A.foldr go z ary+    go (Full ary) z            = A.foldr go z ary+    go (Collision _ ary) z     = A.foldr (\ (L k v) z' -> f k v z') z ary+{-# INLINE foldrWithKey #-}++-- | /O(n)/ Reduce this map by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).+foldlWithKey :: (a -> k -> v -> a) -> a -> HashMap k v -> a+foldlWithKey f = go+  where+    go z Empty                 = z+    go z (Leaf _ (L k v))      = f z k v+    go z (BitmapIndexed _ ary) = A.foldl go z ary+    go z (Full ary)            = A.foldl go z ary+    go z (Collision _ ary)     = A.foldl (\ z' (L k v) -> f z' k v) z ary+{-# INLINE foldlWithKey #-}++-- | /O(n)/ Reduce the map by applying a function to each element+-- and combining the results with a monoid operation.+foldMapWithKey :: Monoid m => (k -> v -> m) -> HashMap k v -> m+foldMapWithKey f = go+  where+    go Empty = mempty+    go (Leaf _ (L k v)) = f k v+    go (BitmapIndexed _ ary) = A.foldMap go ary+    go (Full ary) = A.foldMap go ary+    go (Collision _ ary) = A.foldMap (\ (L k v) -> f k v) ary+{-# INLINE foldMapWithKey #-}++------------------------------------------------------------------------+-- * Filter++-- | /O(n)/ Transform this map by applying a function to every value+--   and retaining only some of them.+mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2+mapMaybeWithKey f = filterMapAux onLeaf onColl+  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (Leaf h (L k v'))+        onLeaf _ = Nothing++        onColl (L k v) | Just v' <- f k v = Just (L k v')+                       | otherwise = Nothing+{-# INLINE mapMaybeWithKey #-}++-- | /O(n)/ Transform this map by applying a function to every value+--   and retaining only some of them.+mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2+mapMaybe f = mapMaybeWithKey (const f)+{-# INLINE mapMaybe #-}++-- | /O(n)/ Filter this map by retaining only elements satisfying a+-- predicate.+filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v+filterWithKey pred = filterMapAux onLeaf onColl+  where onLeaf t@(Leaf _ (L k v)) | pred k v = Just t+        onLeaf _ = Nothing++        onColl el@(L k v) | pred k v = Just el+        onColl _ = Nothing+{-# INLINE filterWithKey #-}+++-- | Common implementation for 'filterWithKey' and 'mapMaybeWithKey',+--   allowing the former to former to reuse terms.+filterMapAux :: forall k v1 v2+              . (HashMap k v1 -> Maybe (HashMap k v2))+             -> (Leaf k v1 -> Maybe (Leaf k v2))+             -> HashMap k v1+             -> HashMap k v2+filterMapAux onLeaf onColl = go+  where+    go Empty = Empty+    go t@Leaf{}+        | Just t' <- onLeaf t = t'+        | otherwise = Empty+    go (BitmapIndexed b ary) = filterA ary b+    go (Full ary) = filterA ary fullNodeMask+    go (Collision h ary) = filterC ary h++    filterA ary0 b0 =+        let !n = A.length ary0+        in runST $ do+            mary <- A.new_ n+            step ary0 mary b0 0 0 1 n+      where+        step :: A.Array (HashMap k v1) -> A.MArray s (HashMap k v2)+             -> Bitmap -> Int -> Int -> Bitmap -> Int+             -> ST s (HashMap k v2)+        step !ary !mary !b i !j !bi n+            | i >= n = case j of+                0 -> return Empty+                1 -> do+                    ch <- A.read mary 0+                    case ch of+                      t | isLeafOrCollision t -> return t+                      _                       -> BitmapIndexed b <$> A.trim mary 1+                _ -> do+                    ary2 <- A.trim mary j+                    return $! if j == maxChildren+                              then Full ary2+                              else BitmapIndexed b ary2+            | bi .&. b == 0 = step ary mary b i j (bi `unsafeShiftL` 1) n+            | otherwise = case go (A.index ary i) of+                Empty -> step ary mary (b .&. complement bi) (i+1) j+                         (bi `unsafeShiftL` 1) n+                t     -> do A.write mary j t+                            step ary mary b (i+1) (j+1) (bi `unsafeShiftL` 1) n++    filterC ary0 h =+        let !n = A.length ary0+        in runST $ do+            mary <- A.new_ n+            step ary0 mary 0 0 n+      where+        step :: A.Array (Leaf k v1) -> A.MArray s (Leaf k v2)+             -> Int -> Int -> Int+             -> ST s (HashMap k v2)+        step !ary !mary i !j n+            | i >= n    = case j of+                0 -> return Empty+                1 -> do l <- A.read mary 0+                        return $! Leaf h l+                _ | i == j -> do ary2 <- A.unsafeFreeze mary+                                 return $! Collision h ary2+                  | otherwise -> do ary2 <- A.trim mary j+                                    return $! Collision h ary2+            | Just el <- onColl $! A.index ary i+                = A.write mary j el >> step ary mary (i+1) (j+1) n+            | otherwise = step ary mary (i+1) j n+{-# INLINE filterMapAux #-}++-- | /O(n)/ Filter this map by retaining only elements which values+-- satisfy a predicate.+filter :: (v -> Bool) -> HashMap k v -> HashMap k v+filter p = filterWithKey (\_ v -> p v)+{-# INLINE filter #-}++------------------------------------------------------------------------+-- * Conversions++-- TODO: Improve fusion rules by modelled them after the Prelude ones+-- on lists.++-- | /O(n)/ Return a list of this map's keys.  The list is produced+-- lazily.+keys :: HashMap k v -> [k]+keys = L.map fst . toList+{-# INLINE keys #-}++-- | /O(n)/ Return a list of this map's values.  The list is produced+-- lazily.+elems :: HashMap k v -> [v]+elems = L.map snd . toList+{-# INLINE elems #-}++------------------------------------------------------------------------+-- ** Lists++-- | /O(n)/ Return a list of this map's elements.  The list is+-- produced lazily. The order of its elements is unspecified.+toList :: HashMap k v -> [(k, v)]+toList t = build (\ c z -> foldrWithKey (curry c) z t)+{-# INLINE toList #-}++-- | /O(n)/ Construct a map with the supplied mappings.  If the list+-- contains duplicate mappings, the later mappings take precedence.+fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v+fromList = L.foldl' (\ m (k, v) -> unsafeInsert k v m) empty+{-# INLINABLE fromList #-}++-- | /O(n*log n)/ Construct a map from a list of elements.  Uses+-- the provided function @f@ to merge duplicate entries with+-- @(f newVal oldVal)@.+--+-- === Examples+--+-- Given a list @xs@, create a map with the number of occurrences of each+-- element in @xs@:+--+-- > let xs = ['a', 'b', 'a']+-- > in fromListWith (+) [ (x, 1) | x <- xs ]+-- >+-- > = fromList [('a', 2), ('b', 1)]+--+-- Given a list of key-value pairs @xs :: [(k, v)]@, group all values by their+-- keys and return a @HashMap k [v]@.+--+-- > let xs = [('a', 1), ('b', 2), ('a', 3)]+-- > in fromListWith (++) [ (k, [v]) | (k, v) <- xs ]+-- >+-- > = fromList [('a', [3, 1]), ('b', [2])]+--+-- Note that the lists in the resulting map contain elements in reverse order+-- from their occurences in the original list.+--+-- More generally, duplicate entries are accumulated as follows;+-- this matters when @f@ is not commutative or not associative.+--+-- > fromListWith f [(k, a), (k, b), (k, c), (k, d)]+-- > = fromList [(k, f d (f c (f b a)))]+fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v+fromListWith f = L.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty+{-# INLINE fromListWith #-}++-- | /O(n*log n)/ Construct a map from a list of elements.  Uses+-- the provided function to merge duplicate entries.+--+-- === Examples+--+-- Given a list of key-value pairs where the keys are of different flavours, e.g:+--+-- > data Key = Div | Sub+--+-- and the values need to be combined differently when there are duplicates,+-- depending on the key:+--+-- > combine Div = div+-- > combine Sub = (-)+--+-- then @fromListWithKey@ can be used as follows:+--+-- > fromListWithKey combine [(Div, 2), (Div, 6), (Sub, 2), (Sub, 3)]+-- > = fromList [(Div, 3), (Sub, 1)]+--+-- More generally, duplicate entries are accumulated as follows;+--+-- > fromListWith f [(k, a), (k, b), (k, c), (k, d)]+-- > = fromList [(k, f k d (f k c (f k b a)))]+--+-- @since 0.2.11+fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v+fromListWithKey f = L.foldl' (\ m (k, v) -> unsafeInsertWithKey f k v m) empty+{-# INLINE fromListWithKey #-}++------------------------------------------------------------------------+-- Array operations++-- | /O(n)/ Look up the value associated with the given key in an+-- array.+lookupInArrayCont ::+#if __GLASGOW_HASKELL__ >= 802+  forall rep (r :: TYPE rep) k v.+#else+  forall r k v.+#endif+  Eq k => ((# #) -> r) -> (v -> Int -> r) -> k -> A.Array (Leaf k v) -> r+lookupInArrayCont absent present k0 ary0 = go k0 ary0 0 (A.length ary0)+  where+    go :: Eq k => k -> A.Array (Leaf k v) -> Int -> Int -> r+    go !k !ary !i !n+        | i >= n    = absent (# #)+        | otherwise = case A.index ary i of+            (L kx v)+                | k == kx   -> present v i+                | otherwise -> go k ary (i+1) n+{-# INLINE lookupInArrayCont #-}++-- | /O(n)/ Lookup the value associated with the given key in this+-- array.  Returns 'Nothing' if the key wasn't found.+indexOf :: Eq k => k -> A.Array (Leaf k v) -> Maybe Int+indexOf k0 ary0 = go k0 ary0 0 (A.length ary0)+  where+    go !k !ary !i !n+        | i >= n    = Nothing+        | otherwise = case A.index ary i of+            (L kx _)+                | k == kx   -> Just i+                | otherwise -> go k ary (i+1) n+{-# INLINABLE indexOf #-}++updateWith# :: Eq k => (v -> (# v #)) -> k -> A.Array (Leaf k v) -> A.Array (Leaf k v)+updateWith# f k0 ary0 = go k0 ary0 0 (A.length ary0)+  where+    go !k !ary !i !n+        | i >= n    = ary+        | otherwise = case A.index ary i of+            (L kx y) | k == kx -> case f y of+                          (# y' #)+                             | ptrEq y y' -> ary+                             | otherwise -> A.update ary i (L k y')+                     | otherwise -> go k ary (i+1) n+{-# INLINABLE updateWith# #-}++updateOrSnocWith :: Eq k => (v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)+                 -> A.Array (Leaf k v)+updateOrSnocWith f = updateOrSnocWithKey (const f)+{-# INLINABLE updateOrSnocWith #-}++updateOrSnocWithKey :: Eq k => (k -> v -> v -> (# v #)) -> k -> v -> A.Array (Leaf k v)+                 -> A.Array (Leaf k v)+updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)+  where+    go !k v !ary !i !n+        | i >= n = A.run $ do+            -- Not found, append to the end.+            mary <- A.new_ (n + 1)+            A.copy ary 0 mary 0 n+            A.write mary n (L k v)+            return mary+        | L kx y <- A.index ary i+        , k == kx+        , (# v2 #) <- f k v y+            = A.update ary i (L k v2)+        | otherwise+            = go k v ary (i+1) n+{-# INLINABLE updateOrSnocWithKey #-}++updateOrConcatWith :: Eq k => (v -> v -> v) -> A.Array (Leaf k v) -> A.Array (Leaf k v) -> A.Array (Leaf k v)+updateOrConcatWith f = updateOrConcatWithKey (const f)+{-# INLINABLE updateOrConcatWith #-}++updateOrConcatWithKey :: Eq k => (k -> v -> v -> v) -> A.Array (Leaf k v) -> A.Array (Leaf k v) -> A.Array (Leaf k v)+updateOrConcatWithKey f ary1 ary2 = A.run $ do+    -- TODO: instead of mapping and then folding, should we traverse?+    -- We'll have to be careful to avoid allocating pairs or similar.++    -- first: look up the position of each element of ary2 in ary1+    let indices = A.map' (\(L k _) -> indexOf k ary1) ary2+    -- that tells us how large the overlap is:+    -- count number of Nothing constructors+    let nOnly2 = A.foldl' (\n -> maybe (n+1) (const n)) 0 indices+    let n1 = A.length ary1+    let n2 = A.length ary2+    -- copy over all elements from ary1+    mary <- A.new_ (n1 + nOnly2)+    A.copy ary1 0 mary 0 n1+    -- append or update all elements from ary2+    let go !iEnd !i2+          | i2 >= n2 = return ()+          | otherwise = case A.index indices i2 of+               Just i1 -> do -- key occurs in both arrays, store combination in position i1+                             L k v1 <- A.indexM ary1 i1+                             L _ v2 <- A.indexM ary2 i2+                             A.write mary i1 (L k (f k v1 v2))+                             go iEnd (i2+1)+               Nothing -> do -- key is only in ary2, append to end+                             A.write mary iEnd =<< A.indexM ary2 i2+                             go (iEnd+1) (i2+1)+    go n1 0+    return mary+{-# INLINABLE updateOrConcatWithKey #-}++-- | /O(n*m)/ Check if the first array is a subset of the second array.+subsetArray :: Eq k => (v1 -> v2 -> Bool) -> A.Array (Leaf k v1) -> A.Array (Leaf k v2) -> Bool+subsetArray cmpV ary1 ary2 = A.length ary1 <= A.length ary2 && A.all inAry2 ary1+  where+    inAry2 (L k1 v1) = lookupInArrayCont (\_ -> False) (\v2 _ -> cmpV v1 v2) k1 ary2+    {-# INLINE inAry2 #-}++------------------------------------------------------------------------+-- Manually unrolled loops++-- | /O(n)/ Update the element at the given position in this array.+update16 :: A.Array e -> Int -> e -> A.Array e+update16 ary idx b = runST (update16M ary idx b)+{-# INLINE update16 #-}++-- | /O(n)/ Update the element at the given position in this array.+update16M :: A.Array e -> Int -> e -> ST s (A.Array e)+update16M ary idx b = do+    mary <- clone16 ary+    A.write mary idx b+    A.unsafeFreeze mary+{-# INLINE update16M #-}++-- | /O(n)/ Update the element at the given position in this array, by applying a function to it.+update16With' :: A.Array e -> Int -> (e -> e) -> A.Array e+update16With' ary idx f+  | (# x #) <- A.index# ary idx+  = update16 ary idx $! f x+{-# INLINE update16With' #-}++-- | Unsafely clone an array of 16 elements.  The length of the input+-- array is not checked.+clone16 :: A.Array e -> ST s (A.MArray s e)+clone16 ary =+    A.thaw ary 0 16++------------------------------------------------------------------------+-- Bit twiddling++bitsPerSubkey :: Int+bitsPerSubkey = 4++maxChildren :: Int+maxChildren = 1 `unsafeShiftL` bitsPerSubkey++subkeyMask :: Bitmap+subkeyMask = 1 `unsafeShiftL` bitsPerSubkey - 1++sparseIndex :: Bitmap -> Bitmap -> Int+sparseIndex b m = popCount (b .&. (m - 1))++mask :: Word -> Shift -> Bitmap+mask w s = 1 `unsafeShiftL` index w s+{-# INLINE mask #-}++-- | Mask out the 'bitsPerSubkey' bits used for indexing at this level+-- of the tree.+index :: Hash -> Shift -> Int+index w s = fromIntegral $ (unsafeShiftR w s) .&. subkeyMask+{-# INLINE index #-}++-- | A bitmask with the 'bitsPerSubkey' least significant bits set.+fullNodeMask :: Bitmap+fullNodeMask = complement (complement 0 `unsafeShiftL` maxChildren)+{-# INLINE fullNodeMask #-}++-- | Check if two the two arguments are the same value.  N.B. This+-- function might give false negatives (due to GC moving objects.)+ptrEq :: a -> a -> Bool+ptrEq x y = isTrue# (reallyUnsafePtrEquality# x y ==# 1#)+{-# INLINE ptrEq #-}++------------------------------------------------------------------------+-- IsList instance+instance (Eq k, Hashable k) => Exts.IsList (HashMap k v) where+    type Item (HashMap k v) = (k, v)+    fromList = fromList+    toList   = toList
+ Data/HashMap/Internal/Array.hs view
@@ -0,0 +1,623 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples, ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}+{-# OPTIONS_HADDOCK not-home #-}++-- | = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.+--+-- = Description+--+-- Zero based arrays.+--+-- Note that no bounds checking are performed.+module Data.HashMap.Internal.Array+    ( Array+    , MArray++      -- * Creation+    , new+    , new_+    , singleton+    , singletonM+    , pair++      -- * Basic interface+    , length+    , lengthM+    , read+    , write+    , index+    , indexM+    , index#+    , update+    , updateWith'+    , unsafeUpdateM+    , insert+    , insertM+    , delete+    , sameArray1+    , trim++    , unsafeFreeze+    , unsafeThaw+    , unsafeSameArray+    , run+    , copy+    , copyM++      -- * Folds+    , foldl+    , foldl'+    , foldr+    , foldr'+    , foldMap+    , all++    , thaw+    , map+    , map'+    , traverse+    , traverse'+    , toList+    , fromList+    ) where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative (Applicative (..), (<$>))+#endif+import Control.Applicative (liftA2)+import Control.DeepSeq+import GHC.Exts(Int(..), Int#, reallyUnsafePtrEquality#, tagToEnum#, unsafeCoerce#, State#)+import GHC.ST (ST(..))+import Control.Monad.ST (stToIO)++#if __GLASGOW_HASKELL__ >= 709+import Prelude hiding (filter, foldMap, foldr, foldl, length, map, read, traverse, all)+#else+import Prelude hiding (filter, foldr, foldl, length, map, read, all)+#endif++#if __GLASGOW_HASKELL__ >= 710+import GHC.Exts (SmallArray#, newSmallArray#, readSmallArray#, writeSmallArray#,+                 indexSmallArray#, unsafeFreezeSmallArray#, unsafeThawSmallArray#,+                 SmallMutableArray#, sizeofSmallArray#, copySmallArray#, thawSmallArray#,+                 sizeofSmallMutableArray#, copySmallMutableArray#, cloneSmallMutableArray#)++#else+import GHC.Exts (Array#, newArray#, readArray#, writeArray#,+                 indexArray#, unsafeFreezeArray#, unsafeThawArray#,+                 MutableArray#, sizeofArray#, copyArray#, thawArray#,+                 sizeofMutableArray#, copyMutableArray#, cloneMutableArray#)+import Data.Monoid (Monoid (..))+#endif++#if defined(ASSERTS)+import qualified Prelude+#endif++import Data.HashMap.Internal.Unsafe (runST)+import Control.Monad ((>=>))+++#if __GLASGOW_HASKELL__ >= 710+type Array# a = SmallArray# a+type MutableArray# a = SmallMutableArray# a++newArray# :: Int# -> a -> State# d -> (# State# d, SmallMutableArray# d a #)+newArray# = newSmallArray#++unsafeFreezeArray# :: SmallMutableArray# d a+                   -> State# d -> (# State# d, SmallArray# a #)+unsafeFreezeArray# = unsafeFreezeSmallArray#++readArray# :: SmallMutableArray# d a+           -> Int# -> State# d -> (# State# d, a #)+readArray# = readSmallArray#++writeArray# :: SmallMutableArray# d a+            -> Int# -> a -> State# d -> State# d+writeArray# = writeSmallArray#++indexArray# :: SmallArray# a -> Int# -> (# a #)+indexArray# = indexSmallArray#++unsafeThawArray# :: SmallArray# a+                 -> State# d -> (# State# d, SmallMutableArray# d a #)+unsafeThawArray# = unsafeThawSmallArray#++sizeofArray# :: SmallArray# a -> Int#+sizeofArray# = sizeofSmallArray#++copyArray# :: SmallArray# a+           -> Int#+           -> SmallMutableArray# d a+           -> Int#+           -> Int#+           -> State# d+           -> State# d+copyArray# = copySmallArray#++cloneMutableArray# :: SmallMutableArray# s a+                   -> Int#+                   -> Int#+                   -> State# s+                   -> (# State# s, SmallMutableArray# s a #)+cloneMutableArray# = cloneSmallMutableArray#++thawArray# :: SmallArray# a+           -> Int#+           -> Int#+           -> State# d+           -> (# State# d, SmallMutableArray# d a #)+thawArray# = thawSmallArray#++sizeofMutableArray# :: SmallMutableArray# s a -> Int#+sizeofMutableArray# = sizeofSmallMutableArray#++copyMutableArray# :: SmallMutableArray# d a+                  -> Int#+                  -> SmallMutableArray# d a+                  -> Int#+                  -> Int#+                  -> State# d+                  -> State# d+copyMutableArray# = copySmallMutableArray#+#endif++------------------------------------------------------------------------++#if defined(ASSERTS)+-- This fugly hack is brought by GHC's apparent reluctance to deal+-- with MagicHash and UnboxedTuples when inferring types. Eek!+# define CHECK_BOUNDS(_func_,_len_,_k_) \+if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.HashMap.Internal.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else+# define CHECK_OP(_func_,_op_,_lhs_,_rhs_) \+if not ((_lhs_) _op_ (_rhs_)) then error ("Data.HashMap.Internal.Array." ++ (_func_) ++ ": Check failed: _lhs_ _op_ _rhs_ (" ++ show (_lhs_) ++ " vs. " ++ show (_rhs_) ++ ")") else+# define CHECK_GT(_func_,_lhs_,_rhs_) CHECK_OP(_func_,>,_lhs_,_rhs_)+# define CHECK_LE(_func_,_lhs_,_rhs_) CHECK_OP(_func_,<=,_lhs_,_rhs_)+# define CHECK_EQ(_func_,_lhs_,_rhs_) CHECK_OP(_func_,==,_lhs_,_rhs_)+#else+# define CHECK_BOUNDS(_func_,_len_,_k_)+# define CHECK_OP(_func_,_op_,_lhs_,_rhs_)+# define CHECK_GT(_func_,_lhs_,_rhs_)+# define CHECK_LE(_func_,_lhs_,_rhs_)+# define CHECK_EQ(_func_,_lhs_,_rhs_)+#endif++data Array a = Array {+      unArray :: !(Array# a)+    }++instance Show a => Show (Array a) where+    show = show . toList++-- Determines whether two arrays have the same memory address.+-- This is more reliable than testing pointer equality on the+-- Array wrappers, but it's still slightly bogus.+unsafeSameArray :: Array a -> Array b -> Bool+unsafeSameArray (Array xs) (Array ys) =+  tagToEnum# (unsafeCoerce# reallyUnsafePtrEquality# xs ys)++sameArray1 :: (a -> b -> Bool) -> Array a -> Array b -> Bool+sameArray1 eq !xs0 !ys0+  | lenxs /= lenys = False+  | otherwise = go 0 xs0 ys0+  where+    go !k !xs !ys+      | k == lenxs = True+      | (# x #) <- index# xs k+      , (# y #) <- index# ys k+      = eq x y && go (k + 1) xs ys++    !lenxs = length xs0+    !lenys = length ys0++length :: Array a -> Int+length ary = I# (sizeofArray# (unArray ary))+{-# INLINE length #-}++data MArray s a = MArray {+      unMArray :: !(MutableArray# s a)+    }++lengthM :: MArray s a -> Int+lengthM mary = I# (sizeofMutableArray# (unMArray mary))+{-# INLINE lengthM #-}++------------------------------------------------------------------------++instance NFData a => NFData (Array a) where+    rnf = rnfArray++rnfArray :: NFData a => Array a -> ()+rnfArray ary0 = go ary0 n0 0+  where+    n0 = length ary0+    go !ary !n !i+        | i >= n = ()+        | (# x #) <- index# ary i+        = rnf x `seq` go ary n (i+1)+-- We use index# just in case GHC can't see that the+-- relevant rnf is strict, or in case it actually isn't.+{-# INLINE rnfArray #-}++-- | Create a new mutable array of specified size, in the specified+-- state thread, with each element containing the specified initial+-- value.+new :: Int -> a -> ST s (MArray s a)+new (I# n#) b =+    CHECK_GT("new",n,(0 :: Int))+    ST $ \s ->+        case newArray# n# b s of+            (# s', ary #) -> (# s', MArray ary #)+{-# INLINE new #-}++new_ :: Int -> ST s (MArray s a)+new_ n = new n undefinedElem++singleton :: a -> Array a+singleton x = runST (singletonM x)+{-# INLINE singleton #-}++singletonM :: a -> ST s (Array a)+singletonM x = new 1 x >>= unsafeFreeze+{-# INLINE singletonM #-}++pair :: a -> a -> Array a+pair x y = run $ do+    ary <- new 2 x+    write ary 1 y+    return ary+{-# INLINE pair #-}++read :: MArray s a -> Int -> ST s a+read ary _i@(I# i#) = ST $ \ s ->+    CHECK_BOUNDS("read", lengthM ary, _i)+        readArray# (unMArray ary) i# s+{-# INLINE read #-}++write :: MArray s a -> Int -> a -> ST s ()+write ary _i@(I# i#) b = ST $ \ s ->+    CHECK_BOUNDS("write", lengthM ary, _i)+        case writeArray# (unMArray ary) i# b s of+            s' -> (# s' , () #)+{-# INLINE write #-}++index :: Array a -> Int -> a+index ary _i@(I# i#) =+    CHECK_BOUNDS("index", length ary, _i)+        case indexArray# (unArray ary) i# of (# b #) -> b+{-# INLINE index #-}++index# :: Array a -> Int -> (# a #)+index# ary _i@(I# i#) =+    CHECK_BOUNDS("index#", length ary, _i)+        indexArray# (unArray ary) i#+{-# INLINE index# #-}++indexM :: Array a -> Int -> ST s a+indexM ary _i@(I# i#) =+    CHECK_BOUNDS("indexM", length ary, _i)+        case indexArray# (unArray ary) i# of (# b #) -> return b+{-# INLINE indexM #-}++unsafeFreeze :: MArray s a -> ST s (Array a)+unsafeFreeze mary+    = ST $ \s -> case unsafeFreezeArray# (unMArray mary) s of+                   (# s', ary #) -> (# s', Array ary #)+{-# INLINE unsafeFreeze #-}++unsafeThaw :: Array a -> ST s (MArray s a)+unsafeThaw ary+    = ST $ \s -> case unsafeThawArray# (unArray ary) s of+                   (# s', mary #) -> (# s', MArray mary #)+{-# INLINE unsafeThaw #-}++run :: (forall s . ST s (MArray s e)) -> Array e+run act = runST $ act >>= unsafeFreeze+{-# INLINE run #-}++-- | Unsafely copy the elements of an array. Array bounds are not checked.+copy :: Array e -> Int -> MArray s e -> Int -> Int -> ST s ()+copy !src !_sidx@(I# sidx#) !dst !_didx@(I# didx#) _n@(I# n#) =+    CHECK_LE("copy", _sidx + _n, length src)+    CHECK_LE("copy", _didx + _n, lengthM dst)+        ST $ \ s# ->+        case copyArray# (unArray src) sidx# (unMArray dst) didx# n# s# of+            s2 -> (# s2, () #)++-- | Unsafely copy the elements of an array. Array bounds are not checked.+copyM :: MArray s e -> Int -> MArray s e -> Int -> Int -> ST s ()+copyM !src !_sidx@(I# sidx#) !dst !_didx@(I# didx#) _n@(I# n#) =+    CHECK_BOUNDS("copyM: src", lengthM src, _sidx + _n - 1)+    CHECK_BOUNDS("copyM: dst", lengthM dst, _didx + _n - 1)+    ST $ \ s# ->+    case copyMutableArray# (unMArray src) sidx# (unMArray dst) didx# n# s# of+        s2 -> (# s2, () #)++cloneM :: MArray s a -> Int -> Int -> ST s (MArray s a)+cloneM _mary@(MArray mary#) _off@(I# off#) _len@(I# len#) =+    CHECK_BOUNDS("cloneM_off", lengthM _mary, _off - 1)+    CHECK_BOUNDS("cloneM_end", lengthM _mary, _off + _len - 1)+    ST $ \ s ->+    case cloneMutableArray# mary# off# len# s of+      (# s', mary'# #) -> (# s', MArray mary'# #)++-- | Create a new array of the @n@ first elements of @mary@.+trim :: MArray s a -> Int -> ST s (Array a)+trim mary n = cloneM mary 0 n >>= unsafeFreeze+{-# INLINE trim #-}++-- | /O(n)/ Insert an element at the given position in this array,+-- increasing its size by one.+insert :: Array e -> Int -> e -> Array e+insert ary idx b = runST (insertM ary idx b)+{-# INLINE insert #-}++-- | /O(n)/ Insert an element at the given position in this array,+-- increasing its size by one.+insertM :: Array e -> Int -> e -> ST s (Array e)+insertM ary idx b =+    CHECK_BOUNDS("insertM", count + 1, idx)+        do mary <- new_ (count+1)+           copy ary 0 mary 0 idx+           write mary idx b+           copy ary idx mary (idx+1) (count-idx)+           unsafeFreeze mary+  where !count = length ary+{-# INLINE insertM #-}++-- | /O(n)/ Update the element at the given position in this array.+update :: Array e -> Int -> e -> Array e+update ary idx b = runST (updateM ary idx b)+{-# INLINE update #-}++-- | /O(n)/ Update the element at the given position in this array.+updateM :: Array e -> Int -> e -> ST s (Array e)+updateM ary idx b =+    CHECK_BOUNDS("updateM", count, idx)+        do mary <- thaw ary 0 count+           write mary idx b+           unsafeFreeze mary+  where !count = length ary+{-# INLINE updateM #-}++-- | /O(n)/ Update the element at the given positio in this array, by+-- applying a function to it.  Evaluates the element to WHNF before+-- inserting it into the array.+updateWith' :: Array e -> Int -> (e -> e) -> Array e+updateWith' ary idx f+  | (# x #) <- index# ary idx+  = update ary idx $! f x+{-# INLINE updateWith' #-}++-- | /O(1)/ Update the element at the given position in this array,+-- without copying.+unsafeUpdateM :: Array e -> Int -> e -> ST s ()+unsafeUpdateM ary idx b =+    CHECK_BOUNDS("unsafeUpdateM", length ary, idx)+        do mary <- unsafeThaw ary+           write mary idx b+           _ <- unsafeFreeze mary+           return ()+{-# INLINE unsafeUpdateM #-}++foldl' :: (b -> a -> b) -> b -> Array a -> b+foldl' f = \ z0 ary0 -> go ary0 (length ary0) 0 z0+  where+    go ary n i !z+        | i >= n = z+        | otherwise+        = case index# ary i of+            (# x #) -> go ary n (i+1) (f z x)+{-# INLINE foldl' #-}++foldr' :: (a -> b -> b) -> b -> Array a -> b+foldr' f = \ z0 ary0 -> go ary0 (length ary0 - 1) z0+  where+    go !_ary (-1) z = z+    go !ary i !z+      | (# x #) <- index# ary i+      = go ary (i - 1) (f x z)+{-# INLINE foldr' #-}++foldr :: (a -> b -> b) -> b -> Array a -> b+foldr f = \ z0 ary0 -> go ary0 (length ary0) 0 z0+  where+    go ary n i z+        | i >= n = z+        | otherwise+        = case index# ary i of+            (# x #) -> f x (go ary n (i+1) z)+{-# INLINE foldr #-}++foldl :: (b -> a -> b) -> b -> Array a -> b+foldl f = \ z0 ary0 -> go ary0 (length ary0 - 1) z0+  where+    go _ary (-1) z = z+    go ary i z+      | (# x #) <- index# ary i+      = f (go ary (i - 1) z) x+{-# INLINE foldl #-}++-- We go to a bit of trouble here to avoid appending an extra mempty.+-- The below implementation is by Mateusz Kowalczyk, who indicates that+-- benchmarks show it to be faster than one that avoids lifting out+-- lst.+foldMap :: Monoid m => (a -> m) -> Array a -> m+foldMap f = \ary0 -> case length ary0 of+  0 -> mempty+  len ->+    let !lst = len - 1+        go i | (# x #) <- index# ary0 i, let fx = f x =+          if i == lst then fx else fx `mappend` go (i + 1)+    in go 0+{-# INLINE foldMap #-}++-- | Verifies that a predicate holds for all elements of an array.+all :: (a -> Bool) -> Array a -> Bool+all p = foldr (\a acc -> p a && acc) True+{-# INLINE all #-}++undefinedElem :: a+undefinedElem = error "Data.HashMap.Internal.Array: Undefined element"+{-# NOINLINE undefinedElem #-}++thaw :: Array e -> Int -> Int -> ST s (MArray s e)+thaw !ary !_o@(I# o#) (I# n#) =+    CHECK_LE("thaw", _o + n, length ary)+        ST $ \ s -> case thawArray# (unArray ary) o# n# s of+            (# s2, mary# #) -> (# s2, MArray mary# #)+{-# INLINE thaw #-}++-- | /O(n)/ Delete an element at the given position in this array,+-- decreasing its size by one.+delete :: Array e -> Int -> Array e+delete ary idx = runST (deleteM ary idx)+{-# INLINE delete #-}++-- | /O(n)/ Delete an element at the given position in this array,+-- decreasing its size by one.+deleteM :: Array e -> Int -> ST s (Array e)+deleteM ary idx = do+    CHECK_BOUNDS("deleteM", count, idx)+        do mary <- new_ (count-1)+           copy ary 0 mary 0 idx+           copy ary (idx+1) mary idx (count-(idx+1))+           unsafeFreeze mary+  where !count = length ary+{-# INLINE deleteM #-}++map :: (a -> b) -> Array a -> Array b+map f = \ ary ->+    let !n = length ary+    in run $ do+        mary <- new_ n+        go ary mary 0 n+  where+    go ary mary i n+        | i >= n    = return mary+        | otherwise = do+             x <- indexM ary i+             write mary i $ f x+             go ary mary (i+1) n+{-# INLINE map #-}++-- | Strict version of 'map'.+map' :: (a -> b) -> Array a -> Array b+map' f = \ ary ->+    let !n = length ary+    in run $ do+        mary <- new_ n+        go ary mary 0 n+  where+    go ary mary i n+        | i >= n    = return mary+        | otherwise = do+             x <- indexM ary i+             write mary i $! f x+             go ary mary (i+1) n+{-# INLINE map' #-}++fromList :: Int -> [a] -> Array a+fromList n xs0 =+    CHECK_EQ("fromList", n, Prelude.length xs0)+        run $ do+            mary <- new_ n+            go xs0 mary 0+  where+    go [] !mary !_   = return mary+    go (x:xs) mary i = do write mary i x+                          go xs mary (i+1)++toList :: Array a -> [a]+toList = foldr (:) []++newtype STA a = STA {_runSTA :: forall s. MutableArray# s a -> ST s (Array a)}++runSTA :: Int -> STA a -> Array a+runSTA !n (STA m) = runST $ new_ n >>= \ (MArray ar) -> m ar++traverse :: Applicative f => (a -> f b) -> Array a -> f (Array b)+traverse f = \ !ary ->+  let+    !len = length ary+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)+      | (# x #) <- index# ary i+      = liftA2 (\b (STA m) -> STA $ \mary ->+                  write (MArray mary) i b >> m mary)+               (f x) (go (i + 1))+  in runSTA len <$> go 0+{-# INLINE [1] traverse #-}++-- TODO: Would it be better to just use a lazy traversal+-- and then force the elements of the result? My guess is+-- yes.+traverse' :: Applicative f => (a -> f b) -> Array a -> f (Array b)+traverse' f = \ !ary ->+  let+    !len = length ary+    go !i+      | i == len = pure $ STA $ \mary -> unsafeFreeze (MArray mary)+      | (# x #) <- index# ary i+      = liftA2 (\ !b (STA m) -> STA $ \mary ->+                    write (MArray mary) i b >> m mary)+               (f x) (go (i + 1))+  in runSTA len <$> go 0+{-# INLINE [1] traverse' #-}++-- Traversing in ST, we don't need to get fancy; we+-- can just do it directly.+traverseST :: (a -> ST s b) -> Array a -> ST s (Array b)+traverseST f = \ ary0 ->+  let+    !len = length ary0+    go k !mary+      | k == len = return mary+      | otherwise = do+          x <- indexM ary0 k+          y <- f x+          write mary k y+          go (k + 1) mary+  in new_ len >>= (go 0 >=> unsafeFreeze)+{-# INLINE traverseST #-}++traverseIO :: (a -> IO b) -> Array a -> IO (Array b)+traverseIO f = \ ary0 ->+  let+    !len = length ary0+    go k !mary+      | k == len = return mary+      | otherwise = do+          x <- stToIO $ indexM ary0 k+          y <- f x+          stToIO $ write mary k y+          go (k + 1) mary+  in stToIO (new_ len) >>= (go 0 >=> stToIO . unsafeFreeze)+{-# INLINE traverseIO #-}+++-- Why don't we have similar RULES for traverse'? The efficient+-- way to traverse strictly in IO or ST is to force results as+-- they come in, which leads to different semantics. In particular,+-- we need to ensure that+--+--  traverse' (\x -> print x *> pure undefined) xs+--+-- will actually print all the values and then return undefined.+-- We could add a strict mapMWithIndex, operating in an arbitrary+-- Monad, that supported such rules, but we don't have that right now.+{-# RULES+"traverse/ST" forall f. traverse f = traverseST f+"traverse/IO" forall f. traverse f = traverseIO f+ #-}
+ Data/HashMap/Internal/List.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}+{-# OPTIONS_HADDOCK not-home #-}++-- | = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.+--+-- = Description+--+-- Extra list functions+--+-- In separate module to aid testing.+module Data.HashMap.Internal.List+    ( isPermutationBy+    , deleteBy+    , unorderedCompare+    ) where++import Data.Maybe (fromMaybe)+import Data.List (sortBy)+import Data.Monoid+import Prelude++-- Note: previous implemenation isPermutation = null (as // bs)+-- was O(n^2) too.+--+-- This assumes lists are of equal length+isPermutationBy :: (a -> b -> Bool) -> [a] -> [b] -> Bool+isPermutationBy f = go+  where+    f' = flip f++    go [] [] = True+    go (x : xs) (y : ys)+        | f x y         = go xs ys+        | otherwise     = fromMaybe False $ do+            xs' <- deleteBy f' y xs+            ys' <- deleteBy f x ys+            return (go xs' ys')+    go [] (_ : _) = False+    go (_ : _) [] = False++-- The idea:+--+-- Homogeonous version+--+-- uc :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering+-- uc c as bs = compare (sortBy c as) (sortBy c bs)+--+-- But as we have only (a -> b -> Ordering), we cannot directly compare+-- elements from the same list.+--+-- So when comparing elements from the list, we count how many elements are+-- "less and greater" in the other list, and use the count as a metric.+--+unorderedCompare :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering+unorderedCompare c as bs = go (sortBy cmpA as) (sortBy cmpB bs)+  where+    go [] [] = EQ+    go [] (_ : _) = LT+    go (_ : _) [] = GT+    go (x : xs) (y : ys) = c x y `mappend` go xs ys++    cmpA a a' = compare (inB a) (inB a')+    cmpB b b' = compare (inA b) (inA b')++    inB a = (length $ filter (\b -> c a b == GT) bs, negate $ length $ filter (\b -> c a b == LT) bs)+    inA b = (length $ filter (\a -> c a b == LT) as, negate $ length $ filter (\a -> c a b == GT) as)++-- Returns Nothing is nothing deleted+deleteBy              :: (a -> b -> Bool) -> a -> [b] -> Maybe [b]+deleteBy _  _ []      = Nothing+deleteBy eq x (y:ys)  = if x `eq` y then Just ys else fmap (y :) (deleteBy eq x ys)
+ Data/HashMap/Internal/Strict.hs view
@@ -0,0 +1,754 @@+{-# LANGUAGE BangPatterns, CPP, PatternGuards, MagicHash, UnboxedTuples #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE Trustworthy #-}+{-# OPTIONS_HADDOCK not-home #-}++------------------------------------------------------------------------+-- |+-- Module      :  Data.HashMap.Strict+-- Copyright   :  2010-2012 Johan Tibell+-- License     :  BSD-style+-- Maintainer  :  johan.tibell@gmail.com+-- Portability :  portable+--+-- = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.+--+-- = Description+--+-- A map from /hashable/ keys to values.  A map cannot contain+-- duplicate keys; each key can map to at most one value.  A 'HashMap'+-- makes no guarantees as to the order of its elements.+--+-- The implementation is based on /hash array mapped tries/.  A+-- 'HashMap' is often faster than other tree-based set types,+-- especially when key comparison is expensive, as in the case of+-- strings.+--+-- Many operations have a average-case complexity of /O(log n)/.  The+-- implementation uses a large base (i.e. 16) so in practice these+-- operations are constant time.+module Data.HashMap.Internal.Strict+    (+      -- * Strictness properties+      -- $strictness++      HashMap++      -- * Construction+    , empty+    , singleton++      -- * Basic interface+    , HM.null+    , size+    , HM.member+    , HM.lookup+    , (HM.!?)+    , HM.findWithDefault+    , lookupDefault+    , (!)+    , insert+    , insertWith+    , delete+    , adjust+    , update+    , alter+    , alterF+    , isSubmapOf+    , isSubmapOfBy++      -- * Combine+      -- ** Union+    , union+    , unionWith+    , unionWithKey+    , unions++      -- * Transformations+    , map+    , mapWithKey+    , traverseWithKey++      -- * Difference and intersection+    , difference+    , differenceWith+    , intersection+    , intersectionWith+    , intersectionWithKey++      -- * Folds+    , foldMapWithKey+    , foldr'+    , foldl'+    , foldrWithKey'+    , foldlWithKey'+    , HM.foldr+    , HM.foldl+    , foldrWithKey+    , foldlWithKey++      -- * Filter+    , HM.filter+    , filterWithKey+    , mapMaybe+    , mapMaybeWithKey++      -- * Conversions+    , keys+    , elems++      -- ** Lists+    , toList+    , fromList+    , fromListWith+    , fromListWithKey+    ) where++import Data.Bits ((.&.), (.|.))++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative (Applicative (..), (<$>))+#endif+import qualified Data.List as L+import Data.Hashable (Hashable)+import Prelude hiding (map, lookup)++import qualified Data.HashMap.Internal.Array as A+import qualified Data.HashMap.Internal as HM+import Data.HashMap.Internal hiding (+    alter, alterF, adjust, fromList, fromListWith, fromListWithKey,+    insert, insertWith,+    differenceWith, intersectionWith, intersectionWithKey, map, mapWithKey,+    mapMaybe, mapMaybeWithKey, singleton, update, unionWith, unionWithKey,+    traverseWithKey)+import Data.HashMap.Internal.Unsafe (runST)+#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity+#endif+import Control.Applicative (Const (..))+import Data.Coerce++-- $strictness+--+-- This module satisfies the following strictness properties:+--+-- 1. Key arguments are evaluated to WHNF;+--+-- 2. Keys and values are evaluated to WHNF before they are stored in+--    the map.++------------------------------------------------------------------------+-- * Construction++-- | /O(1)/ Construct a map with a single element.+singleton :: (Hashable k) => k -> v -> HashMap k v+singleton k !v = HM.singleton k v++------------------------------------------------------------------------+-- * Basic interface++-- | /O(log n)/ Associate the specified value with the specified+-- key in this map.  If this map previously contained a mapping for+-- the key, the old value is replaced.+insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v+insert k !v = HM.insert k v+{-# INLINABLE insert #-}++-- | /O(log n)/ Associate the value with the key in this map.  If+-- this map previously contained a mapping for the key, the old value+-- is replaced by the result of applying the given function to the new+-- and old value.  Example:+--+-- > insertWith f k v map+-- >   where f new old = new + old+insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v+           -> HashMap k v+insertWith f k0 v0 m0 = go h0 k0 v0 0 m0+  where+    h0 = hash k0+    go !h !k x !_ Empty = leaf h k x+    go h k x s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then leaf h k (f x y)+                    else x `seq` (collision h l (L k x))+        | otherwise = x `seq` runST (two s h k x hy t)+    go h k x s (BitmapIndexed b ary)+        | b .&. m == 0 =+            let ary' = A.insert ary i $! leaf h k x+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let st   = A.index ary i+                st'  = go h k x (s+bitsPerSubkey) st+                ary' = A.update ary i $! st'+            in BitmapIndexed b ary'+      where m = mask h s+            i = sparseIndex b m+    go h k x s (Full ary) =+        let st   = A.index ary i+            st'  = go h k x (s+bitsPerSubkey) st+            ary' = update16 ary i $! st'+        in Full ary'+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = Collision h (updateOrSnocWith f k x v)+        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE insertWith #-}++-- | In-place update version of insertWith+unsafeInsertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v+                 -> HashMap k v+unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0+{-# INLINABLE unsafeInsertWith #-}++unsafeInsertWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> k -> v -> HashMap k v+                    -> HashMap k v+unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)+  where+    h0 = hash k0+    go !h !k x !_ Empty = return $! leaf h k x+    go h k x s t@(Leaf hy l@(L ky y))+        | hy == h = if ky == k+                    then return $! leaf h k (f k x y)+                    else do+                        let l' = x `seq` (L k x)+                        return $! collision h l l'+        | otherwise = x `seq` two s h k x hy t+    go h k x s t@(BitmapIndexed b ary)+        | b .&. m == 0 = do+            ary' <- A.insertM ary i $! leaf h k x+            return $! bitmapIndexedOrFull (b .|. m) ary'+        | otherwise = do+            st <- A.indexM ary i+            st' <- go h k x (s+bitsPerSubkey) st+            A.unsafeUpdateM ary i st'+            return t+      where m = mask h s+            i = sparseIndex b m+    go h k x s t@(Full ary) = do+        st <- A.indexM ary i+        st' <- go h k x (s+bitsPerSubkey) st+        A.unsafeUpdateM ary i st'+        return t+      where i = index h s+    go h k x s t@(Collision hy v)+        | h == hy   = return $! Collision h (updateOrSnocWithKey f k x v)+        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)+{-# INLINABLE unsafeInsertWithKey #-}++-- | /O(log n)/ Adjust the value tied to a given key in this map only+-- if it is present. Otherwise, leave the map alone.+adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v+adjust f k0 m0 = go h0 k0 0 m0+  where+    h0 = hash k0+    go !_ !_ !_ Empty = Empty+    go h k _ t@(Leaf hy (L ky y))+        | hy == h && ky == k = leaf h k (f y)+        | otherwise          = t+    go h k s t@(BitmapIndexed b ary)+        | b .&. m == 0 = t+        | otherwise = let st   = A.index ary i+                          st'  = go h k (s+bitsPerSubkey) st+                          ary' = A.update ary i $! st'+                      in BitmapIndexed b ary'+      where m = mask h s+            i = sparseIndex b m+    go h k s (Full ary) =+        let i    = index h s+            st   = A.index ary i+            st'  = go h k (s+bitsPerSubkey) st+            ary' = update16 ary i $! st'+        in Full ary'+    go h k _ t@(Collision hy v)+        | h == hy   = Collision h (updateWith f k v)+        | otherwise = t+{-# INLINABLE adjust #-}++-- | /O(log n)/  The expression @('update' f k map)@ updates the value @x@ at @k@+-- (if it is in the map). If @(f x)@ is 'Nothing', the element is deleted.+-- If it is @('Just' y)@, the key @k@ is bound to the new value @y@.+update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a+update f = alter (>>= f)+{-# INLINABLE update #-}++-- | /O(log n)/  The expression @('alter' f k map)@ alters the value @x@ at @k@, or+-- absence thereof.+--+-- 'alter' can be used to insert, delete, or update a value in a map. In short:+--+-- @+-- 'lookup' k ('alter' f k m) = f ('lookup' k m)+-- @+alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v+alter f k m =+  case f (HM.lookup k m) of+    Nothing -> delete k m+    Just v  -> insert k v m+{-# INLINABLE alter #-}++-- | /O(log n)/  The expression (@'alterF' f k map@) alters the value @x@ at+-- @k@, or absence thereof.+--+-- 'alterF' can be used to insert, delete, or update a value in a map.+--+-- Note: 'alterF' is a flipped version of the 'at' combinator from+-- <https://hackage.haskell.org/package/lens/docs/Control-Lens-At.html#v:at Control.Lens.At>.+--+-- @since 0.2.10+alterF :: (Functor f, Eq k, Hashable k)+       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+-- Special care is taken to only calculate the hash once. When we rewrite+-- with RULES, we also ensure that we only compare the key for equality+-- once. We force the value of the map for consistency with the rewritten+-- version; otherwise someone could tell the difference using a lazy+-- @f@ and a functor that is similar to Const but not actually Const.+alterF f = \ !k !m ->+  let !h = hash k+      mv = lookup' h k m+  in (<$> f mv) $ \fres ->+    case fres of+      Nothing -> maybe m (const (delete' h k m)) mv+      Just !v' -> insert' h k v' m++-- We rewrite this function unconditionally in RULES, but we expose+-- an unfolding just in case it's used in a context where the rules+-- don't fire.+{-# INLINABLE [0] alterF #-}++#if MIN_VERSION_base(4,8,0)+-- See notes in Data.HashMap.Internal+test_bottom :: a+test_bottom = error "Data.HashMap.alterF internal error: hit test_bottom"++bogus# :: (# #) -> (# a #)+bogus# _ = error "Data.HashMap.alterF internal error: hit bogus#"++impossibleAdjust :: a+impossibleAdjust = error "Data.HashMap.alterF internal error: impossible adjust"++{-# RULES++-- See detailed notes on alterF rules in Data.HashMap.Internal.++"alterFWeird" forall f. alterF f =+    alterFWeird (f Nothing) (f (Just test_bottom)) f++"alterFconstant" forall (f :: Maybe a -> Identity (Maybe a)) x.+  alterFWeird x x f = \ !k !m ->+    Identity (case runIdentity x of {Nothing -> delete k m; Just a -> insert k a m})++"alterFinsertWith" [1] forall (f :: Maybe a -> Identity (Maybe a)) x y.+  alterFWeird (coerce (Just x)) (coerce (Just y)) f =+    coerce (insertModifying x (\mold -> case runIdentity (f (Just mold)) of+                                            Nothing -> bogus# (# #)+                                            Just !new -> (# new #)))++-- This rule is written a bit differently than the one for lazy+-- maps because the adjust here is strict. We could write it the+-- same general way anyway, but this seems simpler.+"alterFadjust" forall (f :: Maybe a -> Identity (Maybe a)) x.+  alterFWeird (coerce Nothing) (coerce (Just x)) f =+    coerce (adjust (\a -> case runIdentity (f (Just a)) of+                               Just a' -> a'+                               Nothing -> impossibleAdjust))++"alterFlookup" forall _ign1 _ign2 (f :: Maybe a -> Const r (Maybe a)) .+  alterFWeird _ign1 _ign2 f = \ !k !m -> Const (getConst (f (lookup k m)))+ #-}++-- This is a very unsafe version of alterF used for RULES. When calling+-- alterFWeird x y f, the following *must* hold:+--+-- x = f Nothing+-- y = f (Just _|_)+--+-- Failure to abide by these laws will make demons come out of your nose.+alterFWeird+       :: (Functor f, Eq k, Hashable k)+       => f (Maybe v)+       -> f (Maybe v)+       -> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+alterFWeird _ _ f = alterFEager f+{-# INLINE [0] alterFWeird #-}++-- | This is the default version of alterF that we use in most non-trivial+-- cases. It's called "eager" because it looks up the given key in the map+-- eagerly, whether or not the given function requires that information.+alterFEager :: (Functor f, Eq k, Hashable k)+       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)+alterFEager f !k !m = (<$> f mv) $ \fres ->+  case fres of++    ------------------------------+    -- Delete the key from the map.+    Nothing -> case lookupRes of++      -- Key did not exist in the map to begin with, no-op+      Absent -> m++      -- Key did exist, no collision+      Present _ collPos -> deleteKeyExists collPos h k m++    ------------------------------+    -- Update value+    Just v' -> case lookupRes of++      -- Key did not exist before, insert v' under a new key+      Absent -> insertNewKey h k v' m++      -- Key existed before, no hash collision+      Present v collPos -> v' `seq`+        if v `ptrEq` v'+        -- If the value is identical, no-op+        then m+        -- If the value changed, update the value.+        else insertKeyExists collPos h k v' m++  where !h = hash k+        !lookupRes = lookupRecordCollision h k m+        !mv = case lookupRes of+          Absent -> Nothing+          Present v _ -> Just v+{-# INLINABLE alterFEager #-}+#endif++------------------------------------------------------------------------+-- * Combine++-- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,+-- the provided function (first argument) will be used to compute the result.+unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v+          -> HashMap k v+unionWith f = unionWithKey (const f)+{-# INLINE unionWith #-}++-- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,+-- the provided function (first argument) will be used to compute the result.+unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v+          -> HashMap k v+unionWithKey f = go 0+  where+    -- empty vs. anything+    go !_ t1 Empty = t1+    go _ Empty t2 = t2+    -- leaf vs. leaf+    go s t1@(Leaf h1 l1@(L k1 v1)) t2@(Leaf h2 l2@(L k2 v2))+        | h1 == h2  = if k1 == k2+                      then leaf h1 k1 (f k1 v1 v2)+                      else collision h1 l1 l2+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Leaf h1 (L k1 v1)) t2@(Collision h2 ls2)+        | h1 == h2  = Collision h1 (updateOrSnocWithKey f k1 v1 ls2)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Collision h1 ls1) t2@(Leaf h2 (L k2 v2))+        | h1 == h2  = Collision h1 (updateOrSnocWithKey (flip . f) k2 v2 ls1)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    go s t1@(Collision h1 ls1) t2@(Collision h2 ls2)+        | h1 == h2  = Collision h1 (updateOrConcatWithKey f ls1 ls2)+        | otherwise = goDifferentHash s h1 h2 t1 t2+    -- branch vs. branch+    go s (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =+        let b'   = b1 .|. b2+            ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 b2 ary1 ary2+        in bitmapIndexedOrFull b' ary'+    go s (BitmapIndexed b1 ary1) (Full ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 fullNodeMask ary1 ary2+        in Full ary'+    go s (Full ary1) (BitmapIndexed b2 ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask b2 ary1 ary2+        in Full ary'+    go s (Full ary1) (Full ary2) =+        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask fullNodeMask+                   ary1 ary2+        in Full ary'+    -- leaf vs. branch+    go s (BitmapIndexed b1 ary1) t2+        | b1 .&. m2 == 0 = let ary' = A.insert ary1 i t2+                               b'   = b1 .|. m2+                           in bitmapIndexedOrFull b' ary'+        | otherwise      = let ary' = A.updateWith' ary1 i $ \st1 ->+                                   go (s+bitsPerSubkey) st1 t2+                           in BitmapIndexed b1 ary'+        where+          h2 = leafHashCode t2+          m2 = mask h2 s+          i = sparseIndex b1 m2+    go s t1 (BitmapIndexed b2 ary2)+        | b2 .&. m1 == 0 = let ary' = A.insert ary2 i $! t1+                               b'   = b2 .|. m1+                           in bitmapIndexedOrFull b' ary'+        | otherwise      = let ary' = A.updateWith' ary2 i $ \st2 ->+                                   go (s+bitsPerSubkey) t1 st2+                           in BitmapIndexed b2 ary'+      where+        h1 = leafHashCode t1+        m1 = mask h1 s+        i = sparseIndex b2 m1+    go s (Full ary1) t2 =+        let h2   = leafHashCode t2+            i    = index h2 s+            ary' = update16With' ary1 i $ \st1 -> go (s+bitsPerSubkey) st1 t2+        in Full ary'+    go s t1 (Full ary2) =+        let h1   = leafHashCode t1+            i    = index h1 s+            ary' = update16With' ary2 i $ \st2 -> go (s+bitsPerSubkey) t1 st2+        in Full ary'++    leafHashCode (Leaf h _) = h+    leafHashCode (Collision h _) = h+    leafHashCode _ = error "leafHashCode"++    goDifferentHash s h1 h2 t1 t2+        | m1 == m2  = BitmapIndexed m1 (A.singleton $! go (s+bitsPerSubkey) t1 t2)+        | m1 <  m2  = BitmapIndexed (m1 .|. m2) (A.pair t1 t2)+        | otherwise = BitmapIndexed (m1 .|. m2) (A.pair t2 t1)+      where+        m1 = mask h1 s+        m2 = mask h2 s+{-# INLINE unionWithKey #-}++------------------------------------------------------------------------+-- * Transformations++-- | /O(n)/ Transform this map by applying a function to every value.+mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2+mapWithKey f = go+  where+    go Empty                 = Empty+    go (Leaf h (L k v))      = leaf h k (f k v)+    go (BitmapIndexed b ary) = BitmapIndexed b $ A.map' go ary+    go (Full ary)            = Full $ A.map' go ary+    go (Collision h ary)     =+        Collision h $ A.map' (\ (L k v) -> let !v' = f k v in L k v') ary+{-# INLINE mapWithKey #-}++-- | /O(n)/ Transform this map by applying a function to every value.+map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2+map f = mapWithKey (const f)+{-# INLINE map #-}+++------------------------------------------------------------------------+-- * Filter++-- | /O(n)/ Transform this map by applying a function to every value+--   and retaining only some of them.+mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2+mapMaybeWithKey f = filterMapAux onLeaf onColl+  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (leaf h k v')+        onLeaf _ = Nothing++        onColl (L k v) | Just v' <- f k v = Just (L k v')+                       | otherwise = Nothing+{-# INLINE mapMaybeWithKey #-}++-- | /O(n)/ Transform this map by applying a function to every value+--   and retaining only some of them.+mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2+mapMaybe f = mapMaybeWithKey (const f)+{-# INLINE mapMaybe #-}++-- | /O(n)/ Perform an 'Applicative' action for each key-value pair+-- in a 'HashMap' and produce a 'HashMap' of all the results. Each 'HashMap'+-- will be strict in all its values.+--+-- @+-- traverseWithKey f = fmap ('map' id) . "Data.HashMap.Lazy".'Data.HashMap.Lazy.traverseWithKey' f+-- @+--+-- Note: the order in which the actions occur is unspecified. In particular,+-- when the map contains hash collisions, the order in which the actions+-- associated with the keys involved will depend in an unspecified way on+-- their insertion order.+traverseWithKey+  :: Applicative f+  => (k -> v1 -> f v2)+  -> HashMap k v1 -> f (HashMap k v2)+traverseWithKey f = go+  where+    go Empty                 = pure Empty+    go (Leaf h (L k v))      = leaf h k <$> f k v+    go (BitmapIndexed b ary) = BitmapIndexed b <$> A.traverse' go ary+    go (Full ary)            = Full <$> A.traverse' go ary+    go (Collision h ary)     =+        Collision h <$> A.traverse' (\ (L k v) -> (L k $!) <$> f k v) ary+{-# INLINE traverseWithKey #-}++------------------------------------------------------------------------+-- * Difference and intersection++-- | /O(n*log m)/ Difference with a combining function. When two equal keys are+-- encountered, the combining function is applied to the values of these keys.+-- If it returns 'Nothing', the element is discarded (proper set difference). If+-- it returns (@'Just' y@), the element is updated with a new value @y@.+differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v+differenceWith f a b = foldlWithKey' go empty a+  where+    go m k v = case HM.lookup k b of+                 Nothing -> insert k v m+                 Just w  -> maybe m (\y -> insert k y m) (f v w)+{-# INLINABLE differenceWith #-}++-- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps+-- the provided function is used to combine the values from the two+-- maps.+intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1+                 -> HashMap k v2 -> HashMap k v3+intersectionWith f a b = foldlWithKey' go empty a+  where+    go m k v = case HM.lookup k b of+                 Just w -> insert k (f v w) m+                 _      -> m+{-# INLINABLE intersectionWith #-}++-- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps+-- the provided function is used to combine the values from the two+-- maps.+intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)+                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3+intersectionWithKey f a b = foldlWithKey' go empty a+  where+    go m k v = case HM.lookup k b of+                 Just w -> insert k (f k v w) m+                 _      -> m+{-# INLINABLE intersectionWithKey #-}++------------------------------------------------------------------------+-- ** Lists++-- | /O(n*log n)/ Construct a map with the supplied mappings.  If the+-- list contains duplicate mappings, the later mappings take+-- precedence.+fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v+fromList = L.foldl' (\ m (k, !v) -> HM.unsafeInsert k v m) empty+{-# INLINABLE fromList #-}++-- | /O(n*log n)/ Construct a map from a list of elements.  Uses+-- the provided function @f@ to merge duplicate entries with+-- @(f newVal oldVal)@.+--+-- === Examples+--+-- Given a list @xs@, create a map with the number of occurrences of each+-- element in @xs@:+--+-- > let xs = ['a', 'b', 'a']+-- > in fromListWith (+) [ (x, 1) | x <- xs ]+-- >+-- > = fromList [('a', 2), ('b', 1)]+--+-- Given a list of key-value pairs @xs :: [(k, v)]@, group all values by their+-- keys and return a @HashMap k [v]@.+--+-- > let xs = ('a', 1), ('b', 2), ('a', 3)]+-- > in fromListWith (++) [ (k, [v]) | (k, v) <- xs ]+-- >+-- > = fromList [('a', [3, 1]), ('b', [2])]+--+-- Note that the lists in the resulting map contain elements in reverse order+-- from their occurences in the original list.+--+-- More generally, duplicate entries are accumulated as follows;+-- this matters when @f@ is not commutative or not associative.+--+-- > fromListWith f [(k, a), (k, b), (k, c), (k, d)]+-- > = fromList [(k, f d (f c (f b a)))]+fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v+fromListWith f = L.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty+{-# INLINE fromListWith #-}++-- | /O(n*log n)/ Construct a map from a list of elements.  Uses+-- the provided function to merge duplicate entries.+--+-- === Examples+--+-- Given a list of key-value pairs where the keys are of different flavours, e.g:+--+-- > data Key = Div | Sub+--+-- and the values need to be combined differently when there are duplicates,+-- depending on the key:+--+-- > combine Div = div+-- > combine Sub = (-)+--+-- then @fromListWithKey@ can be used as follows:+--+-- > fromListWithKey combine [(Div, 2), (Div, 6), (Sub, 2), (Sub, 3)]+-- > = fromList [(Div, 3), (Sub, 1)]+--+-- More generally, duplicate entries are accumulated as follows;+--+-- > fromListWith f [(k, a), (k, b), (k, c), (k, d)]+-- > = fromList [(k, f k d (f k c (f k b a)))]+--+-- @since 0.2.11+fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v+fromListWithKey f = L.foldl' (\ m (k, v) -> unsafeInsertWithKey f k v m) empty+{-# INLINE fromListWithKey #-}++------------------------------------------------------------------------+-- Array operations++updateWith :: Eq k => (v -> v) -> k -> A.Array (Leaf k v) -> A.Array (Leaf k v)+updateWith f k0 ary0 = go k0 ary0 0 (A.length ary0)+  where+    go !k !ary !i !n+        | i >= n    = ary+        | otherwise = case A.index ary i of+            (L kx y) | k == kx   -> let !v' = f y in A.update ary i (L k v')+                     | otherwise -> go k ary (i+1) n+{-# INLINABLE updateWith #-}++-- | Append the given key and value to the array. If the key is+-- already present, instead update the value of the key by applying+-- the given function to the new and old value (in that order). The+-- value is always evaluated to WHNF before being inserted into the+-- array.+updateOrSnocWith :: Eq k => (v -> v -> v) -> k -> v -> A.Array (Leaf k v)+                 -> A.Array (Leaf k v)+updateOrSnocWith f = updateOrSnocWithKey (const f)+{-# INLINABLE updateOrSnocWith #-}++-- | Append the given key and value to the array. If the key is+-- already present, instead update the value of the key by applying+-- the given function to the new and old value (in that order). The+-- value is always evaluated to WHNF before being inserted into the+-- array.+updateOrSnocWithKey :: Eq k => (k -> v -> v -> v) -> k -> v -> A.Array (Leaf k v)+                 -> A.Array (Leaf k v)+updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)+  where+    go !k v !ary !i !n+        | i >= n = A.run $ do+            -- Not found, append to the end.+            mary <- A.new_ (n + 1)+            A.copy ary 0 mary 0 n+            let !l = v `seq` (L k v)+            A.write mary n l+            return mary+        | otherwise = case A.index ary i of+            (L kx y) | k == kx   -> let !v' = f k v y in A.update ary i (L k v')+                     | otherwise -> go k v ary (i+1) n+{-# INLINABLE updateOrSnocWithKey #-}++------------------------------------------------------------------------+-- Smart constructors+--+-- These constructors make sure the value is in WHNF before it's+-- inserted into the constructor.++leaf :: Hash -> k -> v -> HashMap k v+leaf h k = \ !v -> Leaf h (L k v)+{-# INLINE leaf #-}
+ Data/HashMap/Internal/Unsafe.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE CPP #-}++#if !MIN_VERSION_base(4,9,0)+{-# LANGUAGE MagicHash, Rank2Types, UnboxedTuples #-}+#endif++{-# OPTIONS_HADDOCK not-home #-}++-- | = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.+--+-- = Description+--+-- This module exports a workaround for this bug:+--+--    http://hackage.haskell.org/trac/ghc/ticket/5916+--+-- Please read the comments in ghc/libraries/base/GHC/ST.lhs to+-- understand what's going on here.+--+-- Code that uses this module should be compiled with -fno-full-laziness+module Data.HashMap.Internal.Unsafe+    ( runST+    ) where++#if MIN_VERSION_base(4,9,0)+-- The GHC issue was fixed in GHC 8.0/base 4.9+import Control.Monad.ST++#else++import GHC.Base (realWorld#)+import qualified GHC.ST as ST++-- | Return the value computed by a state transformer computation.+-- The @forall@ ensures that the internal state used by the 'ST'+-- computation is inaccessible to the rest of the program.+runST :: (forall s. ST.ST s a) -> a+runST st = runSTRep (case st of { ST.ST st_rep -> st_rep })+{-# INLINE runST #-}++runSTRep :: (forall s. ST.STRep s a) -> a+runSTRep st_rep = case st_rep realWorld# of+                        (# _, r #) -> r+{-# INLINE [0] runSTRep #-}+#endif
Data/HashMap/Lazy.hs view
@@ -49,6 +49,8 @@     , update     , alter     , alterF+    , isSubmapOf+    , isSubmapOfBy        -- * Combine       -- ** Union@@ -100,8 +102,8 @@     , HS.keysSet     ) where -import Data.HashMap.Base as HM-import qualified Data.HashSet.Base as HS+import Data.HashMap.Internal as HM+import qualified Data.HashSet.Internal as HS import Prelude ()  -- $strictness
− Data/HashMap/List.hs
@@ -1,66 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}--- | Extra list functions------ In separate module to aid testing.-module Data.HashMap.List-    ( isPermutationBy-    , deleteBy-    , unorderedCompare-    ) where--import Data.Maybe (fromMaybe)-import Data.List (sortBy)-import Data.Monoid-import Prelude---- Note: previous implemenation isPermutation = null (as // bs)--- was O(n^2) too.------ This assumes lists are of equal length-isPermutationBy :: (a -> b -> Bool) -> [a] -> [b] -> Bool-isPermutationBy f = go-  where-    f' = flip f--    go [] [] = True-    go (x : xs) (y : ys)-        | f x y         = go xs ys-        | otherwise     = fromMaybe False $ do-            xs' <- deleteBy f' y xs-            ys' <- deleteBy f x ys-            return (go xs' ys')-    go [] (_ : _) = False-    go (_ : _) [] = False---- The idea:------ Homogeonous version------ uc :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering--- uc c as bs = compare (sortBy c as) (sortBy c bs)------ But as we have only (a -> b -> Ordering), we cannot directly compare--- elements from the same list.------ So when comparing elements from the list, we count how many elements are--- "less and greater" in the other list, and use the count as a metric.----unorderedCompare :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering-unorderedCompare c as bs = go (sortBy cmpA as) (sortBy cmpB bs)-  where-    go [] [] = EQ-    go [] (_ : _) = LT-    go (_ : _) [] = GT-    go (x : xs) (y : ys) = c x y `mappend` go xs ys--    cmpA a a' = compare (inB a) (inB a')-    cmpB b b' = compare (inA b) (inA b')--    inB a = (length $ filter (\b -> c a b == GT) bs, negate $ length $ filter (\b -> c a b == LT) bs)-    inA b = (length $ filter (\a -> c a b == LT) as, negate $ length $ filter (\a -> c a b == GT) as)---- Returns Nothing is nothing deleted-deleteBy              :: (a -> b -> Bool) -> a -> [b] -> Maybe [b]-deleteBy _  _ []      = Nothing-deleteBy eq x (y:ys)  = if x `eq` y then Just ys else fmap (y :) (deleteBy eq x ys)
Data/HashMap/Strict.hs view
@@ -48,6 +48,8 @@     , update     , alter     , alterF+    , isSubmapOf+    , isSubmapOfBy        -- * Combine       -- ** Union@@ -99,8 +101,8 @@     , HS.keysSet     ) where -import Data.HashMap.Strict.Base as HM-import qualified Data.HashSet.Base as HS+import Data.HashMap.Internal.Strict as HM+import qualified Data.HashSet.Internal as HS import Prelude ()  -- $strictness
− Data/HashMap/Strict/Base.hs
@@ -1,732 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, PatternGuards, MagicHash, UnboxedTuples #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE Trustworthy #-}----------------------------------------------------------------------------- |--- Module      :  Data.HashMap.Strict--- Copyright   :  2010-2012 Johan Tibell--- License     :  BSD-style--- Maintainer  :  johan.tibell@gmail.com--- Stability   :  provisional--- Portability :  portable------ A map from /hashable/ keys to values.  A map cannot contain--- duplicate keys; each key can map to at most one value.  A 'HashMap'--- makes no guarantees as to the order of its elements.------ The implementation is based on /hash array mapped tries/.  A--- 'HashMap' is often faster than other tree-based set types,--- especially when key comparison is expensive, as in the case of--- strings.------ Many operations have a average-case complexity of /O(log n)/.  The--- implementation uses a large base (i.e. 16) so in practice these--- operations are constant time.-module Data.HashMap.Strict.Base-    (-      -- * Strictness properties-      -- $strictness--      HashMap--      -- * Construction-    , empty-    , singleton--      -- * Basic interface-    , HM.null-    , size-    , HM.member-    , HM.lookup-    , (HM.!?)-    , HM.findWithDefault-    , lookupDefault-    , (!)-    , insert-    , insertWith-    , delete-    , adjust-    , update-    , alter-    , alterF--      -- * Combine-      -- ** Union-    , union-    , unionWith-    , unionWithKey-    , unions--      -- * Transformations-    , map-    , mapWithKey-    , traverseWithKey--      -- * Difference and intersection-    , difference-    , differenceWith-    , intersection-    , intersectionWith-    , intersectionWithKey--      -- * Folds-    , foldMapWithKey-    , foldr'-    , foldl'-    , foldrWithKey'-    , foldlWithKey'-    , HM.foldr-    , HM.foldl-    , foldrWithKey-    , foldlWithKey--      -- * Filter-    , HM.filter-    , filterWithKey-    , mapMaybe-    , mapMaybeWithKey--      -- * Conversions-    , keys-    , elems--      -- ** Lists-    , toList-    , fromList-    , fromListWith-    , fromListWithKey-    ) where--import Data.Bits ((.&.), (.|.))--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative (Applicative (..), (<$>))-#endif-import qualified Data.List as L-import Data.Hashable (Hashable)-import Prelude hiding (map, lookup)--import qualified Data.HashMap.Array as A-import qualified Data.HashMap.Base as HM-import Data.HashMap.Base hiding (-    alter, alterF, adjust, fromList, fromListWith, fromListWithKey,-    insert, insertWith,-    differenceWith, intersectionWith, intersectionWithKey, map, mapWithKey,-    mapMaybe, mapMaybeWithKey, singleton, update, unionWith, unionWithKey,-    traverseWithKey)-import Data.HashMap.Unsafe (runST)-#if MIN_VERSION_base(4,8,0)-import Data.Functor.Identity-#endif-import Control.Applicative (Const (..))-import Data.Coerce---- $strictness------ This module satisfies the following strictness properties:------ 1. Key arguments are evaluated to WHNF;------ 2. Keys and values are evaluated to WHNF before they are stored in---    the map.----------------------------------------------------------------------------- * Construction---- | /O(1)/ Construct a map with a single element.-singleton :: (Hashable k) => k -> v -> HashMap k v-singleton k !v = HM.singleton k v----------------------------------------------------------------------------- * Basic interface---- | /O(log n)/ Associate the specified value with the specified--- key in this map.  If this map previously contained a mapping for--- the key, the old value is replaced.-insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v-insert k !v = HM.insert k v-{-# INLINABLE insert #-}---- | /O(log n)/ Associate the value with the key in this map.  If--- this map previously contained a mapping for the key, the old value--- is replaced by the result of applying the given function to the new--- and old value.  Example:------ > insertWith f k v map--- >   where f new old = new + old-insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v-           -> HashMap k v-insertWith f k0 v0 m0 = go h0 k0 v0 0 m0-  where-    h0 = hash k0-    go !h !k x !_ Empty = leaf h k x-    go h k x s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then leaf h k (f x y)-                    else x `seq` (collision h l (L k x))-        | otherwise = x `seq` runST (two s h k x hy t)-    go h k x s (BitmapIndexed b ary)-        | b .&. m == 0 =-            let ary' = A.insert ary i $! leaf h k x-            in bitmapIndexedOrFull (b .|. m) ary'-        | otherwise =-            let st   = A.index ary i-                st'  = go h k x (s+bitsPerSubkey) st-                ary' = A.update ary i $! st'-            in BitmapIndexed b ary'-      where m = mask h s-            i = sparseIndex b m-    go h k x s (Full ary) =-        let st   = A.index ary i-            st'  = go h k x (s+bitsPerSubkey) st-            ary' = update16 ary i $! st'-        in Full ary'-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = Collision h (updateOrSnocWith f k x v)-        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE insertWith #-}---- | In-place update version of insertWith-unsafeInsertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v-                 -> HashMap k v-unsafeInsertWith f k0 v0 m0 = unsafeInsertWithKey (const f) k0 v0 m0-{-# INLINABLE unsafeInsertWith #-}--unsafeInsertWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> k -> v -> HashMap k v-                    -> HashMap k v-unsafeInsertWithKey f k0 v0 m0 = runST (go h0 k0 v0 0 m0)-  where-    h0 = hash k0-    go !h !k x !_ Empty = return $! leaf h k x-    go h k x s t@(Leaf hy l@(L ky y))-        | hy == h = if ky == k-                    then return $! leaf h k (f k x y)-                    else do-                        let l' = x `seq` (L k x)-                        return $! collision h l l'-        | otherwise = x `seq` two s h k x hy t-    go h k x s t@(BitmapIndexed b ary)-        | b .&. m == 0 = do-            ary' <- A.insertM ary i $! leaf h k x-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.indexM ary i-            st' <- go h k x (s+bitsPerSubkey) st-            A.unsafeUpdateM ary i st'-            return t-      where m = mask h s-            i = sparseIndex b m-    go h k x s t@(Full ary) = do-        st <- A.indexM ary i-        st' <- go h k x (s+bitsPerSubkey) st-        A.unsafeUpdateM ary i st'-        return t-      where i = index h s-    go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWithKey f k x v)-        | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)-{-# INLINABLE unsafeInsertWithKey #-}---- | /O(log n)/ Adjust the value tied to a given key in this map only--- if it is present. Otherwise, leave the map alone.-adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v-adjust f k0 m0 = go h0 k0 0 m0-  where-    h0 = hash k0-    go !_ !_ !_ Empty = Empty-    go h k _ t@(Leaf hy (L ky y))-        | hy == h && ky == k = leaf h k (f y)-        | otherwise          = t-    go h k s t@(BitmapIndexed b ary)-        | b .&. m == 0 = t-        | otherwise = let st   = A.index ary i-                          st'  = go h k (s+bitsPerSubkey) st-                          ary' = A.update ary i $! st'-                      in BitmapIndexed b ary'-      where m = mask h s-            i = sparseIndex b m-    go h k s (Full ary) =-        let i    = index h s-            st   = A.index ary i-            st'  = go h k (s+bitsPerSubkey) st-            ary' = update16 ary i $! st'-        in Full ary'-    go h k _ t@(Collision hy v)-        | h == hy   = Collision h (updateWith f k v)-        | otherwise = t-{-# INLINABLE adjust #-}---- | /O(log n)/  The expression @('update' f k map)@ updates the value @x@ at @k@--- (if it is in the map). If @(f x)@ is 'Nothing', the element is deleted.--- If it is @('Just' y)@, the key @k@ is bound to the new value @y@.-update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a-update f = alter (>>= f)-{-# INLINABLE update #-}---- | /O(log n)/  The expression (@'alter' f k map@) alters the value @x@ at @k@, or--- absence thereof. @alter@ can be used to insert, delete, or update a value in a--- map. In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@.-alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v-alter f k m =-  case f (HM.lookup k m) of-    Nothing -> delete k m-    Just v  -> insert k v m-{-# INLINABLE alter #-}---- | /O(log n)/  The expression (@'alterF' f k map@) alters the value @x@ at--- @k@, or absence thereof. @alterF@ can be used to insert, delete, or update--- a value in a map.------ Note: 'alterF' is a flipped version of the 'at' combinator from--- <https://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-At.html#v:at Control.Lens.At>.------ @since 0.2.10-alterF :: (Functor f, Eq k, Hashable k)-       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)--- Special care is taken to only calculate the hash once. When we rewrite--- with RULES, we also ensure that we only compare the key for equality--- once. We force the value of the map for consistency with the rewritten--- version; otherwise someone could tell the difference using a lazy--- @f@ and a functor that is similar to Const but not actually Const.-alterF f = \ !k !m ->-  let !h = hash k-      mv = lookup' h k m-  in (<$> f mv) $ \fres ->-    case fres of-      Nothing -> delete' h k m-      Just !v' -> insert' h k v' m---- We rewrite this function unconditionally in RULES, but we expose--- an unfolding just in case it's used in a context where the rules--- don't fire.-{-# INLINABLE [0] alterF #-}--#if MIN_VERSION_base(4,8,0)--- See notes in Data.HashMap.Base-test_bottom :: a-test_bottom = error "Data.HashMap.alterF internal error: hit test_bottom"--bogus# :: (# #) -> (# a #)-bogus# _ = error "Data.HashMap.alterF internal error: hit bogus#"--impossibleAdjust :: a-impossibleAdjust = error "Data.HashMap.alterF internal error: impossible adjust"--{-# RULES---- See detailed notes on alterF rules in Data.HashMap.Base.--"alterFWeird" forall f. alterF f =-    alterFWeird (f Nothing) (f (Just test_bottom)) f--"alterFconstant" forall (f :: Maybe a -> Identity (Maybe a)) x.-  alterFWeird x x f = \ !k !m ->-    Identity (case runIdentity x of {Nothing -> delete k m; Just a -> insert k a m})--"alterFinsertWith" [1] forall (f :: Maybe a -> Identity (Maybe a)) x y.-  alterFWeird (coerce (Just x)) (coerce (Just y)) f =-    coerce (insertModifying x (\mold -> case runIdentity (f (Just mold)) of-                                            Nothing -> bogus# (# #)-                                            Just !new -> (# new #)))---- This rule is written a bit differently than the one for lazy--- maps because the adjust here is strict. We could write it the--- same general way anyway, but this seems simpler.-"alterFadjust" forall (f :: Maybe a -> Identity (Maybe a)) x.-  alterFWeird (coerce Nothing) (coerce (Just x)) f =-    coerce (adjust (\a -> case runIdentity (f (Just a)) of-                               Just a' -> a'-                               Nothing -> impossibleAdjust))--"alterFlookup" forall _ign1 _ign2 (f :: Maybe a -> Const r (Maybe a)) .-  alterFWeird _ign1 _ign2 f = \ !k !m -> Const (getConst (f (lookup k m)))- #-}---- This is a very unsafe version of alterF used for RULES. When calling--- alterFWeird x y f, the following *must* hold:------ x = f Nothing--- y = f (Just _|_)------ Failure to abide by these laws will make demons come out of your nose.-alterFWeird-       :: (Functor f, Eq k, Hashable k)-       => f (Maybe v)-       -> f (Maybe v)-       -> (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)-alterFWeird _ _ f = alterFEager f-{-# INLINE [0] alterFWeird #-}---- | This is the default version of alterF that we use in most non-trivial--- cases. It's called "eager" because it looks up the given key in the map--- eagerly, whether or not the given function requires that information.-alterFEager :: (Functor f, Eq k, Hashable k)-       => (Maybe v -> f (Maybe v)) -> k -> HashMap k v -> f (HashMap k v)-alterFEager f !k !m = (<$> f mv) $ \fres ->-  case fres of--    -------------------------------    -- Delete the key from the map.-    Nothing -> case lookupRes of--      -- Key did not exist in the map to begin with, no-op-      Absent -> m--      -- Key did exist, no collision-      Present _ collPos -> deleteKeyExists collPos h k m--    -------------------------------    -- Update value-    Just v' -> case lookupRes of--      -- Key did not exist before, insert v' under a new key-      Absent -> insertNewKey h k v' m--      -- Key existed before, no hash collision-      Present v collPos -> v' `seq`-        if v `ptrEq` v'-        -- If the value is identical, no-op-        then m-        -- If the value changed, update the value.-        else insertKeyExists collPos h k v' m--  where !h = hash k-        !lookupRes = lookupRecordCollision h k m-        !mv = case lookupRes of-          Absent -> Nothing-          Present v _ -> Just v-{-# INLINABLE alterFEager #-}-#endif----------------------------------------------------------------------------- * Combine---- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,--- the provided function (first argument) will be used to compute the result.-unionWith :: (Eq k, Hashable k) => (v -> v -> v) -> HashMap k v -> HashMap k v-          -> HashMap k v-unionWith f = unionWithKey (const f)-{-# INLINE unionWith #-}---- | /O(n+m)/ The union of two maps.  If a key occurs in both maps,--- the provided function (first argument) will be used to compute the result.-unionWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> HashMap k v -> HashMap k v-          -> HashMap k v-unionWithKey f = go 0-  where-    -- empty vs. anything-    go !_ t1 Empty = t1-    go _ Empty t2 = t2-    -- leaf vs. leaf-    go s t1@(Leaf h1 l1@(L k1 v1)) t2@(Leaf h2 l2@(L k2 v2))-        | h1 == h2  = if k1 == k2-                      then leaf h1 k1 (f k1 v1 v2)-                      else collision h1 l1 l2-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Leaf h1 (L k1 v1)) t2@(Collision h2 ls2)-        | h1 == h2  = Collision h1 (updateOrSnocWithKey f k1 v1 ls2)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Collision h1 ls1) t2@(Leaf h2 (L k2 v2))-        | h1 == h2  = Collision h1 (updateOrSnocWithKey (flip . f) k2 v2 ls1)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    go s t1@(Collision h1 ls1) t2@(Collision h2 ls2)-        | h1 == h2  = Collision h1 (updateOrConcatWithKey f ls1 ls2)-        | otherwise = goDifferentHash s h1 h2 t1 t2-    -- branch vs. branch-    go s (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =-        let b'   = b1 .|. b2-            ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 b2 ary1 ary2-        in bitmapIndexedOrFull b' ary'-    go s (BitmapIndexed b1 ary1) (Full ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) b1 fullNodeMask ary1 ary2-        in Full ary'-    go s (Full ary1) (BitmapIndexed b2 ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask b2 ary1 ary2-        in Full ary'-    go s (Full ary1) (Full ary2) =-        let ary' = unionArrayBy (go (s+bitsPerSubkey)) fullNodeMask fullNodeMask-                   ary1 ary2-        in Full ary'-    -- leaf vs. branch-    go s (BitmapIndexed b1 ary1) t2-        | b1 .&. m2 == 0 = let ary' = A.insert ary1 i t2-                               b'   = b1 .|. m2-                           in bitmapIndexedOrFull b' ary'-        | otherwise      = let ary' = A.updateWith' ary1 i $ \st1 ->-                                   go (s+bitsPerSubkey) st1 t2-                           in BitmapIndexed b1 ary'-        where-          h2 = leafHashCode t2-          m2 = mask h2 s-          i = sparseIndex b1 m2-    go s t1 (BitmapIndexed b2 ary2)-        | b2 .&. m1 == 0 = let ary' = A.insert ary2 i $! t1-                               b'   = b2 .|. m1-                           in bitmapIndexedOrFull b' ary'-        | otherwise      = let ary' = A.updateWith' ary2 i $ \st2 ->-                                   go (s+bitsPerSubkey) t1 st2-                           in BitmapIndexed b2 ary'-      where-        h1 = leafHashCode t1-        m1 = mask h1 s-        i = sparseIndex b2 m1-    go s (Full ary1) t2 =-        let h2   = leafHashCode t2-            i    = index h2 s-            ary' = update16With' ary1 i $ \st1 -> go (s+bitsPerSubkey) st1 t2-        in Full ary'-    go s t1 (Full ary2) =-        let h1   = leafHashCode t1-            i    = index h1 s-            ary' = update16With' ary2 i $ \st2 -> go (s+bitsPerSubkey) t1 st2-        in Full ary'--    leafHashCode (Leaf h _) = h-    leafHashCode (Collision h _) = h-    leafHashCode _ = error "leafHashCode"--    goDifferentHash s h1 h2 t1 t2-        | m1 == m2  = BitmapIndexed m1 (A.singleton $! go (s+bitsPerSubkey) t1 t2)-        | m1 <  m2  = BitmapIndexed (m1 .|. m2) (A.pair t1 t2)-        | otherwise = BitmapIndexed (m1 .|. m2) (A.pair t2 t1)-      where-        m1 = mask h1 s-        m2 = mask h2 s-{-# INLINE unionWithKey #-}----------------------------------------------------------------------------- * Transformations---- | /O(n)/ Transform this map by applying a function to every value.-mapWithKey :: (k -> v1 -> v2) -> HashMap k v1 -> HashMap k v2-mapWithKey f = go-  where-    go Empty                 = Empty-    go (Leaf h (L k v))      = leaf h k (f k v)-    go (BitmapIndexed b ary) = BitmapIndexed b $ A.map' go ary-    go (Full ary)            = Full $ A.map' go ary-    go (Collision h ary)     =-        Collision h $ A.map' (\ (L k v) -> let !v' = f k v in L k v') ary-{-# INLINE mapWithKey #-}---- | /O(n)/ Transform this map by applying a function to every value.-map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2-map f = mapWithKey (const f)-{-# INLINE map #-}------------------------------------------------------------------------------ * Filter---- | /O(n)/ Transform this map by applying a function to every value---   and retaining only some of them.-mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2-mapMaybeWithKey f = filterMapAux onLeaf onColl-  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (leaf h k v')-        onLeaf _ = Nothing--        onColl (L k v) | Just v' <- f k v = Just (L k v')-                       | otherwise = Nothing-{-# INLINE mapMaybeWithKey #-}---- | /O(n)/ Transform this map by applying a function to every value---   and retaining only some of them.-mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2-mapMaybe f = mapMaybeWithKey (const f)-{-# INLINE mapMaybe #-}---- | /O(n)/ Perform an 'Applicative' action for each key-value pair--- in a 'HashMap' and produce a 'HashMap' of all the results. Each 'HashMap'--- will be strict in all its values.------ @--- traverseWithKey f = fmap ('map' id) . "Data.HashMap.Lazy".'Data.HashMap.Lazy.traverseWithKey' f--- @------ Note: the order in which the actions occur is unspecified. In particular,--- when the map contains hash collisions, the order in which the actions--- associated with the keys involved will depend in an unspecified way on--- their insertion order.-traverseWithKey-  :: Applicative f-  => (k -> v1 -> f v2)-  -> HashMap k v1 -> f (HashMap k v2)-traverseWithKey f = go-  where-    go Empty                 = pure Empty-    go (Leaf h (L k v))      = leaf h k <$> f k v-    go (BitmapIndexed b ary) = BitmapIndexed b <$> A.traverse' go ary-    go (Full ary)            = Full <$> A.traverse' go ary-    go (Collision h ary)     =-        Collision h <$> A.traverse' (\ (L k v) -> (L k $!) <$> f k v) ary-{-# INLINE traverseWithKey #-}----------------------------------------------------------------------------- * Difference and intersection---- | /O(n*log m)/ Difference with a combining function. When two equal keys are--- encountered, the combining function is applied to the values of these keys.--- If it returns 'Nothing', the element is discarded (proper set difference). If--- it returns (@'Just' y@), the element is updated with a new value @y@.-differenceWith :: (Eq k, Hashable k) => (v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v-differenceWith f a b = foldlWithKey' go empty a-  where-    go m k v = case HM.lookup k b of-                 Nothing -> insert k v m-                 Just w  -> maybe m (\y -> insert k y m) (f v w)-{-# INLINABLE differenceWith #-}---- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps--- the provided function is used to combine the values from the two--- maps.-intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1-                 -> HashMap k v2 -> HashMap k v3-intersectionWith f a b = foldlWithKey' go empty a-  where-    go m k v = case HM.lookup k b of-                 Just w -> insert k (f v w) m-                 _      -> m-{-# INLINABLE intersectionWith #-}---- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps--- the provided function is used to combine the values from the two--- maps.-intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)-                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3-intersectionWithKey f a b = foldlWithKey' go empty a-  where-    go m k v = case HM.lookup k b of-                 Just w -> insert k (f k v w) m-                 _      -> m-{-# INLINABLE intersectionWithKey #-}----------------------------------------------------------------------------- ** Lists---- | /O(n*log n)/ Construct a map with the supplied mappings.  If the--- list contains duplicate mappings, the later mappings take--- precedence.-fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v-fromList = L.foldl' (\ m (k, !v) -> HM.unsafeInsert k v m) empty-{-# INLINABLE fromList #-}---- | /O(n*log n)/ Construct a map from a list of elements.  Uses--- the provided function @f@ to merge duplicate entries with--- @(f newVal oldVal)@.------ === Examples------ Given a list @xs@, create a map with the number of occurrences of each--- element in @xs@:------ > let xs = ['a', 'b', 'a']--- > in fromListWith (+) [ (x, 1) | x <- xs ]--- >--- > = fromList [('a', 2), ('b', 1)]------ Given a list of key-value pairs @xs :: [(k, v)]@, group all values by their--- keys and return a @HashMap k [v]@.------ > let xs = ('a', 1), ('b', 2), ('a', 3)]--- > in fromListWith (++) [ (k, [v]) | (k, v) <- xs ]--- >--- > = fromList [('a', [3, 1]), ('b', [2])]------ Note that the lists in the resulting map contain elements in reverse order--- from their occurences in the original list.------ More generally, duplicate entries are accumulated as follows;--- this matters when @f@ is not commutative or not associative.------ > fromListWith f [(k, a), (k, b), (k, c), (k, d)]--- > = fromList [(k, f d (f c (f b a)))]-fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v-fromListWith f = L.foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty-{-# INLINE fromListWith #-}---- | /O(n*log n)/ Construct a map from a list of elements.  Uses--- the provided function to merge duplicate entries.------ === Examples------ Given a list of key-value pairs where the keys are of different flavours, e.g:------ > data Key = Div | Sub------ and the values need to be combined differently when there are duplicates,--- depending on the key:------ > combine Div = div--- > combine Sub = (-)------ then @fromListWithKey@ can be used as follows:------ > fromListWithKey combine [(Div, 2), (Div, 6), (Sub, 2), (Sub, 3)]--- > = fromList [(Div, 3), (Sub, 1)]------ More generally, duplicate entries are accumulated as follows;------ > fromListWith f [(k, a), (k, b), (k, c), (k, d)]--- > = fromList [(k, f k d (f k c (f k b a)))]------ @since 0.2.11-fromListWithKey :: (Eq k, Hashable k) => (k -> v -> v -> v) -> [(k, v)] -> HashMap k v-fromListWithKey f = L.foldl' (\ m (k, v) -> unsafeInsertWithKey f k v m) empty-{-# INLINE fromListWithKey #-}----------------------------------------------------------------------------- Array operations--updateWith :: Eq k => (v -> v) -> k -> A.Array (Leaf k v) -> A.Array (Leaf k v)-updateWith f k0 ary0 = go k0 ary0 0 (A.length ary0)-  where-    go !k !ary !i !n-        | i >= n    = ary-        | otherwise = case A.index ary i of-            (L kx y) | k == kx   -> let !v' = f y in A.update ary i (L k v')-                     | otherwise -> go k ary (i+1) n-{-# INLINABLE updateWith #-}---- | Append the given key and value to the array. If the key is--- already present, instead update the value of the key by applying--- the given function to the new and old value (in that order). The--- value is always evaluated to WHNF before being inserted into the--- array.-updateOrSnocWith :: Eq k => (v -> v -> v) -> k -> v -> A.Array (Leaf k v)-                 -> A.Array (Leaf k v)-updateOrSnocWith f = updateOrSnocWithKey (const f)-{-# INLINABLE updateOrSnocWith #-}---- | Append the given key and value to the array. If the key is--- already present, instead update the value of the key by applying--- the given function to the new and old value (in that order). The--- value is always evaluated to WHNF before being inserted into the--- array.-updateOrSnocWithKey :: Eq k => (k -> v -> v -> v) -> k -> v -> A.Array (Leaf k v)-                 -> A.Array (Leaf k v)-updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)-  where-    go !k v !ary !i !n-        | i >= n = A.run $ do-            -- Not found, append to the end.-            mary <- A.new_ (n + 1)-            A.copy ary 0 mary 0 n-            let !l = v `seq` (L k v)-            A.write mary n l-            return mary-        | otherwise = case A.index ary i of-            (L kx y) | k == kx   -> let !v' = f k v y in A.update ary i (L k v')-                     | otherwise -> go k v ary (i+1) n-{-# INLINABLE updateOrSnocWithKey #-}----------------------------------------------------------------------------- Smart constructors------ These constructors make sure the value is in WHNF before it's--- inserted into the constructor.--leaf :: Hash -> k -> v -> HashMap k v-leaf h k = \ !v -> Leaf h (L k v)-{-# INLINE leaf #-}
− Data/HashMap/Unsafe.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE CPP #-}--#if !MIN_VERSION_base(4,9,0)-{-# LANGUAGE MagicHash, Rank2Types, UnboxedTuples #-}-#endif---- | This module exports a workaround for this bug:------    http://hackage.haskell.org/trac/ghc/ticket/5916------ Please read the comments in ghc/libraries/base/GHC/ST.lhs to--- understand what's going on here.------ Code that uses this module should be compiled with -fno-full-laziness-module Data.HashMap.Unsafe-    ( runST-    ) where--#if MIN_VERSION_base(4,9,0)--- The GHC issue was fixed in GHC 8.0/base 4.9-import Control.Monad.ST--#else--import GHC.Base (realWorld#)-import qualified GHC.ST as ST---- | Return the value computed by a state transformer computation.--- The @forall@ ensures that the internal state used by the 'ST'--- computation is inaccessible to the rest of the program.-runST :: (forall s. ST.ST s a) -> a-runST st = runSTRep (case st of { ST.ST st_rep -> st_rep })-{-# INLINE runST #-}--runSTRep :: (forall s. ST.STRep s a) -> a-runSTRep st_rep = case st_rep realWorld# of-                        (# _, r #) -> r-{-# INLINE [0] runSTRep #-}-#endif
− Data/HashMap/UnsafeShift.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE MagicHash #-}--module Data.HashMap.UnsafeShift-    ( unsafeShiftL-    , unsafeShiftR-    ) where--import GHC.Exts (Word(W#), Int(I#), uncheckedShiftL#, uncheckedShiftRL#)--unsafeShiftL :: Word -> Int -> Word-unsafeShiftL (W# x#) (I# i#) = W# (x# `uncheckedShiftL#` i#)-{-# INLINE unsafeShiftL #-}--unsafeShiftR :: Word -> Int -> Word-unsafeShiftR (W# x#) (I# i#) = W# (x# `uncheckedShiftRL#` i#)-{-# INLINE unsafeShiftR #-}
Data/HashSet.hs view
@@ -4,26 +4,95 @@ #endif  --------------------------------------------------------------------------- |--- Module      :  Data.HashSet--- Copyright   :  2011 Bryan O'Sullivan--- License     :  BSD-style--- Maintainer  :  johan.tibell@gmail.com--- Stability   :  provisional--- Portability :  portable------ A set of /hashable/ values.  A set cannot contain duplicate items.--- A 'HashSet' makes no guarantees as to the order of its elements.------ The implementation is based on /hash array mapped trie/.  A--- 'HashSet' is often faster than other tree-based set types,--- especially when value comparison is expensive, as in the case of--- strings.------ Many operations have a average-case complexity of /O(log n)/.  The--- implementation uses a large base (i.e. 16) so in practice these--- operations are constant time.+{-|+Module      :  Data.HashSet+Copyright   :  2011 Bryan O'Sullivan+License     :  BSD-style+Maintainer  :  johan.tibell@gmail.com+Stability   :  provisional+Portability :  portable += Introduction++'HashSet' allows you to store /unique/ elements, providing efficient insertion,+lookups, and deletion. A 'HashSet' makes no guarantees as to the order of its+elements.++If you are storing sets of "Data.Int"s consider using "Data.IntSet" from the+<https://hackage.haskell.org/package/containers containers> package.+++== Examples++All the examples below assume @HashSet@ is imported qualified, and uses the following @dataStructures@ set.++>>> import qualified Data.HashSet as HashSet+>>> let dataStructures = HashSet.fromList ["Set", "Map", "Graph", "Sequence"]++=== Basic Operations++Check membership in a set:++>>> -- Check if "Map" and "Trie" are in the set of data structures.+>>> HashSet.member "Map" dataStructures+True+>>> HashSet.member "Trie" dataStructures+False++Add a new entry to the set:++>>> let moreDataStructures = HashSet.insert "Trie" dataStructures+>>> HashSet.member "Trie" moreDataStructures+> True++Remove the @\"Graph\"@ entry from the set of data structures.++>>> let fewerDataStructures = HashSet.delete "Graph" dataStructures+>>> HashSet.toList fewerDataStructures+["Map","Set","Sequence"]+++Create a new set and combine it with our original set.++>>> let unorderedDataStructures = HashSet.fromList ["HashSet", "HashMap"]+>>> HashSet.union dataStructures unorderedDataStructures+fromList ["Map","HashSet","Graph","HashMap","Set","Sequence"]++=== Using custom data with HashSet++To create a @HashSet@ of your custom type, the type must have instances for+'Data.Eq.Eq' and 'Data.Hashable.Hashable'. The @Hashable@ typeclass is defined in the+<https://hackage.haskell.org/package/hashable hashable> package, see the+documentation for information on how to make your type an instance of+@Hashable@.++We'll start by setting up our custom data type:++>>> :set -XDeriveGeneric+>>> import GHC.Generics (Generic)+>>> import Data.Hashable+>>> data Person = Person { name :: String, likesDogs :: Bool } deriving (Show, Eq, Generic)+>>> instance Hashable Person++And now we'll use it!++>>> let people = HashSet.fromList [Person "Lana" True, Person "Joe" False, Person "Simon" True]+>>> HashSet.filter likesDogs people+fromList [Person {name = "Simon", likesDogs = True},Person {name = "Lana", likesDogs = True}]+++== Performance++The implementation is based on /hash array mapped tries/.  A+'HashSet' is often faster than other 'Data.Ord.Ord'-based set types,+especially when value comparisons are expensive, as in the case of+strings.++Many operations have a average-case complexity of /O(log n)/.  The+implementation uses a large base (i.e. 16) so in practice these+operations are constant time.+-}+ module Data.HashSet     (       HashSet@@ -42,6 +111,7 @@     , member     , insert     , delete+    , isSubsetOf      -- * Transformations     , map@@ -68,5 +138,5 @@     , fromMap     ) where -import Data.HashSet.Base+import Data.HashSet.Internal import Prelude ()
− Data/HashSet/Base.hs
@@ -1,411 +0,0 @@-{-# LANGUAGE CPP, DeriveDataTypeable #-}-#if __GLASGOW_HASKELL__ >= 708-{-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE TypeFamilies #-}-#endif-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif----------------------------------------------------------------------------- |--- Module      :  Data.HashSet.Base--- Copyright   :  2011 Bryan O'Sullivan--- License     :  BSD-style--- Maintainer  :  johan.tibell@gmail.com--- Stability   :  provisional--- Portability :  portable------ A set of /hashable/ values.  A set cannot contain duplicate items.--- A 'HashSet' makes no guarantees as to the order of its elements.------ The implementation is based on /hash array mapped trie/.  A--- 'HashSet' is often faster than other tree-based set types,--- especially when value comparison is expensive, as in the case of--- strings.------ Many operations have a average-case complexity of /O(log n)/.  The--- implementation uses a large base (i.e. 16) so in practice these--- operations are constant time.--module Data.HashSet.Base-    (-      HashSet--    -- * Construction-    , empty-    , singleton--    -- * Combine-    , union-    , unions--    -- * Basic interface-    , null-    , size-    , member-    , insert-    , delete--    -- * Transformations-    , map--      -- * Difference and intersection-    , difference-    , intersection--    -- * Folds-    , foldr-    , foldr'-    , foldl-    , foldl'--    -- * Filter-    , filter--    -- * Conversions--    -- ** Lists-    , toList-    , fromList--    -- * HashMaps-    , toMap-    , fromMap--    -- Exported from Data.HashMap.{Strict, Lazy}-    , keysSet-    ) where--import Control.DeepSeq (NFData(..))-import Data.Data hiding (Typeable)-import Data.HashMap.Base-  ( HashMap, foldMapWithKey, foldlWithKey, foldrWithKey-  , equalKeys, equalKeys1)-import Data.Hashable (Hashable(hashWithSalt))-#if __GLASGOW_HASKELL__ >= 711-import Data.Semigroup (Semigroup(..))-#elif __GLASGOW_HASKELL__ < 709-import Data.Monoid (Monoid(..))-#endif-import GHC.Exts (build)-import Prelude hiding (filter, foldr, foldl, map, null)-import qualified Data.Foldable as Foldable-import qualified Data.HashMap.Base as H-import qualified Data.List as List-import Data.Typeable (Typeable)-import Text.Read--#if __GLASGOW_HASKELL__ >= 708-import qualified GHC.Exts as Exts-#endif--#if MIN_VERSION_base(4,9,0)-import Data.Functor.Classes-#endif--#if MIN_VERSION_hashable(1,2,5)-import qualified Data.Hashable.Lifted as H-#endif--import Data.Functor ((<$))---- | A set of values.  A set cannot contain duplicate values.-newtype HashSet a = HashSet {-      asMap :: HashMap a ()-    } deriving (Typeable)--#if __GLASGOW_HASKELL__ >= 708-type role HashSet nominal-#endif--instance (NFData a) => NFData (HashSet a) where-    rnf = rnf . asMap-    {-# INLINE rnf #-}---- | Note that, in the presence of hash collisions, equal @HashSet@s may--- behave differently, i.e. substitutivity may be violated:------ >>> data D = A | B deriving (Eq, Show)--- >>> instance Hashable D where hashWithSalt salt _d = salt------ >>> x = fromList [A, B]--- >>> y = fromList [B, A]------ >>> x == y--- True--- >>> toList x--- [A,B]--- >>> toList y--- [B,A]------ In general, the lack of substitutivity can be observed with any function--- that depends on the key ordering, such as folds and traversals.-instance (Eq a) => Eq (HashSet a) where-    HashSet a == HashSet b = equalKeys a b-    {-# INLINE (==) #-}--#if MIN_VERSION_base(4,9,0)-instance Eq1 HashSet where-    liftEq eq (HashSet a) (HashSet b) = equalKeys1 eq a b-#endif--instance (Ord a) => Ord (HashSet a) where-    compare (HashSet a) (HashSet b) = compare a b-    {-# INLINE compare #-}--#if MIN_VERSION_base(4,9,0)-instance Ord1 HashSet where-    liftCompare c (HashSet a) (HashSet b) = liftCompare2 c compare a b-#endif--instance Foldable.Foldable HashSet where-    foldMap f = foldMapWithKey (\a _ -> f a) . asMap-    foldr = foldr-    {-# INLINE foldr #-}-    foldl = foldl-    {-# INLINE foldl #-}-    foldl' = foldl'-    {-# INLINE foldl' #-}-    foldr' = foldr'-    {-# INLINE foldr' #-}-#if MIN_VERSION_base(4,8,0)-    toList = toList-    {-# INLINE toList #-}-    null = null-    {-# INLINE null #-}-    length = size-    {-# INLINE length #-}-#endif--#if __GLASGOW_HASKELL__ >= 711--- | '<>' = 'union'------ /O(n+m)/------ To obtain good performance, the smaller set must be presented as--- the first argument.------ ==== __Examples__------ >>> fromList [1,2] <> fromList [2,3]--- fromList [1,2,3]-instance (Hashable a, Eq a) => Semigroup (HashSet a) where-    (<>) = union-    {-# INLINE (<>) #-}-#endif---- | 'mempty' = 'empty'------ 'mappend' = 'union'------ /O(n+m)/------ To obtain good performance, the smaller set must be presented as--- the first argument.------ ==== __Examples__------ >>> mappend (fromList [1,2]) (fromList [2,3])--- fromList [1,2,3]-instance (Hashable a, Eq a) => Monoid (HashSet a) where-    mempty = empty-    {-# INLINE mempty #-}-#if __GLASGOW_HASKELL__ >= 711-    mappend = (<>)-#else-    mappend = union-#endif-    {-# INLINE mappend #-}--instance (Eq a, Hashable a, Read a) => Read (HashSet a) where-    readPrec = parens $ prec 10 $ do-      Ident "fromList" <- lexP-      xs <- readPrec-      return (fromList xs)--    readListPrec = readListPrecDefault--#if MIN_VERSION_base(4,9,0)-instance Show1 HashSet where-    liftShowsPrec sp sl d m =-        showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)-#endif--instance (Show a) => Show (HashSet a) where-    showsPrec d m = showParen (d > 10) $-      showString "fromList " . shows (toList m)--instance (Data a, Eq a, Hashable a) => Data (HashSet a) where-    gfoldl f z m   = z fromList `f` toList m-    toConstr _     = fromListConstr-    gunfold k z c  = case constrIndex c of-        1 -> k (z fromList)-        _ -> error "gunfold"-    dataTypeOf _   = hashSetDataType-    dataCast1 f    = gcast1 f--#if MIN_VERSION_hashable(1,2,6)-instance H.Hashable1 HashSet where-    liftHashWithSalt h s = H.liftHashWithSalt2 h hashWithSalt s . asMap-#endif--instance (Hashable a) => Hashable (HashSet a) where-    hashWithSalt salt = hashWithSalt salt . asMap--fromListConstr :: Constr-fromListConstr = mkConstr hashSetDataType "fromList" [] Prefix--hashSetDataType :: DataType-hashSetDataType = mkDataType "Data.HashSet.Base.HashSet" [fromListConstr]---- | /O(1)/ Construct an empty set.-empty :: HashSet a-empty = HashSet H.empty---- | /O(1)/ Construct a set with a single element.-singleton :: Hashable a => a -> HashSet a-singleton a = HashSet (H.singleton a ())-{-# INLINABLE singleton #-}---- | /O(1)/ Convert to the equivalent 'HashMap'.-toMap :: HashSet a -> HashMap a ()-toMap = asMap---- | /O(1)/ Convert from the equivalent 'HashMap'.-fromMap :: HashMap a () -> HashSet a-fromMap = HashSet---- | /O(n)/ Produce a 'HashSet' of all the keys in the given 'HashMap'.------ @since 0.2.10.0-keysSet :: HashMap k a -> HashSet k-keysSet m = fromMap (() <$ m)---- | /O(n+m)/ Construct a set containing all elements from both sets.------ To obtain good performance, the smaller set must be presented as--- the first argument.------ ==== __Examples__------ >>> union (fromList [1,2]) (fromList [2,3])--- fromList [1,2,3]-union :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a-union s1 s2 = HashSet $ H.union (asMap s1) (asMap s2)-{-# INLINE union #-}---- TODO: Figure out the time complexity of 'unions'.---- | Construct a set containing all elements from a list of sets.-unions :: (Eq a, Hashable a) => [HashSet a] -> HashSet a-unions = List.foldl' union empty-{-# INLINE unions #-}---- | /O(1)/ Return 'True' if this set is empty, 'False' otherwise.-null :: HashSet a -> Bool-null = H.null . asMap-{-# INLINE null #-}---- | /O(n)/ Return the number of elements in this set.-size :: HashSet a -> Int-size = H.size . asMap-{-# INLINE size #-}---- | /O(log n)/ Return 'True' if the given value is present in this--- set, 'False' otherwise.-member :: (Eq a, Hashable a) => a -> HashSet a -> Bool-member a s = case H.lookup a (asMap s) of-               Just _ -> True-               _      -> False-{-# INLINABLE member #-}---- | /O(log n)/ Add the specified value to this set.-insert :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a-insert a = HashSet . H.insert a () . asMap-{-# INLINABLE insert #-}---- | /O(log n)/ Remove the specified value from this set if--- present.-delete :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a-delete a = HashSet . H.delete a . asMap-{-# INLINABLE delete #-}---- | /O(n)/ Transform this set by applying a function to every value.--- The resulting set may be smaller than the source.-map :: (Hashable b, Eq b) => (a -> b) -> HashSet a -> HashSet b-map f = fromList . List.map f . toList-{-# INLINE map #-}---- | /O(n)/ Difference of two sets. Return elements of the first set--- not existing in the second.-difference :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a-difference (HashSet a) (HashSet b) = HashSet (H.difference a b)-{-# INLINABLE difference #-}---- | /O(n)/ Intersection of two sets. Return elements present in both--- the first set and the second.-intersection :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a-intersection (HashSet a) (HashSet b) = HashSet (H.intersection a b)-{-# INLINABLE intersection #-}---- | /O(n)/ Reduce this set by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).  Each application of the operator--- is evaluated before before using the result in the next--- application.  This function is strict in the starting value.-foldl' :: (a -> b -> a) -> a -> HashSet b -> a-foldl' f z0 = H.foldlWithKey' g z0 . asMap-  where g z k _ = f z k-{-# INLINE foldl' #-}---- | /O(n)/ Reduce this set by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator). Each application of the operator--- is evaluated before before using the result in the next--- application. This function is strict in the starting value.-foldr' :: (b -> a -> a) -> a -> HashSet b -> a-foldr' f z0 = H.foldrWithKey' g z0 . asMap-  where g k _ z = f k z-{-# INLINE foldr' #-}---- | /O(n)/ Reduce this set by applying a binary operator to all--- elements, using the given starting value (typically the--- right-identity of the operator).-foldr :: (b -> a -> a) -> a -> HashSet b -> a-foldr f z0 = foldrWithKey g z0 . asMap-  where g k _ z = f k z-{-# INLINE foldr #-}---- | /O(n)/ Reduce this set by applying a binary operator to all--- elements, using the given starting value (typically the--- left-identity of the operator).-foldl :: (a -> b -> a) -> a -> HashSet b -> a-foldl f z0 = foldlWithKey g z0 . asMap-  where g z k _ = f z k-{-# INLINE foldl #-}---- | /O(n)/ Filter this set by retaining only elements satisfying a--- predicate.-filter :: (a -> Bool) -> HashSet a -> HashSet a-filter p = HashSet . H.filterWithKey q . asMap-  where q k _ = p k-{-# INLINE filter #-}---- | /O(n)/ Return a list of this set's elements.  The list is--- produced lazily.-toList :: HashSet a -> [a]-toList t = build (\ c z -> foldrWithKey ((const .) c) z (asMap t))-{-# INLINE toList #-}---- | /O(n*min(W, n))/ Construct a set from a list of elements.-fromList :: (Eq a, Hashable a) => [a] -> HashSet a-fromList = HashSet . List.foldl' (\ m k -> H.insert k () m) H.empty-{-# INLINE fromList #-}--#if __GLASGOW_HASKELL__ >= 708-instance (Eq a, Hashable a) => Exts.IsList (HashSet a) where-    type Item (HashSet a) = a-    fromList = fromList-    toList   = toList-#endif
+ Data/HashSet/Internal.hs view
@@ -0,0 +1,484 @@+{-# LANGUAGE CPP, DeriveDataTypeable #-}+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE TypeFamilies #-}+#endif+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+{-# OPTIONS_HADDOCK not-home #-}++------------------------------------------------------------------------+-- |+-- Module      :  Data.HashSet.Internal+-- Copyright   :  2011 Bryan O'Sullivan+-- License     :  BSD-style+-- Maintainer  :  johan.tibell@gmail.com+-- Portability :  portable+--+-- = WARNING+--+-- This module is considered __internal__.+--+-- The Package Versioning Policy __does not apply__.+--+-- The contents of this module may change __in any way whatsoever__+-- and __without any warning__ between minor versions of this package.+--+-- Authors importing this module are expected to track development+-- closely.+--+-- = Description+--+-- A set of /hashable/ values.  A set cannot contain duplicate items.+-- A 'HashSet' makes no guarantees as to the order of its elements.+--+-- The implementation is based on /hash array mapped tries/.  A+-- 'HashSet' is often faster than other tree-based set types,+-- especially when value comparison is expensive, as in the case of+-- strings.+--+-- Many operations have a average-case complexity of /O(log n)/.  The+-- implementation uses a large base (i.e. 16) so in practice these+-- operations are constant time.++module Data.HashSet.Internal+    (+      HashSet++    -- * Construction+    , empty+    , singleton++    -- * Basic interface+    , null+    , size+    , member+    , insert+    , delete+    , isSubsetOf++    -- * Transformations+    , map++    -- * Combine+    , union+    , unions++      -- * Difference and intersection+    , difference+    , intersection++    -- * Folds+    , foldr+    , foldr'+    , foldl+    , foldl'++    -- * Filter+    , filter++    -- * Conversions++    -- ** Lists+    , toList+    , fromList++    -- * HashMaps+    , toMap+    , fromMap++    -- Exported from Data.HashMap.{Strict, Lazy}+    , keysSet+    ) where++import Control.DeepSeq (NFData(..))+import Data.Data hiding (Typeable)+import Data.HashMap.Internal+  ( HashMap, foldMapWithKey, foldlWithKey, foldrWithKey+  , equalKeys, equalKeys1)+import Data.Hashable (Hashable(hashWithSalt))+#if __GLASGOW_HASKELL__ >= 711+import Data.Semigroup (Semigroup(..))+#elif __GLASGOW_HASKELL__ < 709+import Data.Monoid (Monoid(..))+#endif+import GHC.Exts (build)+import Prelude hiding (filter, foldr, foldl, map, null)+import qualified Data.Foldable as Foldable+import qualified Data.HashMap.Internal as H+import qualified Data.List as List+import Data.Typeable (Typeable)+import Text.Read++#if __GLASGOW_HASKELL__ >= 708+import qualified GHC.Exts as Exts+#endif++#if MIN_VERSION_base(4,9,0)+import Data.Functor.Classes+#endif++#if MIN_VERSION_hashable(1,2,5)+import qualified Data.Hashable.Lifted as H+#endif++import Data.Functor ((<$))++-- | A set of values.  A set cannot contain duplicate values.+newtype HashSet a = HashSet {+      asMap :: HashMap a ()+    } deriving (Typeable)++#if __GLASGOW_HASKELL__ >= 708+type role HashSet nominal+#endif++instance (NFData a) => NFData (HashSet a) where+    rnf = rnf . asMap+    {-# INLINE rnf #-}++-- | Note that, in the presence of hash collisions, equal @HashSet@s may+-- behave differently, i.e. substitutivity may be violated:+--+-- >>> data D = A | B deriving (Eq, Show)+-- >>> instance Hashable D where hashWithSalt salt _d = salt+--+-- >>> x = fromList [A, B]+-- >>> y = fromList [B, A]+--+-- >>> x == y+-- True+-- >>> toList x+-- [A,B]+-- >>> toList y+-- [B,A]+--+-- In general, the lack of substitutivity can be observed with any function+-- that depends on the key ordering, such as folds and traversals.+instance (Eq a) => Eq (HashSet a) where+    HashSet a == HashSet b = equalKeys a b+    {-# INLINE (==) #-}++#if MIN_VERSION_base(4,9,0)+instance Eq1 HashSet where+    liftEq eq (HashSet a) (HashSet b) = equalKeys1 eq a b+#endif++instance (Ord a) => Ord (HashSet a) where+    compare (HashSet a) (HashSet b) = compare a b+    {-# INLINE compare #-}++#if MIN_VERSION_base(4,9,0)+instance Ord1 HashSet where+    liftCompare c (HashSet a) (HashSet b) = liftCompare2 c compare a b+#endif++instance Foldable.Foldable HashSet where+    foldMap f = foldMapWithKey (\a _ -> f a) . asMap+    foldr = foldr+    {-# INLINE foldr #-}+    foldl = foldl+    {-# INLINE foldl #-}+    foldl' = foldl'+    {-# INLINE foldl' #-}+    foldr' = foldr'+    {-# INLINE foldr' #-}+#if MIN_VERSION_base(4,8,0)+    toList = toList+    {-# INLINE toList #-}+    null = null+    {-# INLINE null #-}+    length = size+    {-# INLINE length #-}+#endif++#if __GLASGOW_HASKELL__ >= 711+-- | '<>' = 'union'+--+-- /O(n+m)/+--+-- To obtain good performance, the smaller set must be presented as+-- the first argument.+--+-- ==== __Examples__+--+-- >>> fromList [1,2] <> fromList [2,3]+-- fromList [1,2,3]+instance (Hashable a, Eq a) => Semigroup (HashSet a) where+    (<>) = union+    {-# INLINE (<>) #-}+#endif++-- | 'mempty' = 'empty'+--+-- 'mappend' = 'union'+--+-- /O(n+m)/+--+-- To obtain good performance, the smaller set must be presented as+-- the first argument.+--+-- ==== __Examples__+--+-- >>> mappend (fromList [1,2]) (fromList [2,3])+-- fromList [1,2,3]+instance (Hashable a, Eq a) => Monoid (HashSet a) where+    mempty = empty+    {-# INLINE mempty #-}+#if __GLASGOW_HASKELL__ >= 711+    mappend = (<>)+#else+    mappend = union+#endif+    {-# INLINE mappend #-}++instance (Eq a, Hashable a, Read a) => Read (HashSet a) where+    readPrec = parens $ prec 10 $ do+      Ident "fromList" <- lexP+      xs <- readPrec+      return (fromList xs)++    readListPrec = readListPrecDefault++#if MIN_VERSION_base(4,9,0)+instance Show1 HashSet where+    liftShowsPrec sp sl d m =+        showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)+#endif++instance (Show a) => Show (HashSet a) where+    showsPrec d m = showParen (d > 10) $+      showString "fromList " . shows (toList m)++instance (Data a, Eq a, Hashable a) => Data (HashSet a) where+    gfoldl f z m   = z fromList `f` toList m+    toConstr _     = fromListConstr+    gunfold k z c  = case constrIndex c of+        1 -> k (z fromList)+        _ -> error "gunfold"+    dataTypeOf _   = hashSetDataType+    dataCast1 f    = gcast1 f++#if MIN_VERSION_hashable(1,2,6)+instance H.Hashable1 HashSet where+    liftHashWithSalt h s = H.liftHashWithSalt2 h hashWithSalt s . asMap+#endif++instance (Hashable a) => Hashable (HashSet a) where+    hashWithSalt salt = hashWithSalt salt . asMap++fromListConstr :: Constr+fromListConstr = mkConstr hashSetDataType "fromList" [] Prefix++hashSetDataType :: DataType+hashSetDataType = mkDataType "Data.HashSet.Internal.HashSet" [fromListConstr]++-- | /O(1)/ Construct an empty set.+--+-- >>> HashSet.empty+-- fromList []+empty :: HashSet a+empty = HashSet H.empty++-- | /O(1)/ Construct a set with a single element.+--+-- >>> HashSet.singleton 1+-- fromList [1]+singleton :: Hashable a => a -> HashSet a+singleton a = HashSet (H.singleton a ())+{-# INLINABLE singleton #-}++-- | /O(1)/ Convert to set to the equivalent 'HashMap' with @()@ values.+--+-- >>> HashSet.toMap (HashSet.singleton 1)+-- fromList [(1,())]+toMap :: HashSet a -> HashMap a ()+toMap = asMap++-- | /O(1)/ Convert from the equivalent 'HashMap' with @()@ values.+--+-- >>> HashSet.fromMap (HashMap.singleton 1 ())+-- fromList [1]+fromMap :: HashMap a () -> HashSet a+fromMap = HashSet++-- | /O(n)/ Produce a 'HashSet' of all the keys in the given 'HashMap'.+--+-- >>> HashSet.keysSet (HashMap.fromList [(1, "a"), (2, "b")]+-- fromList [1,2]+--+-- @since 0.2.10.0+keysSet :: HashMap k a -> HashSet k+keysSet m = fromMap (() <$ m)++-- | /O(n*log m)/ Inclusion of sets.+--+-- ==== __Examples__+--+-- >>> fromList [1,3] `isSubsetOf` fromList [1,2,3]+-- True+--+-- >>> fromList [1,2] `isSubsetOf` fromList [1,3]+-- False+--+-- @since 0.2.12+isSubsetOf :: (Eq a, Hashable a) => HashSet a -> HashSet a -> Bool+isSubsetOf s1 s2 = H.isSubmapOfBy (\_ _ -> True) (asMap s1) (asMap s2)++-- | /O(n+m)/ Construct a set containing all elements from both sets.+--+-- To obtain good performance, the smaller set must be presented as+-- the first argument.+--+-- >>> union (fromList [1,2]) (fromList [2,3])+-- fromList [1,2,3]+union :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a+union s1 s2 = HashSet $ H.union (asMap s1) (asMap s2)+{-# INLINE union #-}++-- TODO: Figure out the time complexity of 'unions'.++-- | Construct a set containing all elements from a list of sets.+unions :: (Eq a, Hashable a) => [HashSet a] -> HashSet a+unions = List.foldl' union empty+{-# INLINE unions #-}++-- | /O(1)/ Return 'True' if this set is empty, 'False' otherwise.+--+-- >>> HashSet.null HashSet.empty+-- True+-- >>> HashSet.null (HashSet.singleton 1)+-- False+null :: HashSet a -> Bool+null = H.null . asMap+{-# INLINE null #-}++-- | /O(n)/ Return the number of elements in this set.+--+-- >>> HashSet.size HashSet.empty+-- 0+-- >>> HashSet.size (HashSet.fromList [1,2,3])+-- 3+size :: HashSet a -> Int+size = H.size . asMap+{-# INLINE size #-}++-- | /O(log n)/ Return 'True' if the given value is present in this+-- set, 'False' otherwise.+--+-- >>> HashSet.member 1 (Hashset.fromList [1,2,3])+-- True+-- >>> HashSet.member 1 (Hashset.fromList [4,5,6])+-- False+member :: (Eq a, Hashable a) => a -> HashSet a -> Bool+member a s = case H.lookup a (asMap s) of+               Just _ -> True+               _      -> False+{-# INLINABLE member #-}++-- | /O(log n)/ Add the specified value to this set.+--+-- >>> HashSet.insert 1 HashSet.empty+-- fromList [1]+insert :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a+insert a = HashSet . H.insert a () . asMap+{-# INLINABLE insert #-}++-- | /O(log n)/ Remove the specified value from this set if present.+--+-- >>> HashSet.delete 1 (HashSet.fromList [1,2,3])+-- fromList [2,3]+-- >>> HashSet.delete 1 (HashSet.fromList [4,5,6])+-- fromList [4,5,6]+delete :: (Eq a, Hashable a) => a -> HashSet a -> HashSet a+delete a = HashSet . H.delete a . asMap+{-# INLINABLE delete #-}++-- | /O(n)/ Transform this set by applying a function to every value.+-- The resulting set may be smaller than the source.+--+-- >>> HashSet.map show (HashSet.fromList [1,2,3])+-- HashSet.fromList ["1","2","3"]+map :: (Hashable b, Eq b) => (a -> b) -> HashSet a -> HashSet b+map f = fromList . List.map f . toList+{-# INLINE map #-}++-- | /O(n)/ Difference of two sets. Return elements of the first set+-- not existing in the second.+--+-- >>> HashSet.difference (HashSet.fromList [1,2,3]) (HashSet.fromList [2,3,4])+-- fromList [1]+difference :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a+difference (HashSet a) (HashSet b) = HashSet (H.difference a b)+{-# INLINABLE difference #-}++-- | /O(n)/ Intersection of two sets. Return elements present in both+-- the first set and the second.+--+-- >>> HashSet.intersection (HashSet.fromList [1,2,3]) (HashSet.fromList [2,3,4])+-- fromList [2,3]+intersection :: (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a+intersection (HashSet a) (HashSet b) = HashSet (H.intersection a b)+{-# INLINABLE intersection #-}++-- | /O(n)/ Reduce this set by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).  Each application of the operator+-- is evaluated before before using the result in the next+-- application.  This function is strict in the starting value.+foldl' :: (a -> b -> a) -> a -> HashSet b -> a+foldl' f z0 = H.foldlWithKey' g z0 . asMap+  where g z k _ = f z k+{-# INLINE foldl' #-}++-- | /O(n)/ Reduce this set by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator). Each application of the operator+-- is evaluated before before using the result in the next+-- application. This function is strict in the starting value.+foldr' :: (b -> a -> a) -> a -> HashSet b -> a+foldr' f z0 = H.foldrWithKey' g z0 . asMap+  where g k _ z = f k z+{-# INLINE foldr' #-}++-- | /O(n)/ Reduce this set by applying a binary operator to all+-- elements, using the given starting value (typically the+-- right-identity of the operator).+foldr :: (b -> a -> a) -> a -> HashSet b -> a+foldr f z0 = foldrWithKey g z0 . asMap+  where g k _ z = f k z+{-# INLINE foldr #-}++-- | /O(n)/ Reduce this set by applying a binary operator to all+-- elements, using the given starting value (typically the+-- left-identity of the operator).+foldl :: (a -> b -> a) -> a -> HashSet b -> a+foldl f z0 = foldlWithKey g z0 . asMap+  where g z k _ = f z k+{-# INLINE foldl #-}++-- | /O(n)/ Filter this set by retaining only elements satisfying a+-- predicate.+filter :: (a -> Bool) -> HashSet a -> HashSet a+filter p = HashSet . H.filterWithKey q . asMap+  where q k _ = p k+{-# INLINE filter #-}++-- | /O(n)/ Return a list of this set's elements.  The list is+-- produced lazily.+toList :: HashSet a -> [a]+toList t = build (\ c z -> foldrWithKey ((const .) c) z (asMap t))+{-# INLINE toList #-}++-- | /O(n*min(W, n))/ Construct a set from a list of elements.+fromList :: (Eq a, Hashable a) => [a] -> HashSet a+fromList = HashSet . List.foldl' (\ m k -> H.insert k () m) H.empty+{-# INLINE fromList #-}++#if __GLASGOW_HASKELL__ >= 708+instance (Eq a, Hashable a) => Exts.IsList (HashSet a) where+    type Item (HashSet a) = a+    fromList = fromList+    toList   = toList+#endif
benchmarks/Benchmarks.hs view
@@ -1,9 +1,8 @@-{-# LANGUAGE CPP, DeriveGeneric, GADTs, PackageImports, RecordWildCards #-}+{-# LANGUAGE CPP, DeriveAnyClass, DeriveGeneric, GADTs, PackageImports, RecordWildCards #-}  module Main where  import Control.DeepSeq-import Control.DeepSeq.Generics (genericRnf) import Gauge (bench, bgroup, defaultMain, env, nf, whnf) import Data.Bits ((.&.)) import Data.Functor.Identity@@ -56,18 +55,24 @@     elemsDupBS :: ![(BS.ByteString, Int)],     elemsDupI  :: ![(Int, Int)], -    hm    :: !(HM.HashMap String Int),-    hmbs  :: !(HM.HashMap BS.ByteString Int),-    hmi   :: !(HM.HashMap Int Int),-    hmi2  :: !(HM.HashMap Int Int),-    m     :: !(M.Map String Int),-    mbs   :: !(M.Map BS.ByteString Int),-    im    :: !(IM.IntMap Int),-    ihm   :: !(IHM.Map String Int),-    ihmbs :: !(IHM.Map BS.ByteString Int)-    } deriving Generic--instance NFData Env where rnf = genericRnf+    hm          :: !(HM.HashMap String Int),+    hmSubset    :: !(HM.HashMap String Int),+    hmbs        :: !(HM.HashMap BS.ByteString Int),+    hmbsSubset  :: !(HM.HashMap BS.ByteString Int),+    hmi         :: !(HM.HashMap Int Int),+    hmiSubset   :: !(HM.HashMap Int Int),+    hmi2        :: !(HM.HashMap Int Int),+    m           :: !(M.Map String Int),+    mSubset     :: !(M.Map String Int),+    mbs         :: !(M.Map BS.ByteString Int),+    mbsSubset   :: !(M.Map BS.ByteString Int),+    im          :: !(IM.IntMap Int),+    imSubset    :: !(IM.IntMap Int),+    ihm         :: !(IHM.Map String Int),+    ihmSubset   :: !(IHM.Map String Int),+    ihmbs       :: !(IHM.Map BS.ByteString Int),+    ihmbsSubset :: !(IHM.Map BS.ByteString Int)+    } deriving (Generic, NFData)  setupEnv :: IO Env setupEnv = do@@ -92,16 +97,29 @@         elemsDupBS = zip keysDupBS [1..n]         elemsDupI  = zip keysDupI [1..n] -        hm   = HM.fromList elems-        hmbs = HM.fromList elemsBS-        hmi  = HM.fromList elemsI-        hmi2 = HM.fromList elemsI2-        m    = M.fromList elems-        mbs  = M.fromList elemsBS-        im   = IM.fromList elemsI-        ihm  = IHM.fromList elems-        ihmbs = IHM.fromList elemsBS+        hm          = HM.fromList elems+        hmSubset    = HM.fromList (takeSubset n elems)+        hmbs        = HM.fromList elemsBS+        hmbsSubset  = HM.fromList (takeSubset n elemsBS)+        hmi         = HM.fromList elemsI+        hmiSubset   = HM.fromList (takeSubset n elemsI)+        hmi2        = HM.fromList elemsI2+        m           = M.fromList elems+        mSubset     = M.fromList (takeSubset n elems)+        mbs         = M.fromList elemsBS+        mbsSubset   = M.fromList (takeSubset n elemsBS)+        im          = IM.fromList elemsI+        imSubset    = IM.fromList (takeSubset n elemsI)+        ihm         = IHM.fromList elems+        ihmSubset   = IHM.fromList (takeSubset n elems)+        ihmbs       = IHM.fromList elemsBS+        ihmbsSubset = IHM.fromList (takeSubset n elemsBS)     return Env{..}+  where+    takeSubset n elements =+      -- use 50% of the elements for a subset check.+      let subsetSize = round (fromIntegral n * 0.5 :: Double) :: Int+      in take subsetSize elements  main :: IO () main = do@@ -143,6 +161,10 @@             [ bench "String" $ whnf M.fromList elems             , bench "ByteString" $ whnf M.fromList elemsBS             ]+          , bgroup "isSubmapOf"+            [ bench "String" $ whnf (M.isSubmapOf mSubset) m+            , bench "ByteString" $ whnf (M.isSubmapOf mbsSubset) mbs+            ]           ]            -- ** Map from the hashmap package@@ -180,6 +202,10 @@             [ bench "String" $ whnf IHM.fromList elems             , bench "ByteString" $ whnf IHM.fromList elemsBS             ]+          , bgroup "isSubmapOf"+            [ bench "String" $ whnf (IHM.isSubmapOf ihmSubset) ihm+            , bench "ByteString" $ whnf (IHM.isSubmapOf ihmbsSubset) ihmbs+            ]           , bgroup "hash"             [ bench "String" $ whnf hash hm             , bench "ByteString" $ whnf hash hmbs@@ -197,6 +223,7 @@           , bench "delete-miss" $ whnf (deleteIM keysI') im           , bench "size" $ whnf IM.size im           , bench "fromList" $ whnf IM.fromList elemsI+          , bench "isSubmapOf" $ whnf (IM.isSubmapOf imSubset) im           ]          , env setupEnv $ \ ~(Env{..}) ->@@ -272,6 +299,16 @@             , bench "ByteString" $ whnf (alterFDelete keysBS') hmbs             , bench "Int" $ whnf (alterFDelete keysI') hmi             ]+          , bgroup "isSubmapOf"+            [ bench "String" $ whnf (HM.isSubmapOf hmSubset) hm+            , bench "ByteString" $ whnf (HM.isSubmapOf hmbsSubset) hmbs+            , bench "Int" $ whnf (HM.isSubmapOf hmiSubset) hmi+            ]+          , bgroup "isSubmapOfNaive"+            [ bench "String" $ whnf (isSubmapOfNaive hmSubset) hm+            , bench "ByteString" $ whnf (isSubmapOfNaive hmbsSubset) hmbs+            , bench "Int" $ whnf (isSubmapOfNaive hmiSubset) hmi+            ]              -- Combine           , bench "union" $ whnf (HM.union hmi) hmi2@@ -398,6 +435,12 @@                             -> HM.HashMap String Int #-} {-# SPECIALIZE alterFDelete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int                             -> HM.HashMap BS.ByteString Int #-}++isSubmapOfNaive :: (Eq k, Hashable k) => HM.HashMap k Int -> HM.HashMap k Int -> Bool+isSubmapOfNaive m1 m2 = and [ Just v1 == HM.lookup k1 m2 | (k1,v1) <- HM.toList m1 ]+{-# SPECIALIZE isSubmapOfNaive :: HM.HashMap Int Int -> HM.HashMap Int Int -> Bool #-}+{-# SPECIALIZE isSubmapOfNaive :: HM.HashMap String Int -> HM.HashMap String Int -> Bool #-}+{-# SPECIALIZE isSubmapOfNaive :: HM.HashMap BS.ByteString Int -> HM.HashMap BS.ByteString Int -> Bool #-}  ------------------------------------------------------------------------ -- * Map
tests/HashMapProperties.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} -- because of Arbitrary (HashMap k v)  -- | Tests for the 'Data.HashMap.Lazy' module.  We test functions by -- comparing them to a simpler model, an association list.@@ -15,13 +16,15 @@ import qualified Data.List as L import Data.Ord (comparing) #if defined(STRICT)+import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM import qualified Data.Map.Strict as M #else+import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as HM import qualified Data.Map.Lazy as M #endif-import Test.QuickCheck (Arbitrary, Property, (==>), (===))+import Test.QuickCheck (Arbitrary(..), Property, (==>), (===), forAll, elements) import Test.Framework (Test, defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) #if MIN_VERSION_base(4,8,0)@@ -38,6 +41,9 @@ instance Hashable Key where     hashWithSalt salt k = hashWithSalt salt (unK k) `mod` 20 +instance (Eq k, Hashable k, Arbitrary k, Arbitrary v) => Arbitrary (HashMap k v) where+  arbitrary = fmap (HM.fromList) arbitrary+ ------------------------------------------------------------------------ -- * Properties @@ -225,6 +231,44 @@   `eq`   getConst . HM.alterF (Const . apply f) k +pSubmap :: [(Key, Int)] -> [(Key, Int)] -> Bool+pSubmap xs ys = M.isSubmapOf (M.fromList xs) (M.fromList ys) ==+                HM.isSubmapOf (HM.fromList xs) (HM.fromList ys)++pSubmapReflexive :: HashMap Key Int -> Bool+pSubmapReflexive m = HM.isSubmapOf m m++pSubmapUnion :: HashMap Key Int -> HashMap Key Int -> Bool+pSubmapUnion m1 m2 = HM.isSubmapOf m1 (HM.union m1 m2)++pNotSubmapUnion :: HashMap Key Int -> HashMap Key Int -> Property+pNotSubmapUnion m1 m2 = not (HM.isSubmapOf m1 m2) ==> HM.isSubmapOf m1 (HM.union m1 m2)++pSubmapDifference :: HashMap Key Int -> HashMap Key Int -> Bool+pSubmapDifference m1 m2 = HM.isSubmapOf (HM.difference m1 m2) m1++pNotSubmapDifference :: HashMap Key Int -> HashMap Key Int -> Property+pNotSubmapDifference m1 m2 =+  not (HM.null (HM.intersection m1 m2)) ==>+  not (HM.isSubmapOf m1 (HM.difference m1 m2))++pSubmapDelete :: HashMap Key Int -> Property+pSubmapDelete m = not (HM.null m) ==>+  forAll (elements (HM.keys m)) $ \k ->+  HM.isSubmapOf (HM.delete k m) m++pNotSubmapDelete :: HashMap Key Int -> Property+pNotSubmapDelete m =+  not (HM.null m) ==>+  forAll (elements (HM.keys m)) $ \k ->+  not (HM.isSubmapOf m (HM.delete k m))++pSubmapInsert :: Key -> Int -> HashMap Key Int -> Property+pSubmapInsert k v m = not (HM.member k m) ==> HM.isSubmapOf m (HM.insert k v m)++pNotSubmapInsert :: Key -> Int -> HashMap Key Int -> Property+pNotSubmapInsert k v m = not (HM.member k m) ==> not (HM.isSubmapOf (HM.insert k v m) m)+ ------------------------------------------------------------------------ -- ** Combine @@ -439,6 +483,18 @@       , testProperty "alterFInsertWith" pAlterFInsertWith       , testProperty "alterFDelete" pAlterFDelete       , testProperty "alterFLookup" pAlterFLookup+      , testGroup "isSubmapOf"+        [ testProperty "container compatibility" pSubmap+        , testProperty "m ⊆ m" pSubmapReflexive+        , testProperty "m1 ⊆ m1 ∪ m2" pSubmapUnion+        , testProperty "m1 ⊈ m2  ⇒  m1 ∪ m2 ⊈ m1" pNotSubmapUnion+        , testProperty "m1\\m2 ⊆ m1" pSubmapDifference+        , testProperty "m1 ∩ m2 ≠ ∅  ⇒  m1 ⊈ m1\\m2 " pNotSubmapDifference+        , testProperty "delete k m ⊆ m" pSubmapDelete+        , testProperty "m ⊈ delete k m " pNotSubmapDelete+        , testProperty "k ∉ m  ⇒  m ⊆ insert k v m" pSubmapInsert+        , testProperty "k ∉ m  ⇒  insert k v m ⊈ m" pNotSubmapInsert+        ]       ]     -- Combine     , testProperty "union" pUnion
tests/List.hs view
@@ -1,6 +1,6 @@ module Main (main) where -import Data.HashMap.List+import Data.HashMap.Internal.List import Data.List (nub, sort, sortBy) import Data.Ord (comparing) @@ -9,7 +9,7 @@ import Test.QuickCheck ((==>), (===), property, Property)  tests :: Test-tests = testGroup "Data.HashMap.List"+tests = testGroup "Data.HashMap.Internal.List"     [ testProperty "isPermutationBy" pIsPermutation     , testProperty "isPermutationBy of different length" pIsPermutationDiffLength     , testProperty "pUnorderedCompare" pUnorderedCompare
unordered-containers.cabal view
@@ -1,5 +1,5 @@ name:           unordered-containers-version:        0.2.11.0+version:        0.2.12.0 synopsis:       Efficient hashing-based container types description:   Efficient hashing-based container types.  The containers have been@@ -37,17 +37,15 @@  library   exposed-modules:+    Data.HashMap.Internal+    Data.HashMap.Internal.Array+    Data.HashMap.Internal.List+    Data.HashMap.Internal.Strict+    Data.HashMap.Internal.Unsafe     Data.HashMap.Lazy     Data.HashMap.Strict     Data.HashSet-  other-modules:-    Data.HashMap.Array-    Data.HashMap.Base-    Data.HashMap.Strict.Base-    Data.HashMap.List-    Data.HashMap.Unsafe-    Data.HashMap.UnsafeShift-    Data.HashSet.Base+    Data.HashSet.Internal    build-depends:     base >= 4.7 && < 5,@@ -131,7 +129,7 @@   hs-source-dirs: tests .   main-is: List.hs   other-modules:-    Data.HashMap.List+    Data.HashMap.Internal.List   type: exitcode-stdio-1.0    build-depends:@@ -199,8 +197,7 @@     bytestring,     containers,     gauge >= 0.2.5 && < 0.3,-    deepseq >= 1.1,-    deepseq-generics,+    deepseq >= 1.4,     hashable >= 1.0.1.1,     hashmap,     mtl,