Skip to content

Commit 43e7b7a

Browse files
committedNov 10, 2017
[ADT] Rewrite mapped_iterator in terms of iterator_adaptor_base.
Summary: This eliminates the boilerplate implementation of the iterator interface in mapped_iterator. This patch also adds unit tests that verify that the mapped function is applied by operator* and operator->, and that references returned by the map function are returned via operator*. Reviewers: dblaikie, chandlerc Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D39855 llvm-svn: 317902
1 parent 028d815 commit 43e7b7a

File tree

3 files changed

+68
-75
lines changed

3 files changed

+68
-75
lines changed
 

‎llvm/include/llvm/ADT/STLExtras.h

Lines changed: 16 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -132,91 +132,32 @@ inline void deleter(T *Ptr) {
132132

133133
// mapped_iterator - This is a simple iterator adapter that causes a function to
134134
// be applied whenever operator* is invoked on the iterator.
135-
template <class RootIt, class UnaryFunc>
136-
class mapped_iterator {
137-
RootIt current;
138-
UnaryFunc Fn;
139135

136+
template <typename ItTy, typename FuncTy,
137+
typename FuncReturnTy =
138+
decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))>
139+
class mapped_iterator
140+
: public iterator_adaptor_base<
141+
mapped_iterator<ItTy, FuncTy>, ItTy,
142+
typename std::iterator_traits<ItTy>::iterator_category,
143+
typename std::remove_reference<FuncReturnTy>::type> {
140144
public:
141-
using iterator_category =
142-
typename std::iterator_traits<RootIt>::iterator_category;
143-
using difference_type =
144-
typename std::iterator_traits<RootIt>::difference_type;
145-
using value_type =
146-
decltype(std::declval<UnaryFunc>()(*std::declval<RootIt>()));
147-
148-
using pointer = void;
149-
using reference = void; // Can't modify value returned by fn
150-
151-
using iterator_type = RootIt;
152-
153-
inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
154-
: current(I), Fn(F) {}
155-
156-
inline value_type operator*() const { // All this work to do this
157-
return Fn(*current); // little change
158-
}
159-
160-
mapped_iterator &operator++() {
161-
++current;
162-
return *this;
163-
}
164-
mapped_iterator &operator--() {
165-
--current;
166-
return *this;
167-
}
168-
mapped_iterator operator++(int) {
169-
mapped_iterator __tmp = *this;
170-
++current;
171-
return __tmp;
172-
}
173-
mapped_iterator operator--(int) {
174-
mapped_iterator __tmp = *this;
175-
--current;
176-
return __tmp;
177-
}
178-
mapped_iterator operator+(difference_type n) const {
179-
return mapped_iterator(current + n, Fn);
180-
}
181-
mapped_iterator &operator+=(difference_type n) {
182-
current += n;
183-
return *this;
184-
}
185-
mapped_iterator operator-(difference_type n) const {
186-
return mapped_iterator(current - n, Fn);
187-
}
188-
mapped_iterator &operator-=(difference_type n) {
189-
current -= n;
190-
return *this;
191-
}
192-
reference operator[](difference_type n) const { return *(*this + n); }
145+
mapped_iterator(ItTy U, FuncTy F)
146+
: mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {}
193147

194-
bool operator!=(const mapped_iterator &X) const { return !operator==(X); }
195-
bool operator==(const mapped_iterator &X) const {
196-
return current == X.current;
197-
}
198-
bool operator<(const mapped_iterator &X) const { return current < X.current; }
148+
ItTy getCurrent() { return this->I; }
199149

200-
difference_type operator-(const mapped_iterator &X) const {
201-
return current - X.current;
202-
}
150+
FuncReturnTy operator*() { return F(*this->I); }
203151

204-
inline const RootIt &getCurrent() const { return current; }
205-
inline const UnaryFunc &getFunc() const { return Fn; }
152+
private:
153+
FuncTy F;
206154
};
207155

208-
template <class Iterator, class Func>
209-
inline mapped_iterator<Iterator, Func>
210-
operator+(typename mapped_iterator<Iterator, Func>::difference_type N,
211-
const mapped_iterator<Iterator, Func> &X) {
212-
return mapped_iterator<Iterator, Func>(X.getCurrent() - N, X.getFunc());
213-
}
214-
215156
// map_iterator - Provide a convenient way to create mapped_iterators, just like
216157
// make_pair is useful for creating pairs...
217158
template <class ItTy, class FuncTy>
218-
inline mapped_iterator<ItTy, FuncTy> map_iterator(const ItTy &I, FuncTy F) {
219-
return mapped_iterator<ItTy, FuncTy>(I, F);
159+
inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
160+
return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F));
220161
}
221162

222163
/// Helper to determine if type T has a member called rbegin().

‎llvm/unittests/ADT/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ set(ADTSources
3232
IntrusiveRefCntPtrTest.cpp
3333
IteratorTest.cpp
3434
MakeUniqueTest.cpp
35+
MappedIteratorTest.cpp
3536
MapVectorTest.cpp
3637
OptionalTest.cpp
3738
PackedVectorTest.cpp
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "llvm/ADT/STLExtras.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace llvm;
14+
15+
namespace {
16+
17+
TEST(MappedIteratorTest, ApplyFunctionOnDereference) {
18+
std::vector<int> V({0});
19+
20+
auto I = map_iterator(V.begin(), [](int X) { return X + 1; });
21+
22+
EXPECT_EQ(*I, 1) << "should have applied function in dereference";
23+
}
24+
25+
TEST(MappedIteratorTest, ApplyFunctionOnArrow) {
26+
struct S {
27+
int Z = 0;
28+
};
29+
30+
std::vector<int> V({0});
31+
S Y;
32+
S* P = &Y;
33+
34+
auto I = map_iterator(V.begin(), [&](int X) -> S& { return *(P + X); });
35+
36+
I->Z = 42;
37+
38+
EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
39+
}
40+
41+
TEST(MappedIteratorTest, FunctionPreservesReferences) {
42+
std::vector<int> V({1});
43+
std::map<int, int> M({ {1, 1} });
44+
45+
auto I = map_iterator(V.begin(), [&](int X) -> int& { return M[X]; });
46+
*I = 42;
47+
48+
EXPECT_EQ(M[1], 42) << "assignment should have modified M";
49+
}
50+
51+
} // anonymous namespace

0 commit comments

Comments
 (0)
Please sign in to comment.