module Data.HashMap.Lazy
(
HashMap
, empty
, singleton
, null
, size
, lookup
, lookupDefault
, insert
, delete
, insertWith
, adjust
, union
, unionWith
, map
, traverseWithKey
, difference
, intersection
, foldl'
, foldlWithKey'
, foldr
, foldrWithKey
, filter
, filterWithKey
, elems
, keys
, toList
, fromList
, fromListWith
) where
import qualified Data.FullList.Lazy as FL
import Data.Hashable (Hashable(hash))
import qualified Data.List as List
import Prelude hiding (filter, foldr, lookup, map, null, pred)
import Data.HashMap.Common
null :: HashMap k v -> Bool
null Nil = True
null _ = False
size :: HashMap k v -> Int
size t = go t 0
where
go (Bin _ l r) !sz = go r (go l sz)
go (Tip _ l) !sz = sz + FL.size l
go Nil !sz = sz
lookup :: (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
lookup k0 t = go h0 k0 t
where
h0 = hash k0
go !h !k (Bin sm l r)
| zero h sm = go h k l
| otherwise = go h k r
go h k (Tip h' l)
| h == h' = FL.lookup k l
| otherwise = Nothing
go _ _ Nil = Nothing
#if __GLASGOW_HASKELL__ >= 700
#endif
lookupDefault :: (Eq k, Hashable k)
=> v
-> k -> HashMap k v -> v
lookupDefault def k t = case lookup k t of
Just v -> v
_ -> def
singleton :: Hashable k => k -> v -> HashMap k v
singleton k v = Tip h $ FL.singleton k v
where h = hash k
#if __GLASGOW_HASKELL__ >= 700
#endif
insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v
insert k0 v0 t0 = go h0 k0 v0 t0
where
h0 = hash k0
go !h !k v t@(Bin sm l r)
| nomatch h sm = join h (Tip h $ FL.singleton k v) sm t
| zero h sm = Bin sm (go h k v l) r
| otherwise = Bin sm l (go h k v r)
go h k v t@(Tip h' l)
| h == h' = Tip h $ FL.insert k v l
| otherwise = join h (Tip h $ FL.singleton k v) h' t
go h k v Nil = Tip h $ FL.singleton k v
#if __GLASGOW_HASKELL__ >= 700
#endif
delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
delete k0 = go h0 k0
where
h0 = hash k0
go !h !k t@(Bin sm l r)
| nomatch h sm = t
| zero h sm = bin sm (go h k l) r
| otherwise = bin sm l (go h k r)
go h k t@(Tip h' l)
| h == h' = case FL.delete k l of
Nothing -> Nil
Just l' -> Tip h' l'
| otherwise = t
go _ _ Nil = Nil
#if __GLASGOW_HASKELL__ >= 700
#endif
insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v
-> HashMap k v
insertWith f k0 v0 t0 = go h0 k0 v0 t0
where
h0 = hash k0
go !h !k v t@(Bin sm l r)
| nomatch h sm = join h (Tip h $ FL.singleton k v) sm t
| zero h sm = Bin sm (go h k v l) r
| otherwise = Bin sm l (go h k v r)
go h k v t@(Tip h' l)
| h == h' = Tip h $ FL.insertWith f k v l
| otherwise = join h (Tip h $ FL.singleton k v) h' t
go h k v Nil = Tip h $ FL.singleton k v
#if __GLASGOW_HASKELL__ >= 700
#endif
adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v
adjust f k0 t0 = go h0 k0 t0
where
h0 = hash k0
go !h !k t@(Bin sm l r)
| nomatch h sm = t
| zero h sm = Bin sm (go h k l) r
| otherwise = Bin sm l (go h k r)
go h k t@(Tip h' l)
| h == h' = Tip h $ FL.adjust f k l
| otherwise = t
go _ _ Nil = Nil
#if __GLASGOW_HASKELL__ >= 700
#endif
map :: (v1 -> v2) -> HashMap k v1 -> HashMap k v2
map f = go
where
go (Bin sm l r) = Bin sm (go l) (go r)
go (Tip h l) = Tip h (FL.map f' l)
go Nil = Nil
f' k v = (k, f v)
unionWith :: Eq k => (v -> v -> v) -> HashMap k v -> HashMap k v -> HashMap k v
unionWith f t1@(Bin sm1 l1 r1) t2@(Bin sm2 l2 r2)
| sm1 == sm2 = Bin sm1 (unionWith f l1 l2) (unionWith f r1 r2)
| shorter sm1 sm2 = union1
| shorter sm2 sm1 = union2
| otherwise = join sm1 t1 sm2 t2
where
union1 | nomatch sm2 sm1 = join sm1 t1 sm2 t2
| zero sm2 sm1 = Bin sm1 (unionWith f l1 t2) r1
| otherwise = Bin sm1 l1 (unionWith f r1 t2)
union2 | nomatch sm1 sm2 = join sm1 t1 sm2 t2
| zero sm1 sm2 = Bin sm2 (unionWith f t1 l2) r2
| otherwise = Bin sm2 l2 (unionWith f t1 r2)
unionWith f (Tip h l) t = insertCollidingWith (FL.unionWith f) h l t
unionWith f t (Tip h l) = insertCollidingWith (flip (FL.unionWith f)) h l t
unionWith _ Nil t = t
unionWith _ t Nil = t
#if __GLASGOW_HASKELL__ >= 700
#endif
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
#if __GLASGOW_HASKELL__ >= 700
#endif
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
#if __GLASGOW_HASKELL__ >= 700
#endif
foldr :: (v -> a -> a) -> a -> HashMap k v -> a
foldr f = foldrWithKey (const f)
foldl' :: (a -> v -> a) -> a -> HashMap k v -> a
foldl' f = foldlWithKey' (\ z _ v -> f z v)
foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a
foldlWithKey' f = go
where
go !z (Bin _ l r) = let z' = go z l
in z' `seq` go z' r
go z (Tip _ l) = FL.foldlWithKey' f z l
go z Nil = z
filterWithKey :: (k -> v -> Bool) -> HashMap k v -> HashMap k v
filterWithKey pred = go
where
go (Bin sm l r) = bin sm (go l) (go r)
go (Tip h l) = case FL.filterWithKey pred l of
Just l' -> Tip h l'
Nothing -> Nil
go Nil = Nil
filter :: (v -> Bool) -> HashMap k v -> HashMap k v
filter p = filterWithKey (\_ v -> p v)
fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v
fromList = List.foldl' (\ m (k, v) -> insert k v m) empty
fromListWith :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HashMap k v
fromListWith f = List.foldl' (\ m (k, v) -> insertWith f k v m) empty
keys :: HashMap k v -> [k]
keys = List.map fst . toList
elems :: HashMap k v -> [v]
elems = List.map snd . toList