From 1f404ec04d88dda3f263cd69f6015e3b7238614c Mon Sep 17 00:00:00 2001 From: Jakub Kuderski Date: Thu, 12 Feb 2026 14:05:20 -0500 Subject: [PATCH] [ADT] Allow member pointers in map_range and map_to_vector (#181154) 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 | 27 ++++++++++++++++++++ llvm/unittests/ADT/SmallVectorExtrasTest.cpp | 19 ++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 23da931a63de..74ad080b7bed 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -219,13 +219,13 @@ public: template , int> = 0> decltype(auto) operator()(Pn &&...Params) { - return (*Obj)(std::forward(Params)...); + return std::invoke(*Obj, std::forward(Params)...); } template , int> = 0> decltype(auto) operator()(Pn &&...Params) const { - return (*Obj)(std::forward(Params)...); + return std::invoke(*Obj, std::forward(Params)...); } bool valid() const { return Obj != std::nullopt; } @@ -330,7 +330,7 @@ template auto drop_end(T &&RangeOrContainer, size_t N = 1) { template ()(*std::declval()))> + std::invoke_result_t())>> class mapped_iterator : public iterator_adaptor_base< mapped_iterator, ItTy, @@ -360,6 +360,8 @@ inline mapped_iterator map_iterator(ItTy I, FuncTy F) { return mapped_iterator(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 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 061293fae083..2727fdd66e85 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 auto map_to_vector(ContainerTy &&C, FuncTy &&F) { return to_vector( @@ -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 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 fe71945e4a79..cb59c6d9d1ca 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -835,6 +835,22 @@ TEST(STLExtrasTest, DropEndDefaultTest) { EXPECT_THAT(drop_end(vec), ElementsAre(0, 1, 2, 3)); } +TEST(STLExtrasTest, CallableMemberPointer) { + struct S { + int X; + int getX() const { return X; } + }; + S Obj{42}; + + // Data member pointer. + callable_detail::Callable DataMember(&S::X); + EXPECT_EQ(DataMember(Obj), 42); + + // Member function pointer. + callable_detail::Callable MemFn(&S::getX); + EXPECT_EQ(MemFn(Obj), 42); +} + TEST(STLExtrasTest, MapRangeTest) { SmallVector Vec{0, 1, 2}; EXPECT_THAT(map_range(Vec, [](int V) { return V + 1; }), @@ -845,6 +861,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 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 467eb13ac390..16c313d57ad5 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 Numbers = {1, 2, 3}; + auto Doubled = map_to_vector(Numbers, [](int X) { return X * 2; }); + EXPECT_THAT(Doubled, ElementsAre(2, 4, 6)); + + // Member pointer. + struct MapToVectorStruct { + int X; + int getX() const { return X; } + }; + std::vector Structs = {{1}, {2}, {3}}; + EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::X), + ElementsAre(1, 2, 3)); + + // Member function pointer. + EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::getX), + ElementsAre(1, 2, 3)); +} + TEST(SmallVectorExtrasTest, FilterToVector) { std::vector Numbers = {0, 1, 2, 3, 4}; auto Odd = filter_to_vector<2>(Numbers, [](int X) { return (X % 2) != 0; });