@@ -107,6 +107,8 @@ module Data.HashMap.Base
107
107
, insertModifying
108
108
, ptrEq
109
109
, adjust #
110
+ , unionWithKey #
111
+ , unsafeInsertWith
110
112
) where
111
113
112
114
#if __GLASGOW_HASKELL__ < 710
@@ -650,7 +652,7 @@ insert' h0 k0 v0 m0 = go h0 k0 v0 0 m0
650
652
else Full (update16 ary i st')
651
653
where i = index h s
652
654
go h k x s t@ (Collision hy v)
653
- | h == hy = Collision h (updateOrSnocWith const k x v)
655
+ | h == hy = Collision h (updateOrSnocWith ( \ v1 _ -> ( # v1 # )) k x v)
654
656
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A. singleton t)
655
657
{-# INLINABLE insert' #-}
656
658
@@ -773,7 +775,7 @@ unsafeInsert k0 v0 m0 = runST (go h0 k0 v0 0 m0)
773
775
return t
774
776
where i = index h s
775
777
go h k x s t@ (Collision hy v)
776
- | h == hy = return $! Collision h (updateOrSnocWith const k x v)
778
+ | h == hy = return $! Collision h (updateOrSnocWith ( \ v1 _ -> ( # v1 # )) k x v)
777
779
| otherwise = go h k x s $ BitmapIndexed (mask hy s) (A. singleton t)
778
780
{-# INLINABLE unsafeInsert #-}
779
781
@@ -882,7 +884,7 @@ insertModifyingArr x f k0 ary0 = go k0 ary0 0 (A.length ary0)
882
884
883
885
-- | In-place update version of insertWith
884
886
unsafeInsertWith :: forall k v . (Eq k , Hashable k )
885
- => (v -> v -> v ) -> k -> v -> HashMap k v
887
+ => (v -> v -> ( # v # ) ) -> k -> v -> HashMap k v
886
888
-> HashMap k v
887
889
unsafeInsertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
888
890
where
@@ -891,7 +893,7 @@ unsafeInsertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
891
893
go ! h ! k x ! _ Empty = return $! Leaf h (L k x)
892
894
go h k x s (Leaf hy l@ (L ky y))
893
895
| hy == h = if ky == k
894
- then return $! Leaf h (L k (f x y) )
896
+ then case f x y of ( # v # ) -> return $! Leaf h (L k v )
895
897
else return $! collision h l (L k x)
896
898
| otherwise = two s h k x hy ky y
897
899
go h k x s t@ (BitmapIndexed b ary)
@@ -1256,6 +1258,9 @@ unionWith f = unionWithKey (const f)
1256
1258
-- result.
1257
1259
unionWithKey :: (Eq k , Hashable k ) => (k -> v -> v -> v ) -> HashMap k v -> HashMap k v
1258
1260
-> HashMap k v
1261
+ unionWithKey f m = unionWithKey# (\ k v1 v2 -> (# f k v1 v2 # )) m
1262
+ {-# INLINE unionWithKey #-}
1263
+ {-
1259
1264
unionWithKey f = go 0
1260
1265
where
1261
1266
-- empty vs. anything
@@ -1337,6 +1342,93 @@ unionWithKey f = go 0
1337
1342
m1 = mask h1 s
1338
1343
m2 = mask h2 s
1339
1344
{- # INLINE unionWithKey #-}
1345
+ -}
1346
+
1347
+
1348
+ unionWithKey# :: (Eq k , Hashable k ) => (k -> v -> v -> (# v # )) -> HashMap k v -> HashMap k v
1349
+ -> HashMap k v
1350
+ unionWithKey# f = go 0
1351
+ where
1352
+ -- empty vs. anything
1353
+ go ! _ t1 Empty = t1
1354
+ go _ Empty t2 = t2
1355
+ -- leaf vs. leaf
1356
+ go s t1@ (Leaf h1 l1@ (L k1 v1)) t2@ (Leaf h2 l2@ (L k2 v2))
1357
+ | h1 == h2 = if k1 == k2
1358
+ then case f k1 v1 v2 of (# v # ) -> Leaf h1 (L k1 v)
1359
+ else collision h1 l1 l2
1360
+ | otherwise = goDifferentHash s h1 h2 t1 t2
1361
+ go s t1@ (Leaf h1 (L k1 v1)) t2@ (Collision h2 ls2)
1362
+ | h1 == h2 = Collision h1 (updateOrSnocWithKey f k1 v1 ls2)
1363
+ | otherwise = goDifferentHash s h1 h2 t1 t2
1364
+ go s t1@ (Collision h1 ls1) t2@ (Leaf h2 (L k2 v2))
1365
+ | h1 == h2 = Collision h1 (updateOrSnocWithKey (\ q w x -> f q x w) k2 v2 ls1)
1366
+ | otherwise = goDifferentHash s h1 h2 t1 t2
1367
+ go s t1@ (Collision h1 ls1) t2@ (Collision h2 ls2)
1368
+ | h1 == h2 = Collision h1 (updateOrConcatWithKey f ls1 ls2)
1369
+ | otherwise = goDifferentHash s h1 h2 t1 t2
1370
+ -- branch vs. branch
1371
+ go s (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =
1372
+ let b' = b1 .|. b2
1373
+ ary' = unionArrayBy (go (s+ bitsPerSubkey)) b1 b2 ary1 ary2
1374
+ in bitmapIndexedOrFull b' ary'
1375
+ go s (BitmapIndexed b1 ary1) (Full ary2) =
1376
+ let ary' = unionArrayBy (go (s+ bitsPerSubkey)) b1 fullNodeMask ary1 ary2
1377
+ in Full ary'
1378
+ go s (Full ary1) (BitmapIndexed b2 ary2) =
1379
+ let ary' = unionArrayBy (go (s+ bitsPerSubkey)) fullNodeMask b2 ary1 ary2
1380
+ in Full ary'
1381
+ go s (Full ary1) (Full ary2) =
1382
+ let ary' = unionArrayBy (go (s+ bitsPerSubkey)) fullNodeMask fullNodeMask
1383
+ ary1 ary2
1384
+ in Full ary'
1385
+ -- leaf vs. branch
1386
+ go s (BitmapIndexed b1 ary1) t2
1387
+ | b1 .&. m2 == 0 = let ary' = A. insert ary1 i t2
1388
+ b' = b1 .|. m2
1389
+ in bitmapIndexedOrFull b' ary'
1390
+ | otherwise = let ary' = A. updateWith' ary1 i $ \ st1 ->
1391
+ go (s+ bitsPerSubkey) st1 t2
1392
+ in BitmapIndexed b1 ary'
1393
+ where
1394
+ h2 = leafHashCode t2
1395
+ m2 = mask h2 s
1396
+ i = sparseIndex b1 m2
1397
+ go s t1 (BitmapIndexed b2 ary2)
1398
+ | b2 .&. m1 == 0 = let ary' = A. insert ary2 i $! t1
1399
+ b' = b2 .|. m1
1400
+ in bitmapIndexedOrFull b' ary'
1401
+ | otherwise = let ary' = A. updateWith' ary2 i $ \ st2 ->
1402
+ go (s+ bitsPerSubkey) t1 st2
1403
+ in BitmapIndexed b2 ary'
1404
+ where
1405
+ h1 = leafHashCode t1
1406
+ m1 = mask h1 s
1407
+ i = sparseIndex b2 m1
1408
+ go s (Full ary1) t2 =
1409
+ let h2 = leafHashCode t2
1410
+ i = index h2 s
1411
+ ary' = update16With' ary1 i $ \ st1 -> go (s+ bitsPerSubkey) st1 t2
1412
+ in Full ary'
1413
+ go s t1 (Full ary2) =
1414
+ let h1 = leafHashCode t1
1415
+ i = index h1 s
1416
+ ary' = update16With' ary2 i $ \ st2 -> go (s+ bitsPerSubkey) t1 st2
1417
+ in Full ary'
1418
+
1419
+ leafHashCode (Leaf h _) = h
1420
+ leafHashCode (Collision h _) = h
1421
+ leafHashCode _ = error " leafHashCode"
1422
+
1423
+ goDifferentHash s h1 h2 t1 t2
1424
+ | m1 == m2 = BitmapIndexed m1 (A. singleton $! go (s+ bitsPerSubkey) t1 t2)
1425
+ | m1 < m2 = BitmapIndexed (m1 .|. m2) (A. pair t1 t2)
1426
+ | otherwise = BitmapIndexed (m1 .|. m2) (A. pair t2 t1)
1427
+ where
1428
+ m1 = mask h1 s
1429
+ m2 = mask h2 s
1430
+ {-# INLINE unionWithKey# #-}
1431
+
1340
1432
1341
1433
-- | Strict in the result of @f@.
1342
1434
unionArrayBy :: (a -> a -> a ) -> Bitmap -> Bitmap -> A. Array a -> A. Array a
@@ -1667,7 +1759,7 @@ fromList = L.foldl' (\ m (k, v) -> unsafeInsert k v m) empty
1667
1759
-- | /O(n*log n)/ Construct a map from a list of elements. Uses
1668
1760
-- the provided function to merge duplicate entries.
1669
1761
fromListWith :: (Eq k , Hashable k ) => (v -> v -> v ) -> [(k , v )] -> HashMap k v
1670
- fromListWith f = L. foldl' (\ m (k, v) -> unsafeInsertWith f k v m) empty
1762
+ fromListWith f = L. foldl' (\ m (k, v) -> unsafeInsertWith ( \ x y -> ( # f x y # )) k v m) empty
1671
1763
{-# INLINE fromListWith #-}
1672
1764
1673
1765
------------------------------------------------------------------------
@@ -1719,12 +1811,12 @@ updateWith# f k0 ary0 = go k0 ary0 0 (A.length ary0)
1719
1811
| otherwise -> go k ary (i+ 1 ) n
1720
1812
{-# INLINABLE updateWith# #-}
1721
1813
1722
- updateOrSnocWith :: Eq k => (v -> v -> v ) -> k -> v -> A. Array (Leaf k v )
1814
+ updateOrSnocWith :: Eq k => (v -> v -> ( # v # ) ) -> k -> v -> A. Array (Leaf k v )
1723
1815
-> A. Array (Leaf k v )
1724
1816
updateOrSnocWith f = updateOrSnocWithKey (const f)
1725
1817
{-# INLINABLE updateOrSnocWith #-}
1726
1818
1727
- updateOrSnocWithKey :: Eq k => (k -> v -> v -> v ) -> k -> v -> A. Array (Leaf k v )
1819
+ updateOrSnocWithKey :: Eq k => (k -> v -> v -> ( # v # ) ) -> k -> v -> A. Array (Leaf k v )
1728
1820
-> A. Array (Leaf k v )
1729
1821
updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A. length ary0)
1730
1822
where
@@ -1736,15 +1828,15 @@ updateOrSnocWithKey f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)
1736
1828
A. write mary n (L k v)
1737
1829
return mary
1738
1830
| otherwise = case A. index ary i of
1739
- (L kx y) | k == kx -> A. update ary i (L k (f k v y) )
1831
+ (L kx y) | k == kx -> case f k v y of ( # y' # ) -> A. update ary i (L k y' )
1740
1832
| otherwise -> go k v ary (i+ 1 ) n
1741
1833
{-# INLINABLE updateOrSnocWithKey #-}
1742
1834
1743
- updateOrConcatWith :: Eq k => (v -> v -> v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v )
1835
+ updateOrConcatWith :: Eq k => (v -> v -> ( # v # ) ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v )
1744
1836
updateOrConcatWith f = updateOrConcatWithKey (const f)
1745
1837
{-# INLINABLE updateOrConcatWith #-}
1746
1838
1747
- updateOrConcatWithKey :: Eq k => (k -> v -> v -> v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v )
1839
+ updateOrConcatWithKey :: Eq k => (k -> v -> v -> ( # v # ) ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v ) -> A. Array (Leaf k v )
1748
1840
updateOrConcatWithKey f ary1 ary2 = A. run $ do
1749
1841
-- first: look up the position of each element of ary2 in ary1
1750
1842
let indices = A. map (\ (L k _) -> indexOf k ary1) ary2
@@ -1763,7 +1855,7 @@ updateOrConcatWithKey f ary1 ary2 = A.run $ do
1763
1855
Just i1 -> do -- key occurs in both arrays, store combination in position i1
1764
1856
L k v1 <- A. indexM ary1 i1
1765
1857
L _ v2 <- A. indexM ary2 i2
1766
- A. write mary i1 (L k (f k v1 v2) )
1858
+ case f k v1 v2 of ( # v' # ) -> A. write mary i1 (L k v' )
1767
1859
go iEnd (i2+ 1 )
1768
1860
Nothing -> do -- key is only in ary2, append to end
1769
1861
A. write mary iEnd =<< A. indexM ary2 i2
0 commit comments