@@ -134,6 +134,7 @@ module Data.HashMap.Internal
134134 , equalKeys1
135135 , lookupRecordCollision
136136 , LookupRes (.. )
137+ , lookupResToMaybe
137138 , insert'
138139 , delete'
139140 , lookup'
@@ -655,6 +656,11 @@ lookup' h k m = case lookupRecordCollision# h k m of
655656-- If a collision did not occur then it will have the Int value (-1).
656657data LookupRes a = Absent | Present a ! Int
657658
659+ lookupResToMaybe :: LookupRes a -> Maybe a
660+ lookupResToMaybe Absent = Nothing
661+ lookupResToMaybe (Present x _) = Just x
662+ {-# INLINE lookupResToMaybe #-}
663+
658664-- Internal helper for lookup. This version takes the precomputed hash so
659665-- that functions that make multiple calls to lookup and related functions
660666-- (insert, delete) only need to calculate the hash once.
@@ -1265,11 +1271,19 @@ update f = alter (>>= f)
12651271-- 'lookup' k ('alter' f k m) = f ('lookup' k m)
12661272-- @
12671273alter :: (Eq k , Hashable k ) => (Maybe v -> Maybe v ) -> k -> HashMap k v -> HashMap k v
1268- -- TODO(m-renaud): Consider using specialized insert and delete for alter.
12691274alter f k m =
1270- case f (lookup k m) of
1271- Nothing -> delete k m
1272- Just v -> insert k v m
1275+ let ! h = hash k
1276+ ! lookupRes = lookupRecordCollision h k m
1277+ in case f (lookupResToMaybe lookupRes) of
1278+ Nothing -> case lookupRes of
1279+ Absent -> m
1280+ Present _ collPos -> deleteKeyExists collPos h k m
1281+ Just v' -> case lookupRes of
1282+ Absent -> insertNewKey h k v' m
1283+ Present v collPos ->
1284+ if v `ptrEq` v'
1285+ then m
1286+ else insertKeyExists collPos h k v' m
12731287{-# INLINABLE alter #-}
12741288
12751289-- | \(O(\log n)\) The expression @('alterF' f k map)@ alters the value @x@ at
0 commit comments