[llvm] [ADT] Move DenseMapIterator above DenseMapBase (NFC) (PR #227208)
Kazu Hirata via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 00:31:40 PDT 2026
https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/227208
This patch moves the definition of DenseMapIterator right above
DenseMapBase so that all classes in DenseMap.h are defined in the
bottom-up order without forward declarations:
- DenseMapStorage
- SmallDenseMapStorage
- DenseMapIterator
- DenseMapBase
- DenseMap
- SmallDenseMap
Assisted-by: Antigravity
>From 3317d471ecb35c8cca65dd612c8cf83147fc8ff8 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Mon, 28 Sep 2026 11:12:29 -0700
Subject: [PATCH] [ADT] Move DenseMapIterator above DenseMapBase (NFC)
This patch moves the definition of DenseMapIterator right above
DenseMapBase so that all classes in DenseMap.h are defined in the
bottom-up order without forward declarations:
- DenseMapStorage
- SmallDenseMapStorage
- DenseMapIterator
- DenseMapBase
- DenseMap
- SmallDenseMap
Assisted-by: Antigravity
---
llvm/include/llvm/ADT/DenseMap.h | 286 +++++++++++++++----------------
1 file changed, 141 insertions(+), 145 deletions(-)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 756f9e93a04ef..1757f8ee3438c 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -539,7 +539,147 @@ template <typename KeyT, typename ValueT,
typename KeyInfoT = DenseMapInfo<KeyT>,
typename Bucket = llvm::detail::DenseMapPair<KeyT, ValueT>,
bool IsConst = false>
-class DenseMapIterator;
+class DenseMapIterator : DebugEpochBase::HandleBase {
+ friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
+ friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
+
+ using UsedT = llvm::densemap::detail::UsedT;
+
+public:
+ using difference_type = ptrdiff_t;
+ using value_type = std::conditional_t<IsConst, const Bucket, Bucket>;
+ using pointer = value_type *;
+ using reference = value_type &;
+ using iterator_category = std::forward_iterator_tag;
+
+private:
+ using BucketItTy =
+ std::conditional_t<shouldReverseIterate<KeyT>(),
+ std::reverse_iterator<pointer>, pointer>;
+
+ BucketItTy Ptr = {};
+ BucketItTy End = {};
+ // The non-reversed bucket base and the parallel used array. They map a
+ // bucket back to its index so AdvancePastEmptyBuckets can consult the bits.
+ pointer Buckets = {};
+ const UsedT *Used = {};
+
+ DenseMapIterator(BucketItTy Pos, BucketItTy E, pointer BucketsBase,
+ const UsedT *U, const DebugEpochBase &Epoch)
+ : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E),
+ Buckets(BucketsBase), Used(U) {
+ assert(isHandleInSync() && "invalid construction!");
+ }
+
+public:
+ DenseMapIterator() = default;
+
+ static DenseMapIterator makeBegin(pointer Buckets, const UsedT *Used,
+ unsigned NumBuckets, bool IsEmpty,
+ const DebugEpochBase &Epoch) {
+ // When the map is empty, avoid the overhead of advancing/retreating past
+ // empty buckets.
+ if (IsEmpty)
+ return makeEnd(Buckets, Used, NumBuckets, Epoch);
+ auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
+ DenseMapIterator Iter(R.begin(), R.end(), Buckets, Used, Epoch);
+ Iter.AdvancePastEmptyBuckets();
+ return Iter;
+ }
+
+ static DenseMapIterator makeEnd(pointer Buckets, const UsedT *Used,
+ unsigned NumBuckets,
+ const DebugEpochBase &Epoch) {
+ auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
+ return DenseMapIterator(R.end(), R.end(), Buckets, Used, Epoch);
+ }
+
+ static DenseMapIterator makeIterator(pointer P, pointer Buckets,
+ const UsedT *Used, unsigned NumBuckets,
+ const DebugEpochBase &Epoch) {
+ auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
+ constexpr int Offset = shouldReverseIterate<KeyT>() ? 1 : 0;
+ return DenseMapIterator(BucketItTy(P + Offset), R.end(), Buckets, Used,
+ Epoch);
+ }
+
+ // Converting ctor from non-const iterators to const iterators. SFINAE'd out
+ // for const iterator destinations so it doesn't end up as a user defined copy
+ // constructor.
+ template <bool IsConstSrc,
+ typename = std::enable_if_t<!IsConstSrc && IsConst>>
+ DenseMapIterator(
+ const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
+ : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End),
+ Buckets(I.Buckets), Used(I.Used) {}
+
+ [[nodiscard]] reference operator*() const {
+ assert(isHandleInSync() && "invalid iterator access!");
+ assert(Ptr != End && "dereferencing end() iterator");
+ return *Ptr;
+ }
+ [[nodiscard]] pointer operator->() const { return &operator*(); }
+
+ [[nodiscard]] friend bool operator==(const DenseMapIterator &LHS,
+ const DenseMapIterator &RHS) {
+ assert(LHS.isComparableWith(RHS) && "incomparable iterators!");
+ return LHS.Ptr == RHS.Ptr;
+ }
+
+ [[nodiscard]] friend bool operator!=(const DenseMapIterator &LHS,
+ const DenseMapIterator &RHS) {
+ return !(LHS == RHS);
+ }
+
+ inline DenseMapIterator &operator++() { // Preincrement
+ assert(isHandleInSync() && "invalid iterator access!");
+ assert(Ptr != End && "incrementing end() iterator");
+ ++Ptr;
+ AdvancePastEmptyBuckets();
+ return *this;
+ }
+ DenseMapIterator operator++(int) { // Postincrement
+ assert(isHandleInSync() && "invalid iterator access!");
+ DenseMapIterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+private:
+ void AdvancePastEmptyBuckets() {
+ if constexpr (shouldReverseIterate<KeyT>()) {
+ while (Ptr != End && !llvm::densemap::detail::used(Used, &*Ptr - Buckets))
+ ++Ptr;
+ } else {
+ // Forward iteration skips empty buckets a used-word (32 buckets) at a
+ // time: scan from the current index for the next set occupancy bit.
+ const size_t N = End - Buckets;
+ size_t I = Ptr - Buckets;
+ if (I >= N) {
+ Ptr = End;
+ return;
+ }
+ const size_t NW = llvm::densemap::detail::usedWords(N);
+ size_t W = I >> 5;
+ UsedT Bits = Used[W] & (~UsedT(0) << (I & 31));
+ while (Bits == 0) {
+ if (++W == NW) {
+ Ptr = End;
+ return;
+ }
+ Bits = Used[W];
+ }
+ Ptr = Buckets + ((W << 5) + llvm::countr_zero(Bits));
+ }
+ }
+
+ static auto maybeReverse(iterator_range<pointer> Range) {
+ if constexpr (shouldReverseIterate<KeyT>())
+ return reverse(Range);
+ else
+ return Range;
+ }
+};
template <typename StorageT, typename KeyT, typename ValueT, typename KeyInfoT,
typename BucketT>
@@ -1331,150 +1471,6 @@ class SmallDenseMap
using BaseT::BaseT;
};
-template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
- bool IsConst>
-class DenseMapIterator : DebugEpochBase::HandleBase {
- friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
- friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
-
- using UsedT = llvm::densemap::detail::UsedT;
-
-public:
- using difference_type = ptrdiff_t;
- using value_type = std::conditional_t<IsConst, const Bucket, Bucket>;
- using pointer = value_type *;
- using reference = value_type &;
- using iterator_category = std::forward_iterator_tag;
-
-private:
- using BucketItTy =
- std::conditional_t<shouldReverseIterate<KeyT>(),
- std::reverse_iterator<pointer>, pointer>;
-
- BucketItTy Ptr = {};
- BucketItTy End = {};
- // The non-reversed bucket base and the parallel used array. They map a
- // bucket back to its index so AdvancePastEmptyBuckets can consult the bits.
- pointer Buckets = {};
- const UsedT *Used = {};
-
- DenseMapIterator(BucketItTy Pos, BucketItTy E, pointer BucketsBase,
- const UsedT *U, const DebugEpochBase &Epoch)
- : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E),
- Buckets(BucketsBase), Used(U) {
- assert(isHandleInSync() && "invalid construction!");
- }
-
-public:
- DenseMapIterator() = default;
-
- static DenseMapIterator makeBegin(pointer Buckets, const UsedT *Used,
- unsigned NumBuckets, bool IsEmpty,
- const DebugEpochBase &Epoch) {
- // When the map is empty, avoid the overhead of advancing/retreating past
- // empty buckets.
- if (IsEmpty)
- return makeEnd(Buckets, Used, NumBuckets, Epoch);
- auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
- DenseMapIterator Iter(R.begin(), R.end(), Buckets, Used, Epoch);
- Iter.AdvancePastEmptyBuckets();
- return Iter;
- }
-
- static DenseMapIterator makeEnd(pointer Buckets, const UsedT *Used,
- unsigned NumBuckets,
- const DebugEpochBase &Epoch) {
- auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
- return DenseMapIterator(R.end(), R.end(), Buckets, Used, Epoch);
- }
-
- static DenseMapIterator makeIterator(pointer P, pointer Buckets,
- const UsedT *Used, unsigned NumBuckets,
- const DebugEpochBase &Epoch) {
- auto R = maybeReverse(llvm::make_range(Buckets, Buckets + NumBuckets));
- constexpr int Offset = shouldReverseIterate<KeyT>() ? 1 : 0;
- return DenseMapIterator(BucketItTy(P + Offset), R.end(), Buckets, Used,
- Epoch);
- }
-
- // Converting ctor from non-const iterators to const iterators. SFINAE'd out
- // for const iterator destinations so it doesn't end up as a user defined copy
- // constructor.
- template <bool IsConstSrc,
- typename = std::enable_if_t<!IsConstSrc && IsConst>>
- DenseMapIterator(
- const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
- : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End),
- Buckets(I.Buckets), Used(I.Used) {}
-
- [[nodiscard]] reference operator*() const {
- assert(isHandleInSync() && "invalid iterator access!");
- assert(Ptr != End && "dereferencing end() iterator");
- return *Ptr;
- }
- [[nodiscard]] pointer operator->() const { return &operator*(); }
-
- [[nodiscard]] friend bool operator==(const DenseMapIterator &LHS,
- const DenseMapIterator &RHS) {
- assert(LHS.isComparableWith(RHS) && "incomparable iterators!");
- return LHS.Ptr == RHS.Ptr;
- }
-
- [[nodiscard]] friend bool operator!=(const DenseMapIterator &LHS,
- const DenseMapIterator &RHS) {
- return !(LHS == RHS);
- }
-
- inline DenseMapIterator &operator++() { // Preincrement
- assert(isHandleInSync() && "invalid iterator access!");
- assert(Ptr != End && "incrementing end() iterator");
- ++Ptr;
- AdvancePastEmptyBuckets();
- return *this;
- }
- DenseMapIterator operator++(int) { // Postincrement
- assert(isHandleInSync() && "invalid iterator access!");
- DenseMapIterator tmp = *this;
- ++*this;
- return tmp;
- }
-
-private:
- void AdvancePastEmptyBuckets() {
- if constexpr (shouldReverseIterate<KeyT>()) {
- while (Ptr != End && !llvm::densemap::detail::used(Used, &*Ptr - Buckets))
- ++Ptr;
- } else {
- // Forward iteration skips empty buckets a used-word (32 buckets) at a
- // time: scan from the current index for the next set occupancy bit.
- const size_t N = End - Buckets;
- size_t I = Ptr - Buckets;
- if (I >= N) {
- Ptr = End;
- return;
- }
- const size_t NW = llvm::densemap::detail::usedWords(N);
- size_t W = I >> 5;
- UsedT Bits = Used[W] & (~UsedT(0) << (I & 31));
- while (Bits == 0) {
- if (++W == NW) {
- Ptr = End;
- return;
- }
- Bits = Used[W];
- }
- Ptr = Buckets + ((W << 5) + llvm::countr_zero(Bits));
- }
- }
-
- static auto maybeReverse(iterator_range<pointer> Range) {
- if constexpr (shouldReverseIterate<KeyT>())
- return reverse(Range);
- else
- return Range;
- }
-};
-
template <typename KeyT, typename ValueT, typename KeyInfoT>
[[nodiscard]] inline size_t
capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
More information about the llvm-commits
mailing list