[llvm] [ADT] Allow member pointers in map_range and map_to_vector (PR #181154)

Jakub Kuderski via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 12 06:40:30 PST 2026


https://github.com/kuhar updated https://github.com/llvm/llvm-project/pull/181154

>From a43a5d27cb88663e96237423fb45657e131f5e78 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Thu, 12 Feb 2026 09:33:24 -0500
Subject: [PATCH 1/3] [ADT] Allow member pointers in map_range and
 map_to_vector

This is for when all we need is to access a field or call a getter:
no need to write a lambda just to extract these.

Assisted-by: claude
---
 llvm/include/llvm/ADT/STLExtras.h            |  8 ++++++--
 llvm/include/llvm/ADT/SmallVectorExtras.h    |  2 ++
 llvm/unittests/ADT/STLExtrasTest.cpp         | 11 +++++++++++
 llvm/unittests/ADT/SmallVectorExtrasTest.cpp | 19 +++++++++++++++++++
 4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 23da931a63de1..8f788f17df920 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -330,7 +330,7 @@ template <typename T> auto drop_end(T &&RangeOrContainer, size_t N = 1) {
 
 template <typename ItTy, typename FuncTy,
           typename ReferenceTy =
-              decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))>
+              std::invoke_result_t<FuncTy, decltype(*std::declval<ItTy>())>>
 class mapped_iterator
     : public iterator_adaptor_base<
           mapped_iterator<ItTy, FuncTy>, ItTy,
@@ -347,7 +347,9 @@ class mapped_iterator
 
   const FuncTy &getFunction() const { return F; }
 
-  ReferenceTy operator*() const { return F(*this->I); }
+  ReferenceTy operator*() const {
+    return llvm::invoke(getFunction(), *this->I);
+  }
 
 private:
   callable_detail::Callable<FuncTy> F{};
@@ -360,6 +362,8 @@ inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
   return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F));
 }
 
+/// Return a range that applies \p F to the elements of \p C. \p F can be a
+/// function, lambda, or member pointer.
 template <class ContainerTy, class FuncTy>
 auto map_range(ContainerTy &&C, FuncTy F) {
   return make_range(map_iterator(adl_begin(C), F), map_iterator(adl_end(C), F));
diff --git a/llvm/include/llvm/ADT/SmallVectorExtras.h b/llvm/include/llvm/ADT/SmallVectorExtras.h
index 061293fae0830..2727fdd66e852 100644
--- a/llvm/include/llvm/ADT/SmallVectorExtras.h
+++ b/llvm/include/llvm/ADT/SmallVectorExtras.h
@@ -34,6 +34,7 @@ auto filter_to_vector(ContainerTy &&C, PredicateFn &&Pred) {
 }
 
 /// Map a range to a SmallVector with element types deduced from the mapping.
+/// \p F can be a function, lambda, or member pointer.
 template <unsigned Size, class ContainerTy, class FuncTy>
 auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
   return to_vector<Size>(
@@ -41,6 +42,7 @@ auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
 }
 
 /// Map a range to a SmallVector with element types deduced from the mapping.
+/// \p F can be a function, lambda, or member pointer.
 template <class ContainerTy, class FuncTy>
 auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
   return to_vector(
diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp
index fe71945e4a794..0e72dce216d1f 100644
--- a/llvm/unittests/ADT/STLExtrasTest.cpp
+++ b/llvm/unittests/ADT/STLExtrasTest.cpp
@@ -845,6 +845,17 @@ TEST(STLExtrasTest, MapRangeTest) {
   some_namespace::some_struct S;
   S.data = {3, 4, 5};
   EXPECT_THAT(map_range(S, [](int V) { return V * 2; }), ElementsAre(6, 8, 10));
+
+  // Pointer to data member.
+  struct MapRangeStruct {
+    int X;
+    int getX() const { return X; }
+  };
+  std::vector<MapRangeStruct> Structs = {{1}, {2}, {3}};
+  EXPECT_THAT(map_range(Structs, &MapRangeStruct::X), ElementsAre(1, 2, 3));
+
+  // Pointer to member function.
+  EXPECT_THAT(map_range(Structs, &MapRangeStruct::getX), ElementsAre(1, 2, 3));
 }
 
 TEST(STLExtrasTest, EarlyIncrementTest) {
diff --git a/llvm/unittests/ADT/SmallVectorExtrasTest.cpp b/llvm/unittests/ADT/SmallVectorExtrasTest.cpp
index 467eb13ac390b..6799015afcc1c 100644
--- a/llvm/unittests/ADT/SmallVectorExtrasTest.cpp
+++ b/llvm/unittests/ADT/SmallVectorExtrasTest.cpp
@@ -22,6 +22,25 @@ using testing::ElementsAre;
 namespace llvm {
 namespace {
 
+TEST(SmallVectorExtrasTest, MapToVector) {
+  std::vector<int> Numbers = {1, 2, 3};
+  auto Doubled = map_to_vector(Numbers, [](int X) { return X * 2; });
+  EXPECT_THAT(Doubled, ElementsAre(2, 4, 6));
+
+  // Pointer to data member.
+  struct MapToVectorStruct {
+    int X;
+    int getX() const { return X; }
+  };
+  std::vector<MapToVectorStruct> Structs = {{1}, {2}, {3}};
+  EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::X),
+              ElementsAre(1, 2, 3));
+
+  // Pointer to member function.
+  EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::getX),
+              ElementsAre(1, 2, 3));
+}
+
 TEST(SmallVectorExtrasTest, FilterToVector) {
   std::vector<int> Numbers = {0, 1, 2, 3, 4};
   auto Odd = filter_to_vector<2>(Numbers, [](int X) { return (X % 2) != 0; });

>From ae4b329d1e7d2e50dd5ccad491a25de7be9a8f26 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Thu, 12 Feb 2026 09:38:16 -0500
Subject: [PATCH 2/3] Switch to std::invoke since we don't need constexpr

---
 llvm/include/llvm/ADT/STLExtras.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 8f788f17df920..b71e4cd05032c 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -348,7 +348,7 @@ class mapped_iterator
   const FuncTy &getFunction() const { return F; }
 
   ReferenceTy operator*() const {
-    return llvm::invoke(getFunction(), *this->I);
+    return std::invoke(getFunction(), *this->I);
   }
 
 private:

>From 1824cf9b903d3d18e8d9a6f459c83cbd4849c7ef Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Thu, 12 Feb 2026 09:40:18 -0500
Subject: [PATCH 3/3] Simplify

---
 llvm/include/llvm/ADT/STLExtras.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index b71e4cd05032c..5a21bdd3837be 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -347,9 +347,7 @@ class mapped_iterator
 
   const FuncTy &getFunction() const { return F; }
 
-  ReferenceTy operator*() const {
-    return std::invoke(getFunction(), *this->I);
-  }
+  ReferenceTy operator*() const { return std::invoke(F, *this->I); }
 
 private:
   callable_detail::Callable<FuncTy> F{};



More information about the llvm-commits mailing list