Skip to content

Commit a8b7274

Browse files
committed
Introduce size-aware 'unsafeInsertInternal' function
1 parent 21d960a commit a8b7274

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

Data/HashMap/Base.hs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,10 @@ insert k0 v0 m0 = go h0 k0 v0 0 m0
527527
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
528528
{-# INLINABLE insert #-}
529529

530+
-- | /O(log n)/ Associate the specified value with the specified
531+
-- key in this map. If this map previously contained a mapping for
532+
-- the key, the old value is replaced. Returns a tuple containing the
533+
-- hashmap's change in size, and the hashmap after the insertion.
530534
insertInternal :: (Eq k, Hashable k) => k -> v -> HashMap k v -> (Int, HashMap k v)
531535
insertInternal k0 v0 m0 = go h0 k0 v0 0 m0
532536
where
@@ -602,6 +606,48 @@ unsafeInsert k0 v0 m0 = runST (go h0 k0 v0 0 m0)
602606
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
603607
{-# INLINABLE unsafeInsert #-}
604608

609+
-- | In-place update version of insert. Returns a tuple with the
610+
-- HashMap's change in size and the hashmap itself.
611+
unsafeInsertInternal :: (Eq k, Hashable k) => k -> v -> HashMap k v -> (Int, HashMap k v)
612+
unsafeInsertInternal k0 v0 m0 = runST (go h0 k0 v0 0 m0)
613+
where
614+
h0 = hash k0
615+
go !h !k x !_ Empty = return $! (1, Leaf h (L k x))
616+
go h k x s t@(Leaf hy l@(L ky y))
617+
| hy == h = if ky == k
618+
then if x `ptrEq` y
619+
then return (0, t)
620+
else return $! (0, Leaf h (L k x))
621+
else return $! (1, collision h l (L k x))
622+
| otherwise = do
623+
twoHm <- two s h k x hy ky y
624+
return $! (1, twoHm)
625+
go h k x s t@(BitmapIndexed b ary)
626+
| b .&. m == 0 = do
627+
ary' <- A.insertM ary i $! Leaf h (L k x)
628+
return $! (1, bitmapIndexedOrFull (b .|. m) ary')
629+
| otherwise = do
630+
st <- A.indexM ary i
631+
(sz, st') <- go h k x (s+bitsPerSubkey) st
632+
A.unsafeUpdateM ary i st'
633+
return (sz, t)
634+
where m = mask h s
635+
i = sparseIndex b m
636+
go h k x s t@(Full ary) = do
637+
st <- A.indexM ary i
638+
(sz, st') <- go h k x (s+bitsPerSubkey) st
639+
A.unsafeUpdateM ary i st'
640+
return (sz, t)
641+
where i = index h s
642+
go h k x s t@(Collision hy v)
643+
| h == hy =
644+
let !start = A.length v
645+
!newV = updateOrSnocWith const k x v
646+
!end = A.length newV
647+
in return $! (end - start, Collision h newV)
648+
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t)
649+
{-# INLINABLE unsafeInsertInternal #-}
650+
605651
-- | Create a map from two key-value pairs which hashes don't collide.
606652
two :: Shift -> Hash -> k -> v -> Hash -> k -> v -> ST s (HashMap k v)
607653
two = go

0 commit comments

Comments
 (0)