llvm.org GIT mirror llvm / 3e3f160
Merging r278573 (and r277399, r278157, r278569): ------------------------------------------------------------------------ r278573 | timshen | 2016-08-12 15:47:13 -0700 (Fri, 12 Aug 2016) | 8 lines [LoopVectorize] Detect loops in the innermost loop before creating InnerLoopVectorizer InnerLoopVectorizer shouldn't handle a loop with cycles inside the loop body, even if that cycle isn't a natural loop. Fixes PR28541. Differential Revision: https://reviews.llvm.org/D22952 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r277399 | timshen | 2016-08-01 15:32:20 -0700 (Mon, 01 Aug 2016) | 9 lines [ADT] NFC: Generalize GraphTraits requirement of "NodeType *" in interfaces to "NodeRef", and migrate SCCIterator.h to use NodeRef Summary: By generalize the interface, users are able to inject more flexible Node token into the algorithm, for example, a pair of vector<Node>* and index integer. Currently I only migrated SCCIterator to use NodeRef, but more is coming. It's a NFC. Reviewers: dblaikie, chandlerc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D22937 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r278157 | timshen | 2016-08-09 13:23:13 -0700 (Tue, 09 Aug 2016) | 7 lines [ADT] Change iterator_adaptor_base's default template arguments to forward more underlying typedefs Reviewers: chandlerc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D23217 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r278569 | timshen | 2016-08-12 15:03:28 -0700 (Fri, 12 Aug 2016) | 3 lines [ADT] Add filter_iterator for filtering elements Differential Revision: https://reviews.llvm.org/D22951 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_39@278674 91177308-0d34-0410-b5e6-96231b3b80d8 Hans Wennborg 4 years ago
13 changed file(s) with 387 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
2626 struct GraphTraits {
2727 // Elements to provide:
2828
29 // NOTICE: We are in a transition from migration interfaces that require
30 // NodeType *, to NodeRef. NodeRef is required to be cheap to copy, but does
31 // not have to be a raw pointer. In the transition, user should define
32 // NodeType, and NodeRef = NodeType *.
33 //
2934 // typedef NodeType - Type of Node in the graph
35 // typedef NodeRef - NodeType *
3036 // typedef ChildIteratorType - Type used to iterate over children in graph
3137
32 // static NodeType *getEntryNode(const GraphType &)
38 // static NodeRef getEntryNode(const GraphType &)
3339 // Return the entry node of the graph
3440
35 // static ChildIteratorType child_begin(NodeType *)
36 // static ChildIteratorType child_end (NodeType *)
41 // static ChildIteratorType child_begin(NodeRef)
42 // static ChildIteratorType child_end (NodeRef)
3743 // Return iterators that point to the beginning and ending of the child
3844 // node list for the specified node.
3945 //
40
4146
4247 // typedef ...iterator nodes_iterator;
4348 // static nodes_iterator nodes_begin(GraphType *G)
5661 // your argument to XXX_begin(...) is unknown or needs to have the proper .h
5762 // file #include'd.
5863 //
59 typedef typename GraphType::UnknownGraphTypeError NodeType;
64 typedef typename GraphType::UnknownGraphTypeError NodeRef;
6065 };
6166
6267
3636 /// build up a vector of nodes in a particular SCC. Note that it is a forward
3737 /// iterator and thus you cannot backtrack or re-visit nodes.
3838 template >
39 class scc_iterator
40 : public iterator_facade_base<
41 scc_iterator, std::forward_iterator_tag,
42 const std::vector, ptrdiff_t> {
43 typedef typename GT::NodeType NodeType;
39 class scc_iterator : public iterator_facade_base<
40 scc_iterator, std::forward_iterator_tag,
41 const std::vector, ptrdiff_t> {
42 typedef typename GT::NodeRef NodeRef;
4443 typedef typename GT::ChildIteratorType ChildItTy;
45 typedef std::vectorType *> SccTy;
44 typedef std::vectorRef> SccTy;
4645 typedef typename scc_iterator::reference reference;
4746
4847 /// Element of VisitStack during DFS.
4948 struct StackElement {
50 NodeType *Node; ///< The current node pointer.
49 NodeRef Node; ///< The current node pointer.
5150 ChildItTy NextChild; ///< The next child, modified inplace during DFS.
5251 unsigned MinVisited; ///< Minimum uplink value of all children of Node.
5352
54 StackElement(NodeType *Node, const ChildItTy &Child, unsigned Min)
55 : Node(Node), NextChild(Child), MinVisited(Min) {}
53 StackElement(NodeRef Node, const ChildItTy &Child, unsigned Min)
54 : Node(Node), NextChild(Child), MinVisited(Min) {}
5655
5756 bool operator==(const StackElement &Other) const {
5857 return Node == Other.Node &&
6665 ///
6766 /// nodeVisitNumbers are per-node visit numbers, also used as DFS flags.
6867 unsigned visitNum;
69 DenseMapType *, unsigned> nodeVisitNumbers;
68 DenseMapRef, unsigned> nodeVisitNumbers;
7069
7170 /// Stack holding nodes of the SCC.
72 std::vectorType *> SCCNodeStack;
71 std::vectorRef> SCCNodeStack;
7372
7473 /// The current SCC, retrieved using operator*().
7574 SccTy CurrentSCC;
7978 std::vector VisitStack;
8079
8180 /// A single "visit" within the non-recursive DFS traversal.
82 void DFSVisitOne(NodeType *N);
81 void DFSVisitOne(NodeRef N);
8382
8483 /// The stack-based DFS traversal; defined below.
8584 void DFSVisitChildren();
8786 /// Compute the next SCC using the DFS traversal.
8887 void GetNextSCC();
8988
90 scc_iterator(NodeType *entryN) : visitNum(0) {
89 scc_iterator(NodeRef entryN) : visitNum(0) {
9190 DFSVisitOne(entryN);
9291 GetNextSCC();
9392 }
130129
131130 /// This informs the \c scc_iterator that the specified \c Old node
132131 /// has been deleted, and \c New is to be used in its place.
133 void ReplaceNode(NodeType *Old, NodeType *New) {
132 void ReplaceNode(NodeRef Old, NodeRef New) {
134133 assert(nodeVisitNumbers.count(Old) && "Old not in scc_iterator?");
135134 nodeVisitNumbers[New] = nodeVisitNumbers[Old];
136135 nodeVisitNumbers.erase(Old);
138137 };
139138
140139 template
141 void scc_iterator::DFSVisitOne(NodeType *N) {
140 void scc_iterator::DFSVisitOne(NodeRef N) {
142141 ++visitNum;
143142 nodeVisitNumbers[N] = visitNum;
144143 SCCNodeStack.push_back(N);
154153 assert(!VisitStack.empty());
155154 while (VisitStack.back().NextChild != GT::child_end(VisitStack.back().Node)) {
156155 // TOS has at least one more child so continue DFS
157 NodeType *childN = *VisitStack.back().NextChild++;
158 typename DenseMap::iterator Visited =
156 NodeRef childN = *VisitStack.back().NextChild++;
157 typename DenseMap::iterator Visited =
159158 nodeVisitNumbers.find(childN);
160159 if (Visited == nodeVisitNumbers.end()) {
161160 // this node has never been seen.
175174 DFSVisitChildren();
176175
177176 // Pop the leaf on top of the VisitStack.
178 NodeType *visitingN = VisitStack.back().Node;
177 NodeRef visitingN = VisitStack.back().Node;
179178 unsigned minVisitNum = VisitStack.back().MinVisited;
180179 assert(VisitStack.back().NextChild == GT::child_end(visitingN));
181180 VisitStack.pop_back();
211210 assert(!CurrentSCC.empty() && "Dereferencing END SCC iterator!");
212211 if (CurrentSCC.size() > 1)
213212 return true;
214 NodeType *N = CurrentSCC.front();
213 NodeRef N = CurrentSCC.front();
215214 for (ChildItTy CI = GT::child_begin(N), CE = GT::child_end(N); CI != CE;
216215 ++CI)
217216 if (*CI == N)
2525 #include
2626 #include // for std::pair
2727
28 #include "llvm/ADT/Optional.h"
29 #include "llvm/ADT/iterator.h"
2830 #include "llvm/ADT/iterator_range.h"
2931 #include "llvm/Support/Compiler.h"
3032
3133 namespace llvm {
34 namespace detail {
35
36 template
37 using IterOfRange = decltype(std::begin(std::declval()));
38
39 } // End detail namespace
3240
3341 //===----------------------------------------------------------------------===//
3442 // Extra additions to
234242 llvm::make_reverse_iterator(std::begin(C)));
235243 }
236244
245 /// An iterator adaptor that filters the elements of given inner iterators.
246 ///
247 /// The predicate parameter should be a callable object that accepts the wrapped
248 /// iterator's reference type and returns a bool. When incrementing or
249 /// decrementing the iterator, it will call the predicate on each element and
250 /// skip any where it returns false.
251 ///
252 /// \code
253 /// int A[] = { 1, 2, 3, 4 };
254 /// auto R = make_filter_range(A, [](int N) { return N % 2 == 1; });
255 /// // R contains { 1, 3 }.
256 /// \endcode
257 template
258 class filter_iterator
259 : public iterator_adaptor_base<
260 filter_iterator, WrappedIteratorT,
261 typename std::common_type<
262 std::forward_iterator_tag,
263 typename std::iterator_traits<
264 WrappedIteratorT>::iterator_category>::type> {
265 using BaseT = iterator_adaptor_base<
266 filter_iterator, WrappedIteratorT,
267 typename std::common_type<
268 std::forward_iterator_tag,
269 typename std::iterator_traits::iterator_category>::
270 type>;
271
272 struct PayloadType {
273 WrappedIteratorT End;
274 PredicateT Pred;
275 };
276
277 Optional Payload;
278
279 void findNextValid() {
280 assert(Payload && "Payload should be engaged when findNextValid is called");
281 while (this->I != Payload->End && !Payload->Pred(*this->I))
282 BaseT::operator++();
283 }
284
285 // Construct the begin iterator. The begin iterator requires to know where end
286 // is, so that it can properly stop when it hits end.
287 filter_iterator(WrappedIteratorT Begin, WrappedIteratorT End, PredicateT Pred)
288 : BaseT(std::move(Begin)),
289 Payload(PayloadType{std::move(End), std::move(Pred)}) {
290 findNextValid();
291 }
292
293 // Construct the end iterator. It's not incrementable, so Payload doesn't
294 // have to be engaged.
295 filter_iterator(WrappedIteratorT End) : BaseT(End) {}
296
297 public:
298 using BaseT::operator++;
299
300 filter_iterator &operator++() {
301 BaseT::operator++();
302 findNextValid();
303 return *this;
304 }
305
306 template
307 friend iterator_range, PT>>
308 make_filter_range(RT &&, PT);
309 };
310
311 /// Convenience function that takes a range of elements and a predicate,
312 /// and return a new filter_iterator range.
313 ///
314 /// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the
315 /// lifetime of that temporary is not kept by the returned range object, and the
316 /// temporary is going to be dropped on the floor after the make_iterator_range
317 /// full expression that contains this function call.
318 template
319 iterator_range, PredicateT>>
320 make_filter_range(RangeT &&Range, PredicateT Pred) {
321 using FilterIteratorT =
322 filter_iterator, PredicateT>;
323 return make_range(FilterIteratorT(std::begin(std::forward(Range)),
324 std::end(std::forward(Range)),
325 std::move(Pred)),
326 FilterIteratorT(std::end(std::forward(Range))));
327 }
328
237329 //===----------------------------------------------------------------------===//
238330 // Extra additions to
239331 //===----------------------------------------------------------------------===//
154154 typename T = typename std::iterator_traits::value_type,
155155 typename DifferenceTypeT =
156156 typename std::iterator_traits::difference_type,
157 typename PointerT = T *, typename ReferenceT = T &,
157 typename PointerT = typename std::conditional<
158 std::is_same
159 WrappedIteratorT>::value_type>::value,
160 typename std::iterator_traits::pointer, T *>::type,
161 typename ReferenceT = typename std::conditional<
162 std::is_same
163 WrappedIteratorT>::value_type>::value,
164 typename std::iterator_traits::reference, T &>::type,
158165 // Don't provide these, they are mostly to act as aliases below.
159166 typename WrappedTraitsT = std::iterator_traits>
160167 class iterator_adaptor_base
167174
168175 iterator_adaptor_base() = default;
169176
170 template
171 explicit iterator_adaptor_base(
172 U &&u,
173 typename std::enable_if<
174 !std::is_base_of
175 typename std::remove_reference::type>::type,
176 DerivedT>::value,
177 int>::type = 0)
178 : I(std::forward(u)) {}
177 explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {}
179178
180179 const WrappedIteratorT &wrapped() const { return I; }
181180
409409 // traversals.
410410 template <> struct GraphTraits {
411411 typedef CallGraphNode NodeType;
412 typedef CallGraphNode *NodeRef;
412413
413414 typedef CallGraphNode::CallRecord CGNPairTy;
414415 typedef std::pointer_to_unary_function
430431
431432 template <> struct GraphTraits {
432433 typedef const CallGraphNode NodeType;
434 typedef const CallGraphNode *NodeRef;
433435
434436 typedef CallGraphNode::CallRecord CGNPairTy;
435437 typedef std::pointer_to_unary_function
739739
740740 template <> struct GraphTraits {
741741 typedef MachineBasicBlock NodeType;
742 typedef MachineBasicBlock *NodeRef;
742743 typedef MachineBasicBlock::succ_iterator ChildIteratorType;
743744
744745 static NodeType *getEntryNode(MachineBasicBlock *BB) { return BB; }
752753
753754 template <> struct GraphTraits {
754755 typedef const MachineBasicBlock NodeType;
756 typedef const MachineBasicBlock *NodeRef;
755757 typedef MachineBasicBlock::const_succ_iterator ChildIteratorType;
756758
757759 static NodeType *getEntryNode(const MachineBasicBlock *BB) { return BB; }
771773 //
772774 template <> struct GraphTraits > {
773775 typedef MachineBasicBlock NodeType;
776 typedef MachineBasicBlock *NodeRef;
774777 typedef MachineBasicBlock::pred_iterator ChildIteratorType;
775778 static NodeType *getEntryNode(Inverse G) {
776779 return G.Graph;
785788
786789 template <> struct GraphTraits > {
787790 typedef const MachineBasicBlock NodeType;
791 typedef const MachineBasicBlock *NodeRef;
788792 typedef MachineBasicBlock::const_pred_iterator ChildIteratorType;
789793 static NodeType *getEntryNode(Inverse G) {
790794 return G.Graph;
154154
155155 template <> struct GraphTraits {
156156 typedef BasicBlock NodeType;
157 typedef BasicBlock *NodeRef;
157158 typedef succ_iterator ChildIteratorType;
158159
159160 static NodeType *getEntryNode(BasicBlock *BB) { return BB; }
167168
168169 template <> struct GraphTraits {
169170 typedef const BasicBlock NodeType;
171 typedef const BasicBlock *NodeRef;
170172 typedef succ_const_iterator ChildIteratorType;
171173
172174 static NodeType *getEntryNode(const BasicBlock *BB) { return BB; }
186188 //
187189 template <> struct GraphTraits > {
188190 typedef BasicBlock NodeType;
191 typedef BasicBlock *NodeRef;
189192 typedef pred_iterator ChildIteratorType;
190193 static NodeType *getEntryNode(Inverse G) { return G.Graph; }
191194 static inline ChildIteratorType child_begin(NodeType *N) {
198201
199202 template <> struct GraphTraits > {
200203 typedef const BasicBlock NodeType;
204 typedef const BasicBlock *NodeRef;
201205 typedef const_pred_iterator ChildIteratorType;
202206 static NodeType *getEntryNode(Inverse G) {
203207 return G.Graph;
622622 typedef bfi_detail::IrreducibleGraph GraphT;
623623
624624 typedef const GraphT::IrrNode NodeType;
625 typedef const GraphT::IrrNode *NodeRef;
625626 typedef GraphT::IrrNode::iterator ChildIteratorType;
626627
627628 static const NodeType *getEntryNode(const GraphT &G) {
331331 namespace llvm {
332332 template <> struct GraphTraits {
333333 typedef ArgumentGraphNode NodeType;
334 typedef ArgumentGraphNode *NodeRef;
334335 typedef SmallVectorImpl::iterator ChildIteratorType;
335336
336337 static inline NodeType *getEntryNode(NodeType *A) { return A; }
4949 #include "llvm/ADT/DenseMap.h"
5050 #include "llvm/ADT/Hashing.h"
5151 #include "llvm/ADT/MapVector.h"
52 #include "llvm/ADT/SCCIterator.h"
5253 #include "llvm/ADT/SetVector.h"
5354 #include "llvm/ADT/SmallPtrSet.h"
5455 #include "llvm/ADT/SmallSet.h"
219220 class LoopVectorizationCostModel;
220221 class LoopVectorizationRequirements;
221222
223 // A traits type that is intended to be used in graph algorithms. The graph it
224 // models starts at the loop header, and traverses the BasicBlocks that are in
225 // the loop body, but not the loop header. Since the loop header is skipped,
226 // the back edges are excluded.
227 struct LoopBodyTraits {
228 using NodeRef = std::pair;
229
230 // This wraps a const Loop * into the iterator, so we know which edges to
231 // filter out.
232 class WrappedSuccIterator
233 : public iterator_adaptor_base<
234 WrappedSuccIterator, succ_iterator,
235 typename std::iterator_traits::iterator_category,
236 NodeRef, std::ptrdiff_t, NodeRef *, NodeRef> {
237 using BaseT = iterator_adaptor_base<
238 WrappedSuccIterator, succ_iterator,
239 typename std::iterator_traits::iterator_category,
240 NodeRef, std::ptrdiff_t, NodeRef *, NodeRef>;
241
242 const Loop *L;
243
244 public:
245 WrappedSuccIterator(succ_iterator Begin, const Loop *L)
246 : BaseT(Begin), L(L) {}
247
248 NodeRef operator*() const { return {L, *I}; }
249 };
250
251 struct LoopBodyFilter {
252 bool operator()(NodeRef N) const {
253 const Loop *L = N.first;
254 return N.second != L->getHeader() && L->contains(N.second);
255 }
256 };
257
258 using ChildIteratorType =
259 filter_iterator;
260
261 static NodeRef getEntryNode(const Loop &G) { return {&G, G.getHeader()}; }
262
263 static ChildIteratorType child_begin(NodeRef Node) {
264 return make_filter_range(make_range(
265 {succ_begin(Node.second), Node.first},
266 {succ_end(Node.second), Node.first}),
267 LoopBodyFilter{})
268 .begin();
269 }
270
271 static ChildIteratorType child_end(NodeRef Node) {
272 return make_filter_range(make_range(
273 {succ_begin(Node.second), Node.first},
274 {succ_end(Node.second), Node.first}),
275 LoopBodyFilter{})
276 .end();
277 }
278 };
279
280 /// Returns true if the given loop body has a cycle, excluding the loop
281 /// itself.
282 static bool hasCyclesInLoopBody(const Loop &L) {
283 if (!L.empty())
284 return true;
285
286 for (const auto SCC :
287 make_range(scc_iterator::begin(L),
288 scc_iterator::end(L))) {
289 if (SCC.size() > 1) {
290 DEBUG(dbgs() << "LVL: Detected a cycle in the loop body:\n");
291 DEBUG(L.dump());
292 return true;
293 }
294 }
295 return false;
296 }
297
222298 /// \brief This modifies LoopAccessReport to initialize message with
223299 /// loop-vectorizer-specific part.
224300 class VectorizationReport : public LoopAccessReport {
17811857 Instruction *UnsafeAlgebraInst;
17821858 };
17831859
1784 static void addInnerLoop(Loop &L, SmallVectorImpl &V) {
1785 if (L.empty())
1786 return V.push_back(&L);
1787
1860 static void addAcyclicInnerLoop(Loop &L, SmallVectorImpl &V) {
1861 if (L.empty()) {
1862 if (!hasCyclesInLoopBody(L))
1863 V.push_back(&L);
1864 return;
1865 }
17881866 for (Loop *InnerL : L)
1789 addInnerLoop(*InnerL, V);
1867 addAcyclicInnerLoop(*InnerL, V);
17901868 }
17911869
17921870 /// The LoopVectorize Pass.
43944472 return false;
43954473 }
43964474
4475 // FIXME: The code is currently dead, since the loop gets sent to
4476 // LoopVectorizationLegality is already an innermost loop.
4477 //
43974478 // We can only vectorize innermost loops.
43984479 if (!TheLoop->empty()) {
43994480 emitAnalysis(VectorizationReport() << "loop is not the innermost loop");
66386719 SmallVector Worklist;
66396720
66406721 for (Loop *L : *LI)
6641 addInnerLoop(*L, Worklist);
6722 addAcyclicInnerLoop(*L, Worklist);
66426723
66436724 LoopsAnalyzed += Worklist.size();
66446725
0 ; RUN: opt -loop-vectorize -pass-remarks=loop-vectorize -S < %s 2>&1 | FileCheck %s
1
2 ; FIXME: Check for -pass-remarks-missed and -pass-remarks-analysis output when
3 ; addAcyclicInnerLoop emits analysis.
4
5 ; Check that opt does not crash on such input:
6 ;
7 ; a, b, c;
8 ; fn1() {
9 ; while (b--) {
10 ; c = a;
11 ; switch (a & 3)
12 ; case 0:
13 ; do
14 ; case 3:
15 ; case 2:
16 ; case 1:
17 ; ;
18 ; while (--c)
19 ; ;
20 ; }
21 ; }
22
23 @b = common global i32 0, align 4
24 @a = common global i32 0, align 4
25 @c = common global i32 0, align 4
26
27 ; CHECK-NOT: vectorized loop
28 ; CHECK-LABEL: fn1
29
30 define i32 @fn1() {
31 entry:
32 %tmp2 = load i32, i32* @b, align 4
33 %dec3 = add nsw i32 %tmp2, -1
34 store i32 %dec3, i32* @b, align 4
35 %tobool4 = icmp eq i32 %tmp2, 0
36 br i1 %tobool4, label %while.end, label %while.body.lr.ph
37
38 while.body.lr.ph: ; preds = %entry
39 %tmp1 = load i32, i32* @a, align 4
40 %and = and i32 %tmp1, 3
41 %switch = icmp eq i32 %and, 0
42 br label %while.body
43
44 while.cond: ; preds = %do.cond
45 %dec = add nsw i32 %dec7, -1
46 %tobool = icmp eq i32 %dec7, 0
47 br i1 %tobool, label %while.cond.while.end_crit_edge, label %while.body
48
49 while.body: ; preds = %while.body.lr.ph, %while.cond
50 %dec7 = phi i32 [ %dec3, %while.body.lr.ph ], [ %dec, %while.cond ]
51 br i1 %switch, label %do.body, label %do.cond
52
53 do.body: ; preds = %do.cond, %while.body
54 %dec25 = phi i32 [ %dec2, %do.cond ], [ %tmp1, %while.body ]
55 br label %do.cond
56
57 do.cond: ; preds = %do.body, %while.body
58 %dec26 = phi i32 [ %dec25, %do.body ], [ %tmp1, %while.body ]
59 %dec2 = add nsw i32 %dec26, -1
60 %tobool3 = icmp eq i32 %dec2, 0
61 br i1 %tobool3, label %while.cond, label %do.body
62
63 while.cond.while.end_crit_edge: ; preds = %while.cond
64 store i32 0, i32* @c, align 4
65 store i32 -1, i32* @b, align 4
66 br label %while.end
67
68 while.end: ; preds = %while.cond.while.end_crit_edge, %entry
69 ret i32 undef
70 }
229229 template
230230 struct GraphTraits > {
231231 typedef typename Graph::NodeType NodeType;
232 typedef typename Graph::NodeType *NodeRef;
232233 typedef typename Graph::ChildIterator ChildIteratorType;
233234
234235 static inline NodeType *getEntryNode(const Graph &G) { return G.AccessNode(0); }
1414 using namespace llvm;
1515
1616 namespace {
17
18 template struct Shadow;
19
20 struct WeirdIter : std::iterator, Shadow<1>,
21 Shadow<2>, Shadow<3>> {};
22
23 struct AdaptedIter : iterator_adaptor_base {};
24
25 // Test that iterator_adaptor_base forwards typedefs, if value_type is
26 // unchanged.
27 static_assert(std::is_same>::value,
28 "");
29 static_assert(
30 std::is_same>::value, "");
31 static_assert(std::is_same>::value,
32 "");
33 static_assert(std::is_same>::value,
34 "");
1735
1836 TEST(PointeeIteratorTest, Basic) {
1937 int arr[4] = { 1, 2, 3, 4 };
97115 EXPECT_EQ(End, I);
98116 }
99117
118 TEST(FilterIteratorTest, Lambda) {
119 auto IsOdd = [](int N) { return N % 2 == 1; };
120 int A[] = {0, 1, 2, 3, 4, 5, 6};
121 auto Range = make_filter_range(A, IsOdd);
122 SmallVector Actual(Range.begin(), Range.end());
123 EXPECT_EQ((SmallVector{1, 3, 5}), Actual);
124 }
125
126 TEST(FilterIteratorTest, CallableObject) {
127 int Counter = 0;
128 struct Callable {
129 int &Counter;
130
131 Callable(int &Counter) : Counter(Counter) {}
132
133 bool operator()(int N) {
134 Counter++;
135 return N % 2 == 1;
136 }
137 };
138 Callable IsOdd(Counter);
139 int A[] = {0, 1, 2, 3, 4, 5, 6};
140 auto Range = make_filter_range(A, IsOdd);
141 EXPECT_EQ(2, Counter);
142 SmallVector Actual(Range.begin(), Range.end());
143 EXPECT_GE(Counter, 7);
144 EXPECT_EQ((SmallVector{1, 3, 5}), Actual);
145 }
146
147 TEST(FilterIteratorTest, FunctionPointer) {
148 bool (*IsOdd)(int) = [](int N) { return N % 2 == 1; };
149 int A[] = {0, 1, 2, 3, 4, 5, 6};
150 auto Range = make_filter_range(A, IsOdd);
151 SmallVector Actual(Range.begin(), Range.end());
152 EXPECT_EQ((SmallVector{1, 3, 5}), Actual);
153 }
154
155 TEST(FilterIteratorTest, Composition) {
156 auto IsOdd = [](int N) { return N % 2 == 1; };
157 std::unique_ptr A[] = {make_unique(0), make_unique(1),
158 make_unique(2), make_unique(3),
159 make_unique(4), make_unique(5),
160 make_unique(6)};
161 using PointeeIterator = pointee_iterator *>;
162 auto Range = make_filter_range(
163 make_range(PointeeIterator(std::begin(A)), PointeeIterator(std::end(A))),
164 IsOdd);
165 SmallVector Actual(Range.begin(), Range.end());
166 EXPECT_EQ((SmallVector{1, 3, 5}), Actual);
167 }
168
169 TEST(FilterIteratorTest, InputIterator) {
170 struct InputIterator
171 : iterator_adaptor_base {
172 using BaseT =
173 iterator_adaptor_base;
174
175 InputIterator(int *It) : BaseT(It) {}
176 };
177
178 auto IsOdd = [](int N) { return N % 2 == 1; };
179 int A[] = {0, 1, 2, 3, 4, 5, 6};
180 auto Range = make_filter_range(
181 make_range(InputIterator(std::begin(A)), InputIterator(std::end(A))),
182 IsOdd);
183 SmallVector Actual(Range.begin(), Range.end());
184 EXPECT_EQ((SmallVector{1, 3, 5}), Actual);
185 }
186
100187 } // anonymous namespace