From 7f017fe07ebe2184193d43bd9c1a39fa7e63959e Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Thu, 12 May 2022 00:06:06 +0200 Subject: [PATCH 1/3] Try something else for avoiding allocations on no-ops --- Data/HashMap/Internal.hs | 50 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/Data/HashMap/Internal.hs b/Data/HashMap/Internal.hs index 79c6babb..2a9ababf 100644 --- a/Data/HashMap/Internal.hs +++ b/Data/HashMap/Internal.hs @@ -4,6 +4,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE PatternGuards #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} @@ -803,37 +804,38 @@ insert k v m = insert' (hash k) k v m {-# INLINABLE insert #-} insert' :: Eq k => Hash -> k -> v -> HashMap k v -> HashMap k v -insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0 +insert' h0 k0 v0 m0 = + case go h0 k0 v0 0 m0 of + NoChange -> m0 + Changed m -> m where - go !h !k x !_ Empty = Leaf h (L k x) + go !h !k x !_ Empty = Changed (Leaf h (L k x)) go h k x s t@(Leaf hy l@(L ky y)) | hy == h = if ky == k then if x `ptrEq` y - then t - else Leaf h (L k x) - else collision h l (L k x) - | otherwise = runST (two s h k x hy t) - go h k x s t@(BitmapIndexed b ary) + then NoChange + else Changed (Leaf h (L k x)) + else Changed $ collision h l (L k x) + | otherwise = Changed $ runST (two s h k x hy t) + go h k x s (BitmapIndexed b ary) | b .&. m == 0 = let !ary' = A.insert ary i $! Leaf h (L k x) - in bitmapIndexedOrFull (b .|. m) ary' + in Changed $ bitmapIndexedOrFull (b .|. m) ary' | otherwise = let !st = A.index ary i - !st' = go h k x (nextShift s) st - in if st' `ptrEq` st - then t - else BitmapIndexed b (A.update ary i st') + in case go h k x (nextShift s) st of + NoChange -> NoChange + Changed st' -> Changed $ BitmapIndexed b (A.update ary i st') where m = mask h s i = sparseIndex b m - go h k x s t@(Full ary) = + go h k x s (Full ary) = let !st = A.index ary i - !st' = go h k x (nextShift s) st - in if st' `ptrEq` st - then t - else Full (update32 ary i st') + in case go h k x (nextShift s) st of + NoChange -> NoChange + Changed st' -> Changed $ Full (update32 ary i st') where i = index h s go h k x s t@(Collision hy v) - | h == hy = Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v) + | h == hy = Changed $ Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v) -- TODO: Improve | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t) {-# INLINABLE insert' #-} @@ -2502,6 +2504,18 @@ ptrEq :: a -> a -> Bool ptrEq x y = Exts.isTrue# (Exts.reallyUnsafePtrEquality# x y ==# 1#) {-# INLINE ptrEq #-} +type Change a = (# (# #) | a #) + +pattern NoChange :: Change a +pattern NoChange <- (# (# #) | #) + where NoChange = (# (# #) | #) + +pattern Changed :: a -> Change a +pattern Changed a <- (# | a #) where + Changed a = (# | a #) + +{-# COMPLETE NoChange, Changed #-} + ------------------------------------------------------------------------ -- IsList instance instance (Eq k, Hashable k) => Exts.IsList (HashMap k v) where From 2e0014e7be62071f478f995060910c95cf028218 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Thu, 12 May 2022 00:19:59 +0200 Subject: [PATCH 2/3] Avoid re-allocating NoChanges --- Data/HashMap/Internal.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Data/HashMap/Internal.hs b/Data/HashMap/Internal.hs index 2a9ababf..69795650 100644 --- a/Data/HashMap/Internal.hs +++ b/Data/HashMap/Internal.hs @@ -824,15 +824,15 @@ insert' h0 k0 v0 m0 = | otherwise = let !st = A.index ary i in case go h k x (nextShift s) st of - NoChange -> NoChange Changed st' -> Changed $ BitmapIndexed b (A.update ary i st') + noChange -> noChange where m = mask h s i = sparseIndex b m go h k x s (Full ary) = let !st = A.index ary i in case go h k x (nextShift s) st of - NoChange -> NoChange Changed st' -> Changed $ Full (update32 ary i st') + noChange -> noChange where i = index h s go h k x s t@(Collision hy v) | h == hy = Changed $ Collision h (updateOrSnocWith (\a _ -> (# a #)) k x v) -- TODO: Improve From 2cc5d07078c339b7f14fd3e13c32c958ff541f36 Mon Sep 17 00:00:00 2001 From: Simon Jakobi Date: Thu, 12 May 2022 00:26:53 +0200 Subject: [PATCH 3/3] Changed is strict now --- Data/HashMap/Internal.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Data/HashMap/Internal.hs b/Data/HashMap/Internal.hs index 69795650..10b37bd0 100644 --- a/Data/HashMap/Internal.hs +++ b/Data/HashMap/Internal.hs @@ -2512,7 +2512,7 @@ pattern NoChange <- (# (# #) | #) pattern Changed :: a -> Change a pattern Changed a <- (# | a #) where - Changed a = (# | a #) + Changed !a = (# | a #) {-# COMPLETE NoChange, Changed #-}