| ... |
... |
@@ -99,7 +99,8 @@ import qualified GHC.Data.Word64Set as W |
|
99
|
99
|
--
|
|
100
|
100
|
-- There is an implementation cost: each element is given a serial number
|
|
101
|
101
|
-- as it is added, and `udfmToList` orders its result by this serial number
|
|
102
|
|
--- (see Note [Placement sort in eltsUDFM]). So you should only use `UniqDFM`
|
|
|
102
|
+-- (see Note [Placement sort in eltsUDFM] and
|
|
|
103
|
+-- Note [Cost of deterministic iteration]). So you should only use `UniqDFM`
|
|
103
|
104
|
-- if you need the deterministic property.
|
|
104
|
105
|
--
|
|
105
|
106
|
-- `foldUDFM` also preserves determinism.
|
| ... |
... |
@@ -159,11 +160,15 @@ data UniqDFM key ele = |
|
159
|
160
|
-- time. See Note [Overflow on plusUDFM]
|
|
160
|
161
|
deriving (Data, Functor)
|
|
161
|
162
|
|
|
162
|
|
--- | Deterministic. See Note [Placement sort in eltsUDFM] for the cost.
|
|
|
163
|
+-- | Deterministic.
|
|
|
164
|
+--
|
|
|
165
|
+-- See Note [Cost of deterministic iteration].
|
|
163
|
166
|
instance Foldable (UniqDFM key) where
|
|
164
|
167
|
foldr = foldUDFM
|
|
165
|
168
|
|
|
166
|
|
--- | Deterministic. See Note [Placement sort in eltsUDFM] for the cost.
|
|
|
169
|
+-- | Deterministic.
|
|
|
170
|
+--
|
|
|
171
|
+-- See Note [Cost of deterministic iteration].
|
|
167
|
172
|
instance Traversable (UniqDFM key) where
|
|
168
|
173
|
traverse f = fmap listToUDFM_Directly
|
|
169
|
174
|
. traverse (\(u,a) -> (u,) <$> f a)
|
| ... |
... |
@@ -316,14 +321,18 @@ elemUDFM :: Uniquable key => key -> UniqDFM key elt -> Bool |
|
316
|
321
|
elemUDFM k (UDFM m _i) = M.member (getKey $ getUnique k) m
|
|
317
|
322
|
|
|
318
|
323
|
-- | Performs a deterministic fold over the UniqDFM.
|
|
|
324
|
+--
|
|
319
|
325
|
-- It's O(n) in the common case, with an O(n log n) fallback
|
|
320
|
|
--- (see Note [Placement sort in eltsUDFM]).
|
|
|
326
|
+-- (see Note [Placement sort in eltsUDFM]), and pays that in full even if
|
|
|
327
|
+-- only a prefix is demanded (see Note [Cost of deterministic iteration]).
|
|
321
|
328
|
foldUDFM :: (elt -> a -> a) -> a -> UniqDFM key elt -> a
|
|
322
|
329
|
{-# INLINE foldUDFM #-}
|
|
323
|
330
|
-- This INLINE prevents a regression in !10568
|
|
324
|
331
|
foldUDFM k z m = foldr k z (eltsUDFM m)
|
|
325
|
332
|
|
|
326
|
|
--- | Like 'foldUDFM' but the function also receives a key
|
|
|
333
|
+-- | Like 'foldUDFM' but the function also receives a key.
|
|
|
334
|
+--
|
|
|
335
|
+-- See Note [Cost of deterministic iteration].
|
|
327
|
336
|
foldWithKeyUDFM :: (Unique -> elt -> a -> a) -> a -> UniqDFM key elt -> a
|
|
328
|
337
|
{-# INLINE foldWithKeyUDFM #-}
|
|
329
|
338
|
-- This INLINE was copied from foldUDFM
|
| ... |
... |
@@ -338,6 +347,24 @@ nonDetStrictFoldUDFM k z (UDFM m _i) = foldl' k' z m |
|
338
|
347
|
where
|
|
339
|
348
|
k' acc (TaggedVal v _) = k v acc
|
|
340
|
349
|
|
|
|
350
|
+-- Note [Cost of deterministic iteration]
|
|
|
351
|
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
352
|
+-- Deterministic iteration orders elements by insertion tag, and any such
|
|
|
353
|
+-- ordering must inspect every element's tag before it can emit the first
|
|
|
354
|
+-- element. So even the head of the result costs a full O(n) traversal of the
|
|
|
355
|
+-- map -- the iteration is not incremental, and laziness in the result list (see
|
|
|
356
|
+-- Note [Placement sort in eltsUDFM]) saves allocation for undemanded
|
|
|
357
|
+-- elements, not that up-front traversal. #27459 shows this cost biting in
|
|
|
358
|
+-- consumers that demanded only the head.
|
|
|
359
|
+--
|
|
|
360
|
+-- So: to test for emptiness, use isNullUDFM rather than null on eltsUDFM;
|
|
|
361
|
+-- for order-oblivious queries, prefer short-circuiting anyUDFM/allUDFM; and
|
|
|
362
|
+-- if you don't need the deterministic order at all, use the nonDet functions
|
|
|
363
|
+-- (with a justification).
|
|
|
364
|
+
|
|
|
365
|
+-- | Deterministic, in order of insertion.
|
|
|
366
|
+--
|
|
|
367
|
+-- See Note [Cost of deterministic iteration].
|
|
341
|
368
|
eltsUDFM :: UniqDFM key elt -> [elt]
|
|
342
|
369
|
{-# INLINE eltsUDFM #-}
|
|
343
|
370
|
-- The INLINE makes it a good producer (from the map)
|
| ... |
... |
@@ -359,7 +386,8 @@ sort_it m = sortBy (compare `on` taggedSnd) (M.elems m) |
|
359
|
386
|
-- its tag, freeze, and read out in index order. That's O(i) work (which
|
|
360
|
387
|
-- subsumes the O(n) fill, since distinct tags force n <= i), no comparisons,
|
|
361
|
388
|
-- and the readout is lazy, so consumers that demand only a prefix pay almost
|
|
362
|
|
--- nothing beyond the fill.
|
|
|
389
|
+-- nothing beyond the fill (but the fill itself is unavoidable; see
|
|
|
390
|
+-- Note [Cost of deterministic iteration]).
|
|
363
|
391
|
--
|
|
364
|
392
|
-- Holes: slots whose tag never occurs keep the initial sentinel, a TaggedVal
|
|
365
|
393
|
-- with tag -1. Real tags are non-negative, so the readout skips on tag < 0;
|
| ... |
... |
@@ -378,7 +406,9 @@ usePlacement :: Int -> Int -> Bool |
|
378
|
406
|
usePlacement n i = i <= 4 * n
|
|
379
|
407
|
|
|
380
|
408
|
-- | Order a list of 'TaggedVal's by tag, by placing each at array index =
|
|
381
|
|
--- its tag. The tags must be distinct and in @[0, i)@.
|
|
|
409
|
+-- its tag.
|
|
|
410
|
+--
|
|
|
411
|
+-- The tags must be distinct and in @[0, i)@.
|
|
382
|
412
|
-- See Note [Placement sort in eltsUDFM].
|
|
383
|
413
|
placementSort :: forall r. Int -> [TaggedVal r] -> [r]
|
|
384
|
414
|
placementSort i tvs = runST (ST (\s0 ->
|
| ... |
... |
@@ -420,8 +450,10 @@ udfmRestrictKeysSet (UDFM val_set i) set = |
|
420
|
450
|
in UDFM (M.restrictKeys val_set key_set) i
|
|
421
|
451
|
|
|
422
|
452
|
-- | Converts `UniqDFM` to a list, with elements in deterministic order.
|
|
|
453
|
+--
|
|
423
|
454
|
-- It's O(n) in the common case, with an O(n log n) fallback
|
|
424
|
|
--- (see Note [Placement sort in eltsUDFM]).
|
|
|
455
|
+-- (see Note [Placement sort in eltsUDFM]), and pays that in full even if
|
|
|
456
|
+-- only a prefix is demanded (see Note [Cost of deterministic iteration]).
|
|
425
|
457
|
udfmToList :: UniqDFM key elt -> [(Unique, elt)]
|
|
426
|
458
|
udfmToList (UDFM m i)
|
|
427
|
459
|
| n <= 1 = [ (mkUniqueGrimily k, taggedFst v) | (k, v) <- M.toList m ]
|