https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/156137
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. >From 2acfa1ad795eac48ea106ae2d0af2a398c9b3eb5 Mon Sep 17 00:00:00 2001 From: Kazu Hirata <k...@google.com> Date: Fri, 29 Aug 2025 13:56:48 -0700 Subject: [PATCH] [ADT] Refactor StringMap iterators (NFC) 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. --- .../fuchsia/MultipleInheritanceCheck.cpp | 2 +- clang/lib/Driver/OffloadBundler.cpp | 3 +- llvm/include/llvm/ADT/StringMap.h | 98 +++++++------------ 3 files changed, 39 insertions(+), 64 deletions(-) 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(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits