Skip to content

Commit 91307ed

Browse files
committed
Introduce size-aware 'unsafeInsertWithInternal' function
1 parent 9fd024e commit 91307ed

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

Data/HashMap/Base.hs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,10 @@ insertWith f k0 v0 m0 = go h0 k0 v0 0 m0
712712
-- | /O(log n)/ Associate the value with the key in this map. If
713713
-- this map previously contained a mapping for the key, the old value
714714
-- is replaced by the result of applying the given function to the new
715-
-- and old value. Example:
715+
-- and old value. Returns a tuple where the first component is the
716+
-- difference in size between the old and new hashmaps, and the second
717+
-- is the new hashmap.
718+
-- Example:
716719
--
717720
-- > insertWithInternal f k v map
718721
-- > where f new old = new + old
@@ -789,6 +792,48 @@ unsafeInsertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
789792
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
790793
{-# INLINABLE unsafeInsertWith #-}
791794

795+
-- | In-place update version of insertWithInternal
796+
unsafeInsertWithInternal :: forall k v. (Eq k, Hashable k)
797+
=> (v -> v -> v) -> k -> v -> HashMap k v
798+
-> (Int, HashMap k v)
799+
unsafeInsertWithInternal f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
800+
where
801+
h0 = hash k0
802+
go :: Hash -> k -> v -> Shift -> HashMap k v -> ST s (Int, HashMap k v)
803+
go !h !k x !_ Empty = return $! (1, Leaf h (L k x))
804+
go h k x s (Leaf hy l@(L ky y))
805+
| hy == h = if ky == k
806+
then return $! (0, Leaf h (L k (f x y)))
807+
else return $! (1, collision h l (L k x))
808+
| otherwise = do
809+
twoHm <- two s h k x hy ky y
810+
return $! (1, twoHm)
811+
go h k x s t@(BitmapIndexed b ary)
812+
| b .&. m == 0 = do
813+
ary' <- A.insertM ary i $! Leaf h (L k x)
814+
return $! (1, bitmapIndexedOrFull (b .|. m) ary')
815+
| otherwise = do
816+
st <- A.indexM ary i
817+
(sz, st') <- go h k x (s+bitsPerSubkey) st
818+
A.unsafeUpdateM ary i st'
819+
return (sz, t)
820+
where m = mask h s
821+
i = sparseIndex b m
822+
go h k x s t@(Full ary) = do
823+
st <- A.indexM ary i
824+
(sz, st') <- go h k x (s+bitsPerSubkey) st
825+
A.unsafeUpdateM ary i st'
826+
return (sz, t)
827+
where i = index h s
828+
go h k x s t@(Collision hy v)
829+
| h == hy =
830+
let !start = A.length v
831+
!newV = updateOrSnocWith const k x v
832+
!end = A.length newV
833+
in return $! (end - start, Collision h newV)
834+
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
835+
{-# INLINABLE unsafeInsertWithInternal #-}
836+
792837
-- | /O(log n)/ Remove the mapping for the specified key from this map
793838
-- if present.
794839
delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v

0 commit comments

Comments
 (0)