Skip to content

Commit 71a28f3

Browse files
[ADT] Simplify DenseMapIterator with std::reverse_iterator (NFC) (#157389)
DenseMapIterator has two tasks: - iterate the buckets in the requested direction - skip the empty and tombstone buckets These tasks are intertwined in the current implementation. This patch cleans up DenseMapIterator by separating the two tasks. Specifically, we introduce a private middleman iterator type called BucketItTy. This is the same as the pointer-based iterator in the forward direction, but it becomes std::reverse_iterator<pointer> otherwise. Now, the user-facing iterator iterates over BucketItTy while skipping the empty and tombstone buckets. This way, AdvancePastEmptyBuckets always calls BucketItTy::operator++. If the reverse iteration is requested, the underlying raw pointer gets decremented, but that logic is hidden behind std::reverse_iterator<pointer>::operator++. As a result, we can remove RetreatPastEmptyBuckets and a couple of calls to shouldReverseIterate. Here is a data point. A couple of months ago, we were calling shouldReverseIterate from 18 places in DenseMap.h. That's down to 5. This patch reduces it further down to 3.
1 parent ee5bc57 commit 71a28f3

File tree

1 file changed

+23
-32
lines changed

1 file changed

+23
-32
lines changed

llvm/include/llvm/ADT/DenseMap.h

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,10 +1184,14 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
11841184
using iterator_category = std::forward_iterator_tag;
11851185

11861186
private:
1187-
pointer Ptr = nullptr;
1188-
pointer End = nullptr;
1187+
using BucketItTy =
1188+
std::conditional_t<shouldReverseIterate<KeyT>(),
1189+
std::reverse_iterator<pointer>, pointer>;
11891190

1190-
DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch)
1191+
BucketItTy Ptr = {};
1192+
BucketItTy End = {};
1193+
1194+
DenseMapIterator(BucketItTy Pos, BucketItTy E, const DebugEpochBase &Epoch)
11911195
: DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
11921196
assert(isHandleInSync() && "invalid construction!");
11931197
}
@@ -1201,29 +1205,24 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
12011205
// empty buckets.
12021206
if (IsEmpty)
12031207
return makeEnd(Buckets, Epoch);
1204-
if (shouldReverseIterate<KeyT>()) {
1205-
DenseMapIterator Iter(Buckets.end(), Buckets.begin(), Epoch);
1206-
Iter.RetreatPastEmptyBuckets();
1207-
return Iter;
1208-
}
1209-
DenseMapIterator Iter(Buckets.begin(), Buckets.end(), Epoch);
1208+
auto R = maybeReverse(Buckets);
1209+
DenseMapIterator Iter(R.begin(), R.end(), Epoch);
12101210
Iter.AdvancePastEmptyBuckets();
12111211
return Iter;
12121212
}
12131213

12141214
static DenseMapIterator makeEnd(iterator_range<pointer> Buckets,
12151215
const DebugEpochBase &Epoch) {
1216-
if (shouldReverseIterate<KeyT>())
1217-
return DenseMapIterator(Buckets.begin(), Buckets.begin(), Epoch);
1218-
return DenseMapIterator(Buckets.end(), Buckets.end(), Epoch);
1216+
auto R = maybeReverse(Buckets);
1217+
return DenseMapIterator(R.end(), R.end(), Epoch);
12191218
}
12201219

12211220
static DenseMapIterator makeIterator(pointer P,
12221221
iterator_range<pointer> Buckets,
12231222
const DebugEpochBase &Epoch) {
1224-
if (shouldReverseIterate<KeyT>())
1225-
return DenseMapIterator(P + 1, Buckets.begin(), Epoch);
1226-
return DenseMapIterator(P, Buckets.end(), Epoch);
1223+
auto R = maybeReverse(Buckets);
1224+
constexpr int Offset = shouldReverseIterate<KeyT>() ? 1 : 0;
1225+
return DenseMapIterator(BucketItTy(P + Offset), R.end(), Epoch);
12271226
}
12281227

12291228
// Converting ctor from non-const iterators to const iterators. SFINAE'd out
@@ -1238,16 +1237,16 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
12381237
reference operator*() const {
12391238
assert(isHandleInSync() && "invalid iterator access!");
12401239
assert(Ptr != End && "dereferencing end() iterator");
1241-
if (shouldReverseIterate<KeyT>())
1242-
return Ptr[-1];
12431240
return *Ptr;
12441241
}
12451242
pointer operator->() const { return &operator*(); }
12461243

12471244
friend bool operator==(const DenseMapIterator &LHS,
12481245
const DenseMapIterator &RHS) {
1249-
assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
1250-
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
1246+
assert((!LHS.getEpochAddress() || LHS.isHandleInSync()) &&
1247+
"handle not in sync!");
1248+
assert((!RHS.getEpochAddress() || RHS.isHandleInSync()) &&
1249+
"handle not in sync!");
12511250
assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
12521251
"comparing incomparable iterators!");
12531252
return LHS.Ptr == RHS.Ptr;
@@ -1261,11 +1260,6 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
12611260
inline DenseMapIterator &operator++() { // Preincrement
12621261
assert(isHandleInSync() && "invalid iterator access!");
12631262
assert(Ptr != End && "incrementing end() iterator");
1264-
if (shouldReverseIterate<KeyT>()) {
1265-
--Ptr;
1266-
RetreatPastEmptyBuckets();
1267-
return *this;
1268-
}
12691263
++Ptr;
12701264
AdvancePastEmptyBuckets();
12711265
return *this;
@@ -1288,14 +1282,11 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
12881282
++Ptr;
12891283
}
12901284

1291-
void RetreatPastEmptyBuckets() {
1292-
assert(Ptr >= End);
1293-
const KeyT Empty = KeyInfoT::getEmptyKey();
1294-
const KeyT Tombstone = KeyInfoT::getTombstoneKey();
1295-
1296-
while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
1297-
KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
1298-
--Ptr;
1285+
static auto maybeReverse(iterator_range<pointer> Range) {
1286+
if constexpr (shouldReverseIterate<KeyT>())
1287+
return reverse(Range);
1288+
else
1289+
return Range;
12991290
}
13001291
};
13011292

0 commit comments

Comments
 (0)