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

Reply via email to