@@ -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.
973959two' :: 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
11881168deleteKeyExists :: Int -> Hash -> k -> HashMap k v -> HashMap k v
11891169deleteKeyExists ! 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
25122478nextShift 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