Skip to content

Commit b0644f9

Browse files
committed
Introduce ShiftedHash
1 parent 8a69068 commit b0644f9

File tree

1 file changed

+41
-47
lines changed

1 file changed

+41
-47
lines changed

Data/HashMap/Internal.hs

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -884,33 +884,19 @@ insertKeyExists !collPos0 !h0 !k0 x0 !m0 = go collPos0 h0 k0 x0 m0
884884
= Leaf h (L k x)
885885
go collPos shiftedHash k x (BitmapIndexed b ary) =
886886
let !st = A.index ary i
887-
!st' = go collPos (shiftHash shiftedHash) k x st
887+
!st' = go collPos (nextSH shiftedHash) k x st
888888
in BitmapIndexed b (A.update ary i st')
889-
where m = mask' shiftedHash
889+
where m = maskSH shiftedHash
890890
i = sparseIndex b m
891891
go collPos shiftedHash k x (Full ary) =
892892
let !st = A.index ary i
893-
!st' = go collPos (shiftHash shiftedHash) k x st
893+
!st' = go collPos (nextSH shiftedHash) k x st
894894
in Full (updateFullArray ary i st')
895-
where i = index' shiftedHash
895+
where i = indexSH shiftedHash
896896
go collPos _shiftedHash k x (Collision h v)
897897
| collPos >= 0 = Collision h (setAtPosition collPos k x v)
898898
| otherwise = Empty -- error "Internal error: go {collPos negative}"
899899
go _ _ _ _ Empty = Empty -- error "Internal error: go Empty"
900-
901-
-- Customized version of 'index' that doesn't require a 'Shift'.
902-
index' :: Hash -> Int
903-
index' w = fromIntegral $ w .&. subkeyMask
904-
{-# INLINE index' #-}
905-
906-
-- Customized version of 'mask' that doesn't require a 'Shift'.
907-
mask' :: Word -> Bitmap
908-
mask' w = 1 `unsafeShiftL` index' w
909-
{-# INLINE mask' #-}
910-
911-
shiftHash h = h `unsafeShiftR` bitsPerSubkey
912-
{-# INLINE shiftHash #-}
913-
914900
{-# NOINLINE insertKeyExists #-}
915901

916902
-- | Replace the ith Leaf with Leaf k v.
@@ -971,11 +957,11 @@ two s h1 k1 v1 = two' s h1 (Leaf h1 (L k1 v1))
971957
-- It is the caller's responsibility to ensure that both HashMap arguments are
972958
-- in WHNF.
973959
two' :: Shift -> Hash -> HashMap k v -> Hash -> HashMap k v -> ST s (HashMap k v)
974-
two' s h1 lc1 h2 lc2 = go (shiftHash h1 s) lc1 (shiftHash h2 s) lc2
960+
two' s h1 lc1 h2 lc2 = go (shiftHash s h1) lc1 (shiftHash s h2) lc2
975961
where
976962
go !sh1 t1 !sh2 t2
977963
| bp1 == bp2 = do
978-
st <- go (shiftHash sh1 bitsPerSubkey) t1 (shiftHash sh2 bitsPerSubkey) t2
964+
st <- go (nextSH sh1) t1 (nextSH sh2) t2
979965
ary <- A.singletonM st
980966
return $ BitmapIndexed bp1 ary
981967
| otherwise = do
@@ -984,21 +970,15 @@ two' s h1 lc1 h2 lc2 = go (shiftHash h1 s) lc1 (shiftHash h2 s) lc2
984970
ary <- A.unsafeFreeze mary
985971
return $ BitmapIndexed (bp1 .|. bp2) ary
986972
where
987-
!bp1@(W# bp1#) = mask' sh1
988-
!bp2@(W# bp2#) = mask' sh2
973+
!bp1@(W# bp1#) = maskSH sh1
974+
!bp2@(W# bp2#) = maskSH sh2
989975
idx2 = I# (bp1# `Exts.ltWord#` bp2#)
990976
-- This way of computing idx2 saves us a branch compared to the previous approach:
991977
--
992978
-- idx2 | index h1 s < index h2 s = 1
993979
-- | otherwise = 0
994980
--
995981
-- See https://github.com/haskell-unordered-containers/unordered-containers/issues/75#issuecomment-1128419337
996-
997-
shiftHash :: Hash -> Shift -> Word -- type ShiftedHash
998-
shiftHash h n = h `unsafeShiftR` n
999-
1000-
mask' :: Word -> Bitmap
1001-
mask' w = 1 `unsafeShiftL` fromIntegral (w .&. subkeyMask)
1002982
{-# INLINE two' #-} -- Really?!
1003983

1004984
-- | \(O(\log n)\) Associate the value with the key in this map. If
@@ -1188,11 +1168,11 @@ delete' h0 k0 m0 = go h0 k0 0 m0
11881168
deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v
11891169
deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 m0
11901170
where
1191-
go :: Int -> Word -> k -> HashMap k v -> HashMap k v
1171+
go :: Int -> ShiftedHash -> k -> HashMap k v -> HashMap k v
11921172
go !_collPos !_shiftedHash !_k (Leaf _ _) = Empty
11931173
go collPos shiftedHash k (BitmapIndexed b ary) =
11941174
let !st = A.index ary i
1195-
!st' = go collPos (shiftHash shiftedHash) k st
1175+
!st' = go collPos (nextSH shiftedHash) k st
11961176
in case st' of
11971177
Empty | A.length ary == 1 -> Empty
11981178
| A.length ary == 2 ->
@@ -1205,39 +1185,25 @@ deleteKeyExists !collPos0 !h0 !k0 !m0 = go collPos0 h0 k0 m0
12051185
bIndexed = BitmapIndexed (b .&. complement m) (A.delete ary i)
12061186
l | isLeafOrCollision l && A.length ary == 1 -> l
12071187
_ -> BitmapIndexed b (A.update ary i st')
1208-
where m = mask' shiftedHash
1188+
where m = maskSH shiftedHash
12091189
i = sparseIndex b m
12101190
go collPos shiftedHash k (Full ary) =
12111191
let !st = A.index ary i
1212-
!st' = go collPos (shiftHash shiftedHash) k st
1192+
!st' = go collPos (nextSH shiftedHash) k st
12131193
in case st' of
12141194
Empty ->
12151195
let ary' = A.delete ary i
12161196
bm = fullBitmap .&. complement (1 `unsafeShiftL` i)
12171197
in BitmapIndexed bm ary'
12181198
_ -> Full (A.update ary i st')
1219-
where i = index' shiftedHash
1199+
where i = indexSH shiftedHash
12201200
go collPos _shiftedHash _k (Collision h v)
12211201
| A.length v == 2
12221202
= if collPos == 0
12231203
then Leaf h (A.index v 1)
12241204
else Leaf h (A.index v 0)
12251205
| otherwise = Collision h (A.delete v collPos)
12261206
go !_ !_ !_ Empty = Empty -- error "Internal error: deleteKeyExists empty"
1227-
1228-
-- Customized version of 'index' that doesn't require a 'Shift'.
1229-
index' :: Hash -> Int
1230-
index' w = fromIntegral $ w .&. subkeyMask
1231-
{-# INLINE index' #-}
1232-
1233-
-- Customized version of 'mask' that doesn't require a 'Shift'.
1234-
mask' :: Word -> Bitmap
1235-
mask' w = 1 `unsafeShiftL` index' w
1236-
{-# INLINE mask' #-}
1237-
1238-
shiftHash h = h `unsafeShiftR` bitsPerSubkey
1239-
{-# INLINE shiftHash #-}
1240-
12411207
{-# NOINLINE deleteKeyExists #-}
12421208

12431209
-- | \(O(\log n)\) Adjust the value tied to a given key in this map only
@@ -2512,6 +2478,34 @@ nextShift :: Shift -> Shift
25122478
nextShift s = s + bitsPerSubkey
25132479
{-# INLINE nextShift #-}
25142480

2481+
------------------------------------------------------------------------
2482+
-- ShiftedHash
2483+
2484+
-- | Sometimes it's more efficient to right-shift the hashes directly instead
2485+
-- of keeping track of an additional 'Shift' value.
2486+
type ShiftedHash = Hash
2487+
2488+
-- | Construct a 'ShiftedHash' from a 'Shift' and a 'Hash'.
2489+
shiftHash :: Shift -> Hash -> ShiftedHash
2490+
shiftHash s h = h `unsafeShiftR` s
2491+
{-# INLINE shiftHash #-}
2492+
2493+
-- | Update a 'ShiftedHash' for the next level of the tree.
2494+
nextSH :: ShiftedHash -> ShiftedHash
2495+
nextSH sh = sh `unsafeShiftR` bitsPerSubkey
2496+
{-# INLINE nextSH #-}
2497+
2498+
-- | Version of 'index' for use with @'ShiftedHash'es@.
2499+
indexSH :: ShiftedHash -> Int
2500+
indexSH sh = fromIntegral $ sh .&. subkeyMask
2501+
{-# INLINE indexSH #-}
2502+
2503+
-- | Version of 'mask' for use with @'ShiftedHash'es@.
2504+
maskSH :: ShiftedHash -> Bitmap
2505+
maskSH sh = 1 `unsafeShiftL` indexSH sh
2506+
{-# INLINE maskSH #-}
2507+
2508+
25152509
------------------------------------------------------------------------
25162510
-- Pointer equality
25172511

0 commit comments

Comments
 (0)