Index: llvm/trunk/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/trunk/include/llvm/ADT/STLExtras.h +++ llvm/trunk/include/llvm/ADT/STLExtras.h @@ -132,91 +132,32 @@ // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. -template -class mapped_iterator { - RootIt current; - UnaryFunc Fn; +template ()(*std::declval()))> +class mapped_iterator + : public iterator_adaptor_base< + mapped_iterator, ItTy, + typename std::iterator_traits::iterator_category, + typename std::remove_reference::type> { public: - using iterator_category = - typename std::iterator_traits::iterator_category; - using difference_type = - typename std::iterator_traits::difference_type; - using value_type = - decltype(std::declval()(*std::declval())); - - using pointer = void; - using reference = void; // Can't modify value returned by fn - - using iterator_type = RootIt; + mapped_iterator(ItTy U, FuncTy F) + : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {} - inline explicit mapped_iterator(const RootIt &I, UnaryFunc F) - : current(I), Fn(F) {} + ItTy getCurrent() { return this->I; } - inline value_type operator*() const { // All this work to do this - return Fn(*current); // little change - } + FuncReturnTy operator*() { return F(*this->I); } - mapped_iterator &operator++() { - ++current; - return *this; - } - mapped_iterator &operator--() { - --current; - return *this; - } - mapped_iterator operator++(int) { - mapped_iterator __tmp = *this; - ++current; - return __tmp; - } - mapped_iterator operator--(int) { - mapped_iterator __tmp = *this; - --current; - return __tmp; - } - mapped_iterator operator+(difference_type n) const { - return mapped_iterator(current + n, Fn); - } - mapped_iterator &operator+=(difference_type n) { - current += n; - return *this; - } - mapped_iterator operator-(difference_type n) const { - return mapped_iterator(current - n, Fn); - } - mapped_iterator &operator-=(difference_type n) { - current -= n; - return *this; - } - reference operator[](difference_type n) const { return *(*this + n); } - - bool operator!=(const mapped_iterator &X) const { return !operator==(X); } - bool operator==(const mapped_iterator &X) const { - return current == X.current; - } - bool operator<(const mapped_iterator &X) const { return current < X.current; } - - difference_type operator-(const mapped_iterator &X) const { - return current - X.current; - } - - inline const RootIt &getCurrent() const { return current; } - inline const UnaryFunc &getFunc() const { return Fn; } +private: + FuncTy F; }; -template -inline mapped_iterator -operator+(typename mapped_iterator::difference_type N, - const mapped_iterator &X) { - return mapped_iterator(X.getCurrent() - N, X.getFunc()); -} - // map_iterator - Provide a convenient way to create mapped_iterators, just like // make_pair is useful for creating pairs... template -inline mapped_iterator map_iterator(const ItTy &I, FuncTy F) { - return mapped_iterator(I, F); +inline mapped_iterator map_iterator(ItTy I, FuncTy F) { + return mapped_iterator(std::move(I), std::move(F)); } /// Helper to determine if type T has a member called rbegin(). Index: llvm/trunk/unittests/ADT/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/ADT/CMakeLists.txt +++ llvm/trunk/unittests/ADT/CMakeLists.txt @@ -32,6 +32,7 @@ IntrusiveRefCntPtrTest.cpp IteratorTest.cpp MakeUniqueTest.cpp + MappedIteratorTest.cpp MapVectorTest.cpp OptionalTest.cpp PackedVectorTest.cpp Index: llvm/trunk/unittests/ADT/MappedIteratorTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/MappedIteratorTest.cpp +++ llvm/trunk/unittests/ADT/MappedIteratorTest.cpp @@ -0,0 +1,51 @@ +//===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(MappedIteratorTest, ApplyFunctionOnDereference) { + std::vector V({0}); + + auto I = map_iterator(V.begin(), [](int X) { return X + 1; }); + + EXPECT_EQ(*I, 1) << "should have applied function in dereference"; +} + +TEST(MappedIteratorTest, ApplyFunctionOnArrow) { + struct S { + int Z = 0; + }; + + std::vector V({0}); + S Y; + S* P = &Y; + + auto I = map_iterator(V.begin(), [&](int X) -> S& { return *(P + X); }); + + I->Z = 42; + + EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow"; +} + +TEST(MappedIteratorTest, FunctionPreservesReferences) { + std::vector V({1}); + std::map M({ {1, 1} }); + + auto I = map_iterator(V.begin(), [&](int X) -> int& { return M[X]; }); + *I = 42; + + EXPECT_EQ(M[1], 42) << "assignment should have modified M"; +} + +} // anonymous namespace