-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[ADT] Refactor StringMap iterators (NFC) #156137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ADT] Refactor StringMap iterators (NFC) #156137
Conversation
StringMap has four iterator classes: - StringMapIterBase - StringMapIterator - StringMapConstIterator - StringMapKeyIterator This patch consolidates the first three into one class, namely StringMapIterBase, adds a boolean template parameter to indicate desired constness, and then use "using" directives to specialize the common class: using const_iterator = StringMapIterBase<ValueTy, true>; using iterator = StringMapIterBase<ValueTy, false>; just like how we simplified DenseMapIterator. Remarks: - This patch drops CRTP and iterator_facade_base for simplicity. For fairly simple forward iterators, iterator_facade_base doesn't buy us much. We just have to write a few "using" directives and operator!= manually. - StringMapIterBase has a SFINAE-based constructor to construct a const iterator from a non-const one just like DenseMapIterator. - We now rely on compiler-generated copy and assignment operators.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-tools-extra Author: Kazu Hirata (kazutakahirata) ChangesStringMap has four iterator classes:
This patch consolidates the first three into one class, namely using const_iterator = StringMapIterBase<ValueTy, true>; just like how we simplified DenseMapIterator. Remarks:
Full diff: https://github.com/llvm/llvm-project/pull/156137.diff 3 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
index 36b6007b58a51..4382f9df5336e 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
@@ -39,7 +39,7 @@ bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
bool &IsInterface) const {
assert(Node->getIdentifier());
StringRef Name = Node->getIdentifier()->getName();
- llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
+ auto Pair = InterfaceMap.find(Name);
if (Pair == InterfaceMap.end())
return false;
IsInterface = Pair->second;
diff --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp
index e83aee01b75cb..f69ac41dddb3e 100644
--- a/clang/lib/Driver/OffloadBundler.cpp
+++ b/clang/lib/Driver/OffloadBundler.cpp
@@ -1936,8 +1936,7 @@ Error OffloadBundler::UnbundleArchive() {
/// Write out an archive for each target
for (auto &Target : BundlerConfig.TargetNames) {
StringRef FileName = TargetOutputFileNameMap[Target];
- StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
- OutputArchivesMap.find(Target);
+ auto CurArchiveMembers = OutputArchivesMap.find(Target);
if (CurArchiveMembers != OutputArchivesMap.end()) {
if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
SymtabWritingMode::NormalSymtab,
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
index dbc0485967ac6..aabe8cd7903c8 100644
--- a/llvm/include/llvm/ADT/StringMap.h
+++ b/llvm/include/llvm/ADT/StringMap.h
@@ -21,11 +21,11 @@
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <initializer_list>
#include <iterator>
+#include <type_traits>
namespace llvm {
-template <typename ValueTy> class StringMapConstIterator;
-template <typename ValueTy> class StringMapIterator;
+template <typename ValueTy, bool IsConst> class StringMapIterBase;
template <typename ValueTy> class StringMapKeyIterator;
/// StringMapImpl - This is the base class of StringMap that is shared among
@@ -217,8 +217,8 @@ class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
- using const_iterator = StringMapConstIterator<ValueTy>;
- using iterator = StringMapIterator<ValueTy>;
+ using const_iterator = StringMapIterBase<ValueTy, true>;
+ using iterator = StringMapIterBase<ValueTy, false>;
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
iterator end() { return iterator(TheTable + NumBuckets, true); }
@@ -431,14 +431,19 @@ class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
}
};
-template <typename DerivedTy, typename ValueTy>
-class StringMapIterBase
- : public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
- ValueTy> {
-protected:
+template <typename ValueTy, bool IsConst> class StringMapIterBase {
+ using EntryTy = std::conditional_t<IsConst, const StringMapEntry<ValueTy>,
+ StringMapEntry<ValueTy>>;
+
StringMapEntryBase **Ptr = nullptr;
public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = EntryTy;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
StringMapIterBase() = default;
explicit StringMapIterBase(StringMapEntryBase **Bucket,
@@ -448,85 +453,56 @@ class StringMapIterBase
AdvancePastEmptyBuckets();
}
- DerivedTy &operator=(const DerivedTy &Other) {
- Ptr = Other.Ptr;
- return static_cast<DerivedTy &>(*this);
- }
-
- friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
- return LHS.Ptr == RHS.Ptr;
- }
+ reference operator*() const { return *static_cast<EntryTy *>(*Ptr); }
+ pointer operator->() const { return &operator*(); }
- DerivedTy &operator++() { // Preincrement
+ StringMapIterBase &operator++() { // Preincrement
++Ptr;
AdvancePastEmptyBuckets();
- return static_cast<DerivedTy &>(*this);
+ return *this;
}
- DerivedTy operator++(int) { // Post-increment
- DerivedTy Tmp(Ptr);
+ StringMapIterBase operator++(int) { // Post-increment
+ StringMapIterBase Tmp(*this);
++*this;
return Tmp;
}
-private:
- void AdvancePastEmptyBuckets() {
- while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
- ++Ptr;
+ template <bool ToConst,
+ typename = typename std::enable_if<!IsConst && ToConst>::type>
+ operator StringMapIterBase<ValueTy, ToConst>() const {
+ return StringMapIterBase<ValueTy, ToConst>(Ptr, true);
}
-};
-
-template <typename ValueTy>
-class StringMapConstIterator
- : public StringMapIterBase<StringMapConstIterator<ValueTy>,
- const StringMapEntry<ValueTy>> {
- using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
- const StringMapEntry<ValueTy>>;
-
-public:
- StringMapConstIterator() = default;
- explicit StringMapConstIterator(StringMapEntryBase **Bucket,
- bool NoAdvance = false)
- : base(Bucket, NoAdvance) {}
- const StringMapEntry<ValueTy> &operator*() const {
- return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
+ friend bool operator==(const StringMapIterBase &LHS,
+ const StringMapIterBase &RHS) {
+ return LHS.Ptr == RHS.Ptr;
}
-};
-
-template <typename ValueTy>
-class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
- StringMapEntry<ValueTy>> {
- using base =
- StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
-public:
- StringMapIterator() = default;
- explicit StringMapIterator(StringMapEntryBase **Bucket,
- bool NoAdvance = false)
- : base(Bucket, NoAdvance) {}
-
- StringMapEntry<ValueTy> &operator*() const {
- return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
+ friend bool operator!=(const StringMapIterBase &LHS,
+ const StringMapIterBase &RHS) {
+ return !(LHS == RHS);
}
- operator StringMapConstIterator<ValueTy>() const {
- return StringMapConstIterator<ValueTy>(this->Ptr, true);
+private:
+ void AdvancePastEmptyBuckets() {
+ while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
+ ++Ptr;
}
};
template <typename ValueTy>
class StringMapKeyIterator
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
- StringMapConstIterator<ValueTy>,
+ StringMapIterBase<ValueTy, true>,
std::forward_iterator_tag, StringRef> {
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
- StringMapConstIterator<ValueTy>,
+ StringMapIterBase<ValueTy, true>,
std::forward_iterator_tag, StringRef>;
public:
StringMapKeyIterator() = default;
- explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
+ explicit StringMapKeyIterator(StringMapIterBase<ValueTy, true> Iter)
: base(std::move(Iter)) {}
StringRef operator*() const { return this->wrapped()->getKey(); }
|
@llvm/pr-subscribers-llvm-adt Author: Kazu Hirata (kazutakahirata) ChangesStringMap has four iterator classes:
This patch consolidates the first three into one class, namely using const_iterator = StringMapIterBase<ValueTy, true>; just like how we simplified DenseMapIterator. Remarks:
Full diff: https://github.com/llvm/llvm-project/pull/156137.diff 3 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
index 36b6007b58a51..4382f9df5336e 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
@@ -39,7 +39,7 @@ bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
bool &IsInterface) const {
assert(Node->getIdentifier());
StringRef Name = Node->getIdentifier()->getName();
- llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
+ auto Pair = InterfaceMap.find(Name);
if (Pair == InterfaceMap.end())
return false;
IsInterface = Pair->second;
diff --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp
index e83aee01b75cb..f69ac41dddb3e 100644
--- a/clang/lib/Driver/OffloadBundler.cpp
+++ b/clang/lib/Driver/OffloadBundler.cpp
@@ -1936,8 +1936,7 @@ Error OffloadBundler::UnbundleArchive() {
/// Write out an archive for each target
for (auto &Target : BundlerConfig.TargetNames) {
StringRef FileName = TargetOutputFileNameMap[Target];
- StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
- OutputArchivesMap.find(Target);
+ auto CurArchiveMembers = OutputArchivesMap.find(Target);
if (CurArchiveMembers != OutputArchivesMap.end()) {
if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
SymtabWritingMode::NormalSymtab,
diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h
index dbc0485967ac6..aabe8cd7903c8 100644
--- a/llvm/include/llvm/ADT/StringMap.h
+++ b/llvm/include/llvm/ADT/StringMap.h
@@ -21,11 +21,11 @@
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <initializer_list>
#include <iterator>
+#include <type_traits>
namespace llvm {
-template <typename ValueTy> class StringMapConstIterator;
-template <typename ValueTy> class StringMapIterator;
+template <typename ValueTy, bool IsConst> class StringMapIterBase;
template <typename ValueTy> class StringMapKeyIterator;
/// StringMapImpl - This is the base class of StringMap that is shared among
@@ -217,8 +217,8 @@ class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
- using const_iterator = StringMapConstIterator<ValueTy>;
- using iterator = StringMapIterator<ValueTy>;
+ using const_iterator = StringMapIterBase<ValueTy, true>;
+ using iterator = StringMapIterBase<ValueTy, false>;
iterator begin() { return iterator(TheTable, NumBuckets == 0); }
iterator end() { return iterator(TheTable + NumBuckets, true); }
@@ -431,14 +431,19 @@ class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
}
};
-template <typename DerivedTy, typename ValueTy>
-class StringMapIterBase
- : public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
- ValueTy> {
-protected:
+template <typename ValueTy, bool IsConst> class StringMapIterBase {
+ using EntryTy = std::conditional_t<IsConst, const StringMapEntry<ValueTy>,
+ StringMapEntry<ValueTy>>;
+
StringMapEntryBase **Ptr = nullptr;
public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = EntryTy;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
StringMapIterBase() = default;
explicit StringMapIterBase(StringMapEntryBase **Bucket,
@@ -448,85 +453,56 @@ class StringMapIterBase
AdvancePastEmptyBuckets();
}
- DerivedTy &operator=(const DerivedTy &Other) {
- Ptr = Other.Ptr;
- return static_cast<DerivedTy &>(*this);
- }
-
- friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
- return LHS.Ptr == RHS.Ptr;
- }
+ reference operator*() const { return *static_cast<EntryTy *>(*Ptr); }
+ pointer operator->() const { return &operator*(); }
- DerivedTy &operator++() { // Preincrement
+ StringMapIterBase &operator++() { // Preincrement
++Ptr;
AdvancePastEmptyBuckets();
- return static_cast<DerivedTy &>(*this);
+ return *this;
}
- DerivedTy operator++(int) { // Post-increment
- DerivedTy Tmp(Ptr);
+ StringMapIterBase operator++(int) { // Post-increment
+ StringMapIterBase Tmp(*this);
++*this;
return Tmp;
}
-private:
- void AdvancePastEmptyBuckets() {
- while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
- ++Ptr;
+ template <bool ToConst,
+ typename = typename std::enable_if<!IsConst && ToConst>::type>
+ operator StringMapIterBase<ValueTy, ToConst>() const {
+ return StringMapIterBase<ValueTy, ToConst>(Ptr, true);
}
-};
-
-template <typename ValueTy>
-class StringMapConstIterator
- : public StringMapIterBase<StringMapConstIterator<ValueTy>,
- const StringMapEntry<ValueTy>> {
- using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
- const StringMapEntry<ValueTy>>;
-
-public:
- StringMapConstIterator() = default;
- explicit StringMapConstIterator(StringMapEntryBase **Bucket,
- bool NoAdvance = false)
- : base(Bucket, NoAdvance) {}
- const StringMapEntry<ValueTy> &operator*() const {
- return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
+ friend bool operator==(const StringMapIterBase &LHS,
+ const StringMapIterBase &RHS) {
+ return LHS.Ptr == RHS.Ptr;
}
-};
-
-template <typename ValueTy>
-class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
- StringMapEntry<ValueTy>> {
- using base =
- StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
-public:
- StringMapIterator() = default;
- explicit StringMapIterator(StringMapEntryBase **Bucket,
- bool NoAdvance = false)
- : base(Bucket, NoAdvance) {}
-
- StringMapEntry<ValueTy> &operator*() const {
- return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
+ friend bool operator!=(const StringMapIterBase &LHS,
+ const StringMapIterBase &RHS) {
+ return !(LHS == RHS);
}
- operator StringMapConstIterator<ValueTy>() const {
- return StringMapConstIterator<ValueTy>(this->Ptr, true);
+private:
+ void AdvancePastEmptyBuckets() {
+ while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal())
+ ++Ptr;
}
};
template <typename ValueTy>
class StringMapKeyIterator
: public iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
- StringMapConstIterator<ValueTy>,
+ StringMapIterBase<ValueTy, true>,
std::forward_iterator_tag, StringRef> {
using base = iterator_adaptor_base<StringMapKeyIterator<ValueTy>,
- StringMapConstIterator<ValueTy>,
+ StringMapIterBase<ValueTy, true>,
std::forward_iterator_tag, StringRef>;
public:
StringMapKeyIterator() = default;
- explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
+ explicit StringMapKeyIterator(StringMapIterBase<ValueTy, true> Iter)
: base(std::move(Iter)) {}
StringRef operator*() const { return this->wrapped()->getKey(); }
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have dedicated unit tests for these iterators?
I wouldn't say
I'd say this is pretty good coverage. |
Maybe we could add some tests with |
@kuhar Good idea! I've added a couple of tests about iterator types. Please take a look. Thanks in advance! |
@kuhar I've added a few more tests on iterator traits. Also, I've corrected a bug where |
✅ With the latest revision this PR passed the C/C++ code formatter. |
StringMap has four iterator classes:
This patch consolidates the first three into one class, namely
StringMapIterBase, adds a boolean template parameter to indicate
desired constness, and then use "using" directives to specialize the
common class:
using const_iterator = StringMapIterBase<ValueTy, true>;
using iterator = StringMapIterBase<ValueTy, false>;
just like how we simplified DenseMapIterator.
Remarks:
This patch drops CRTP and iterator_facade_base for simplicity. For
fairly simple forward iterators, iterator_facade_base doesn't buy us
much. We just have to write a few "using" directives and operator!=
manually.
StringMapIterBase has a SFINAE-based constructor to construct a
const iterator from a non-const one just like DenseMapIterator.
We now rely on compiler-generated copy and assignment operators.