[llvm] [ADT] Move the core logic of swapping to DenseMapBase::swap (NFC) (PR #168486)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 18 09:10:43 PST 2025


================
@@ -424,6 +433,43 @@ class DenseMapBase : public DebugEpochBase {
     return NextPowerOf2(NumEntries * 4 / 3 + 1);
   }
 
+  // Move buckets without rehash.
+  //
+  // Preconditions:
+  // - *this is killed.
+  // - RHS is valid.
+  //
+  // Post conditions:
+  // - *this is valid.
+  // - RHS is valid or killed (but not uninitialized).
+  void moveWithoutRehash(DerivedT &&RHS) {
+    if (derived().maybeMoveFast(std::move(RHS.derived())))
+      return;
+
+    derived().allocateBuckets(RHS.getNumBuckets());
+    setNumEntries(RHS.getNumEntries());
+    setNumTombstones(RHS.getNumTombstones());
+    DerivedT &LHS = derived();
+    iterator_range<BucketT *> LHSBuckets = LHS.buckets();
+    iterator_range<BucketT *> RHSBuckets = RHS.buckets();
+    assert(std::distance(LHSBuckets.begin(), LHSBuckets.end()) ==
+           std::distance(RHSBuckets.begin(), RHSBuckets.end()));
+    const KeyT EmptyKey = KeyInfoT::getEmptyKey();
+    const KeyT TombstoneKey = KeyInfoT::getTombstoneKey();
+    for (BucketT *L = LHSBuckets.begin(), *R = RHSBuckets.begin(),
+                 *E = LHSBuckets.end();
+         L != E; ++L, ++R) {
+      ::new (&L->getFirst()) KeyT(std::move(R->getFirst()));
+      R->getFirst().~KeyT();
+      if (!KeyInfoT::isEqual(L->getFirst(), EmptyKey) &&
+          !KeyInfoT::isEqual(L->getFirst(), TombstoneKey)) {
+        ::new (&L->getSecond()) ValueT(std::move(R->getSecond()));
+        R->getSecond().~ValueT();
+      }
+    }
+    RHS.derived().kill();
----------------
kazutakahirata wrote:

The call to `deallocateBuckets` inside `kill` is a no-op here because this path is used in the small mode.

If `RHS` is in the large mode, we take the fast path:

```
    if (derived().maybeMoveFast(std::move(RHS)))
      return;
```

If `RHS` is in the small mode, we take the slow path ending with `kill()`.

`kill()` here puts `RHS` in a known good state that is safe for destruction.  Without `kill()`, `RHS` would remain a move-from object, and that's not safe for destruction, which involves `destroyAll`.


https://github.com/llvm/llvm-project/pull/168486


More information about the llvm-commits mailing list