Index: llvm/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/include/llvm/ADT/STLExtras.h +++ llvm/include/llvm/ADT/STLExtras.h @@ -283,24 +283,62 @@ // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. +// Using two different implementations: for functions which return a reference +// type, and functions which do not +template ()(*std::declval()))>::value> +class mapped_iterator; + +// Base class for both implementations template ()(*std::declval()))> -class mapped_iterator + decltype(std::declval()(*std::declval()))> +class mapped_iterator_base : public iterator_adaptor_base< - mapped_iterator, ItTy, - typename std::iterator_traits::iterator_category, - typename std::remove_reference::type> { + mapped_iterator, ItTy, + typename std::iterator_traits::iterator_category, + typename std::remove_reference::type> { public: - mapped_iterator(ItTy U, FuncTy F) - : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {} + mapped_iterator_base(ItTy U, FuncTy F) + : mapped_iterator_base::iterator_adaptor_base(std::move(U)), + F(std::move(F)) {} ItTy getCurrent() { return this->I; } - FuncReturnTy operator*() const { return F(*this->I); } +protected: + FuncTy F; +}; + +// Implementation for reference return type: operator* could simply return the +// reference +template +class mapped_iterator + : public mapped_iterator_base { +public: + using mapped_iterator::mapped_iterator_base::mapped_iterator_base; + + typename mapped_iterator::mapped_iterator_base::reference operator*() const { + return this->F(*this->I); + } +}; + +// Implementation for non-reference return type: hold the function's return +// value in a member variable to make operator* be able to return a reference +// value +template +class mapped_iterator + : public mapped_iterator_base { +public: + using mapped_iterator::mapped_iterator_base::mapped_iterator_base; + + typename mapped_iterator::mapped_iterator_base::reference operator*() const { + V = this->F(*this->I); + return V; + } private: - FuncTy F; + mutable typename mapped_iterator::mapped_iterator_base::value_type V; }; // map_iterator - Provide a convenient way to create mapped_iterators, just like Index: llvm/unittests/ADT/MappedIteratorTest.cpp =================================================================== --- llvm/unittests/ADT/MappedIteratorTest.cpp +++ llvm/unittests/ADT/MappedIteratorTest.cpp @@ -47,4 +47,17 @@ EXPECT_EQ(M[1], 42) << "assignment should have modified M"; } +TEST(MappedIteratorTest, MappedRangeCouldBeReversed) { + std::vector V({1, 2, 3}); + + auto R1 = map_range(V, [](int N) { return N + 1; }); // {1, 2, 3} -> {2, 3, 4} + auto R2 = reverse(R1); // {2, 3, 4} -> {4, 3, 2} + + int Val1 = *R1.begin(); // == 2 + int Val2 = *R2.begin(); // == 4 + + EXPECT_EQ(Val1, 2) << "mapped array should start from 2"; + EXPECT_EQ(Val2, 4) << "reversed array should start from 4"; +} + } // anonymous namespace Index: llvm/unittests/Analysis/CallGraphTest.cpp =================================================================== --- llvm/unittests/Analysis/CallGraphTest.cpp +++ llvm/unittests/Analysis/CallGraphTest.cpp @@ -23,11 +23,11 @@ auto X = ++I; // Should be able to iterate over all nodes of the graph. - static_assert(std::is_same::value, + static_assert(std::is_same::value, "Node type does not match"); - static_assert(std::is_same::value, + static_assert(std::is_same::value, "Node type does not match"); - static_assert(std::is_same::value, + static_assert(std::is_same::value, "Node type does not match"); NodeRef N = GraphTraits::getEntryNode(G); @@ -36,9 +36,9 @@ auto F = GraphTraits::child_end(N); // Should be able to iterate over immediate successors of a node. - static_assert(std::is_same::value, + static_assert(std::is_same::value, "Node type does not match"); - static_assert(std::is_same::value, + static_assert(std::is_same::value, "Node type does not match"); }