Skip to content

Commit 8c20f7a

Browse files
authored
Tweak insertKeyExists and deleteKeyExists (#458)
1 parent f4bf21d commit 8c20f7a

File tree

1 file changed

+50
-29
lines changed

1 file changed

+50
-29
lines changed

Data/HashMap/Internal.hs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -877,31 +877,41 @@ insertNewKey !h0 !k0 x0 !m0 = go h0 k0 x0 0 m0
877877
--
878878
-- It is only valid to call this when the key exists in the map and you know the
879879
-- hash collision position if there was one. This information can be obtained
880-
-- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos
880+
-- from 'lookupRecordCollision'. If there is no collision, pass (-1) as collPos
881881
-- (first argument).
882-
--
883-
-- We can skip the key equality check on a Leaf because we know the leaf must be
884-
-- for this key.
885882
insertKeyExists :: Int -> Hash -> k -> v -> HashMap k v -> HashMap k v
886-
insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 0 m0
883+
insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 m0
887884
where
888-
go !_collPos !h !k x !_s (Leaf _hy _kx)
885+
go !_collPos !_shiftedHash !k x (Leaf h _kx)
889886
= Leaf h (L k x)
890-
go collPos h k x s (BitmapIndexed b ary) =
887+
go collPos shiftedHash k x (BitmapIndexed b ary) =
891888
let !st = A.index ary i
892-
!st' = go collPos h k x (nextShift s) st
889+
!st' = go collPos (shiftHash shiftedHash) k x st
893890
in BitmapIndexed b (A.update ary i st')
894-
where m = mask h s
891+
where m = mask' shiftedHash
895892
i = sparseIndex b m
896-
go collPos h k x s (Full ary) =
893+
go collPos shiftedHash k x (Full ary) =
897894
let !st = A.index ary i
898-
!st' = go collPos h k x (nextShift s) st
895+
!st' = go collPos (shiftHash shiftedHash) k x st
899896
in Full (update32 ary i st')
900-
where i = index h s
901-
go collPos h k x _s (Collision _hy v)
897+
where i = index' shiftedHash
898+
go collPos _shiftedHash k x (Collision h v)
902899
| collPos >= 0 = Collision h (setAtPosition collPos k x v)
903900
| otherwise = Empty -- error "Internal error: go {collPos negative}"
904-
go _ _ _ _ _ Empty = Empty -- error "Internal error: go Empty"
901+
go _ _ _ _ Empty = Empty -- error "Internal error: go Empty"
902+
903+
-- Customized version of 'index' that doesn't require a 'Shift'.
904+
index' :: Hash -> Int
905+
index' w = fromIntegral $ w .&. subkeyMask
906+
{-# INLINE index' #-}
907+
908+
-- Customized version of 'mask' that doesn't require a 'Shift'.
909+
mask' :: Word -> Bitmap
910+
mask' w = 1 `unsafeShiftL` index' w
911+
{-# INLINE mask' #-}
912+
913+
shiftHash h = h `unsafeShiftR` bitsPerSubkey
914+
{-# INLINE shiftHash #-}
905915

906916
{-# NOINLINE insertKeyExists #-}
907917

@@ -1159,18 +1169,15 @@ delete' h0 k0 m0 = go h0 k0 0 m0
11591169
--
11601170
-- It is only valid to call this when the key exists in the map and you know the
11611171
-- hash collision position if there was one. This information can be obtained
1162-
-- from 'lookupRecordCollision'. If there is no collision pass (-1) as collPos.
1163-
--
1164-
-- We can skip:
1165-
-- - the key equality check on the leaf, if we reach a leaf it must be the key
1172+
-- from 'lookupRecordCollision'. If there is no collision, pass (-1) as collPos.
11661173
deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v
1167-
deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 0 m0
1174+
deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 m0
11681175
where
1169-
go :: Int -> Hash -> k -> Int -> HashMap k v -> HashMap k v
1170-
go !_collPos !_h !_k !_s (Leaf _ _) = Empty
1171-
go collPos h k s (BitmapIndexed b ary) =
1176+
go :: Int -> Word -> k -> HashMap k v -> HashMap k v
1177+
go !_collPos !_shiftedHash !_k (Leaf _ _) = Empty
1178+
go collPos shiftedHash k (BitmapIndexed b ary) =
11721179
let !st = A.index ary i
1173-
!st' = go collPos h k (nextShift s) st
1180+
!st' = go collPos (shiftHash shiftedHash) k st
11741181
in case st' of
11751182
Empty | A.length ary == 1 -> Empty
11761183
| A.length ary == 2 ->
@@ -1183,25 +1190,39 @@ deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 0 m0
11831190
bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)
11841191
l | isLeafOrCollision l && A.length ary == 1 -> l
11851192
_ -> BitmapIndexed b (A.update ary i st')
1186-
where m = mask h s
1193+
where m = mask' shiftedHash
11871194
i = sparseIndex b m
1188-
go collPos h k s (Full ary) =
1195+
go collPos shiftedHash k (Full ary) =
11891196
let !st = A.index ary i
1190-
!st' = go collPos h k (nextShift s) st
1197+
!st' = go collPos (shiftHash shiftedHash) k st
11911198
in case st' of
11921199
Empty ->
11931200
let ary' = A.delete ary i
11941201
bm = fullBitmap .&. complement (1 `unsafeShiftL` i)
11951202
in BitmapIndexed bm ary'
11961203
_ -> Full (A.update ary i st')
1197-
where i = index h s
1198-
go collPos h _ _ (Collision _hy v)
1204+
where i = index' shiftedHash
1205+
go collPos _shiftedHash _k (Collision h v)
11991206
| A.length v == 2
12001207
= if collPos == 0
12011208
then Leaf h (A.index v 1)
12021209
else Leaf h (A.index v 0)
12031210
| otherwise = Collision h (A.delete v collPos)
1204-
go !_ !_ !_ !_ Empty = Empty -- error "Internal error: deleteKeyExists empty"
1211+
go !_ !_ !_ Empty = Empty -- error "Internal error: deleteKeyExists empty"
1212+
1213+
-- Customized version of 'index' that doesn't require a 'Shift'.
1214+
index' :: Hash -> Int
1215+
index' w = fromIntegral $ w .&. subkeyMask
1216+
{-# INLINE index' #-}
1217+
1218+
-- Customized version of 'mask' that doesn't require a 'Shift'.
1219+
mask' :: Word -> Bitmap
1220+
mask' w = 1 `unsafeShiftL` index' w
1221+
{-# INLINE mask' #-}
1222+
1223+
shiftHash h = h `unsafeShiftR` bitsPerSubkey
1224+
{-# INLINE shiftHash #-}
1225+
12051226
{-# NOINLINE deleteKeyExists #-}
12061227

12071228
-- | \(O(\log n)\) Adjust the value tied to a given key in this map only

0 commit comments

Comments
 (0)