Index: include/llvm/ADT/DenseMap.h =================================================================== --- include/llvm/ADT/DenseMap.h +++ include/llvm/ADT/DenseMap.h @@ -19,6 +19,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/ReverseIteration.h" #include "llvm/Support/type_traits.h" #include #include @@ -67,18 +68,27 @@ DenseMapIterator; inline iterator begin() { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + return makeIterator(getBucketsEnd() - 1, getBuckets(), *this); +#endif // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets(). - return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this); + return empty() ? end() + : makeIterator(getBuckets(), getBucketsEnd(), *this); } inline iterator end() { - return iterator(getBucketsEnd(), getBucketsEnd(), *this, true); + return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true); } inline const_iterator begin() const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this); +#endif return empty() ? end() - : const_iterator(getBuckets(), getBucketsEnd(), *this); + : makeConstIterator(getBuckets(), getBucketsEnd(), *this); } inline const_iterator end() const { - return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true); + return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true); } LLVM_NODISCARD bool empty() const { @@ -131,13 +141,13 @@ iterator find(const_arg_type_t Val) { BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return iterator(TheBucket, getBucketsEnd(), *this, true); + return makeIterator(TheBucket, getBucketsEnd(), *this, true); return end(); } const_iterator find(const_arg_type_t Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return const_iterator(TheBucket, getBucketsEnd(), *this, true); + return makeConstIterator(TheBucket, getBucketsEnd(), *this, true); return end(); } @@ -150,14 +160,14 @@ iterator find_as(const LookupKeyT &Val) { BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return iterator(TheBucket, getBucketsEnd(), *this, true); + return makeIterator(TheBucket, getBucketsEnd(), *this, true); return end(); } template const_iterator find_as(const LookupKeyT &Val) const { const BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return const_iterator(TheBucket, getBucketsEnd(), *this, true); + return makeConstIterator(TheBucket, getBucketsEnd(), *this, true); return end(); } @@ -191,14 +201,16 @@ std::pair try_emplace(KeyT &&Key, Ts &&... Args) { BucketT *TheBucket; if (LookupBucketFor(Key, TheBucket)) - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - false); // Already in map. + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. // Otherwise, insert the new element. TheBucket = InsertIntoBucket(TheBucket, std::move(Key), std::forward(Args)...); - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - true); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); } // Inserts key,value pair into the map if the key isn't already in the map. @@ -208,13 +220,15 @@ std::pair try_emplace(const KeyT &Key, Ts &&... Args) { BucketT *TheBucket; if (LookupBucketFor(Key, TheBucket)) - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - false); // Already in map. + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. // Otherwise, insert the new element. TheBucket = InsertIntoBucket(TheBucket, Key, std::forward(Args)...); - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - true); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); } /// Alternate version of insert() which allows a different, and possibly @@ -227,14 +241,16 @@ const LookupKeyT &Val) { BucketT *TheBucket; if (LookupBucketFor(Val, TheBucket)) - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - false); // Already in map. + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. // Otherwise, insert the new element. TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first), std::move(KV.second), Val); - return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), - true); + return std::make_pair( + makeIterator(TheBucket, getBucketsEnd(), *this, true), + true); } /// insert - Range insertion of pairs. @@ -405,6 +421,30 @@ } private: + iterator makeIterator(BucketT *P, BucketT *E, + DebugEpochBase &Epoch, + bool NoAdvance=false) { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) { + BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1; + return iterator(B, E, Epoch, NoAdvance); + } +#endif + return iterator(P, E, Epoch, NoAdvance); + } + + const_iterator makeConstIterator(const BucketT *P, const BucketT *E, + const DebugEpochBase &Epoch, + const bool NoAdvance=false) const { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) { + const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1; + return const_iterator(B, E, Epoch, NoAdvance); + } +#endif + return const_iterator(P, E, Epoch, NoAdvance); + } + unsigned getNumEntries() const { return static_cast(this)->getNumEntries(); } @@ -1089,6 +1129,12 @@ bool NoAdvance = false) : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) { assert(isHandleInSync() && "invalid construction!"); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) { + if (!NoAdvance) RetreatPastEmptyBuckets(); + return; + } +#endif if (!NoAdvance) AdvancePastEmptyBuckets(); } @@ -1103,10 +1149,18 @@ reference operator*() const { assert(isHandleInSync() && "invalid iterator access!"); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + return Ptr[-1]; +#endif return *Ptr; } pointer operator->() const { assert(isHandleInSync() && "invalid iterator access!"); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) + return &(Ptr[-1]); +#endif return Ptr; } @@ -1127,6 +1181,13 @@ inline DenseMapIterator& operator++() { // Preincrement assert(isHandleInSync() && "invalid iterator access!"); +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + if (ReverseIterate::value) { + --Ptr; + RetreatPastEmptyBuckets(); + return *this; + } +#endif ++Ptr; AdvancePastEmptyBuckets(); return *this; @@ -1138,6 +1199,7 @@ private: void AdvancePastEmptyBuckets() { + assert(Ptr <= End); const KeyT Empty = KeyInfoT::getEmptyKey(); const KeyT Tombstone = KeyInfoT::getTombstoneKey(); @@ -1145,6 +1207,17 @@ KeyInfoT::isEqual(Ptr->getFirst(), Tombstone))) ++Ptr; } +#if LLVM_ENABLE_ABI_BREAKING_CHECKS + void RetreatPastEmptyBuckets() { + assert(Ptr >= End); + const KeyT Empty = KeyInfoT::getEmptyKey(); + const KeyT Tombstone = KeyInfoT::getTombstoneKey(); + + while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) || + KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone))) + --Ptr; + } +#endif }; template Index: unittests/ADT/ReverseIterationTest.cpp =================================================================== --- unittests/ADT/ReverseIterationTest.cpp +++ unittests/ADT/ReverseIterationTest.cpp @@ -11,12 +11,49 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "gtest/gtest.h" #if LLVM_ENABLE_ABI_BREAKING_CHECKS using namespace llvm; +TEST(ReverseIterationTest, DenseMapTest) { + + DenseMap Map; + void *Keys[] = { (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4 }; + void *ReverseKeys[] = { (void*)0x4, (void*)0x3, (void*)0x2, (void*)0x1 }; + + for (auto *Key: Keys) + Map[Key] = 0; + + // Check forward iteration. + ReverseIterate::value = false; + for (const auto &Tuple : zip(Map, Keys)) + ASSERT_EQ(std::get<0>(Tuple).first, std::get<1>(Tuple)); + + // Check operator++ (post-increment) in forward iteration. + int i = 0; + for (auto begin = Map.begin(), end = Map.end(); + begin != end; i++) { + ASSERT_EQ(begin->first, Keys[i]); + begin++; + } + + // Check reverse iteration. + ReverseIterate::value = true; + for (const auto &Tuple : zip(Map, ReverseKeys)) + ASSERT_EQ(std::get<0>(Tuple).first, std::get<1>(Tuple)); + + // Check operator++ (post-increment) in reverse iteration. + i = 0; + for (auto begin = Map.begin(), end = Map.end(); + begin != end; i++) { + ASSERT_EQ(begin->first, ReverseKeys[i]); + begin++; + } +} + TEST(ReverseIterationTest, SmallPtrSetTest) { SmallPtrSet Set;