Skip to content

Commit 999c489

Browse files
committed
Introduce size-aware 'deleteInternal' function
1 parent 91307ed commit 999c489

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

Data/HashMap/Base.hs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{-# LANGUAGE ScopedTypeVariables #-}
33
{-# LANGUAGE PatternGuards #-}
44
{-# LANGUAGE RoleAnnotations #-}
5+
{-# LANGUAGE TupleSections #-}
56
{-# LANGUAGE TypeFamilies #-}
67
{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}
78

@@ -889,6 +890,62 @@ delete k0 m0 = go h0 k0 0 m0
889890
| otherwise = t
890891
{-# INLINABLE delete #-}
891892

893+
-- | /O(log n)/ Remove the mapping for the specified key from this map
894+
-- if present. Returns a tuple with the hashmap's change in size and the
895+
-- hashmap after the deletion.
896+
deleteInternal :: (Eq k, Hashable k) => k -> HashMap k v -> (Int, HashMap k v)
897+
deleteInternal k0 m0 = go h0 k0 0 m0
898+
where
899+
h0 = hash k0
900+
go !_ !_ !_ Empty = (0, Empty)
901+
go h k _ t@(Leaf hy (L ky _))
902+
| hy == h && ky == k = (-1, Empty)
903+
| otherwise = (0, t)
904+
go h k s t@(BitmapIndexed b ary)
905+
| b .&. m == 0 = (0, t)
906+
| otherwise =
907+
let !st = A.index ary i
908+
(!sz, !st') = go h k (s+bitsPerSubkey) st
909+
in (sz,) (if st' `ptrEq` st
910+
then t
911+
else case st' of
912+
Empty | A.length ary == 1 -> Empty
913+
| A.length ary == 2 ->
914+
case (i, A.index ary 0, A.index ary 1) of
915+
(0, _, l) | isLeafOrCollision l -> l
916+
(1, l, _) | isLeafOrCollision l -> l
917+
_ -> bIndexed
918+
| otherwise -> bIndexed
919+
where
920+
bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)
921+
l | isLeafOrCollision l && A.length ary == 1 -> l
922+
_ -> BitmapIndexed b (A.update ary i st'))
923+
where m = mask h s
924+
i = sparseIndex b m
925+
go h k s t@(Full ary) =
926+
let !st = A.index ary i
927+
(!sz, !st') = go h k (s+bitsPerSubkey) st
928+
in (sz,) (if st' `ptrEq` st
929+
then t
930+
else case st' of
931+
Empty ->
932+
let ary' = A.delete ary i
933+
bm = fullNodeMask .&. complement (1 `unsafeShiftL` i)
934+
in BitmapIndexed bm ary'
935+
_ -> Full (A.update ary i st'))
936+
where i = index h s
937+
go h k _ t@(Collision hy v)
938+
| h == hy = case indexOf k v of
939+
Just i
940+
| A.length v == 2 ->
941+
(-1,) (if i == 0
942+
then Leaf h (A.index v 1)
943+
else Leaf h (A.index v 0))
944+
| otherwise -> (-1, Collision h (A.delete v i))
945+
Nothing -> (0, t)
946+
| otherwise = (0, t)
947+
{-# INLINABLE deleteInternal #-}
948+
892949
-- | /O(log n)/ Adjust the value tied to a given key in this map only
893950
-- if it is present. Otherwise, leave the map alone.
894951
adjust :: (Eq k, Hashable k) => (v -> v) -> k -> HashMap k v -> HashMap k v

0 commit comments

Comments
 (0)