Dune Core Modules (unstable)

iteratortest.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5
6#ifndef DUNE_COMMON_TEST_ITERATORTEST_HH
7#define DUNE_COMMON_TEST_ITERATORTEST_HH
8#include <iostream>
9#include <algorithm>
12
20template<class Iter, class Value>
21void testOutputIterator(Iter iterator, std::size_t iterations, Value value)
22{
23 // Test whether iterator is copy-constructible
24 // The new iterator object will go out of scope at the end of this method, and hence
25 // destructibility will also be tested.
26 Iter tmp1(iterator);
27
28 // Test whether iterator is copy-assignable
29 Iter tmp2 = iterator;
30
31 // Test whether pre-increment and assignment works
32 for (size_t i=0; i<iterations; ++i, ++tmp1)
33 // An output iterator can only be dereferenced as an lvalue (if in a dereferenceable state).
34 // It shall only be dereferenced as the left-side of an assignment statement.
35 *tmp1 = value;
36
37 // Test whether post-increment and assignment works
38 for (size_t i=0; i<iterations; ++i, tmp2++)
39 *tmp2 = value;
40
41 // Test whether std::iterator_traits is properly specialized
42 // The AlwaysTrue<A> construction allows one to test whether the type A exists at all,
43 // without assuming anything further about A.
45 "std::iterator_traits::difference_type is not defined!");
47 "std::iterator_traits::value_type is not defined!");
49 "std::iterator_traits::pointer is not defined!");
51 "std::iterator_traits::reference is not defined!");
52
53 // Make sure the iterator_category is properly set
54 static_assert(std::is_same<typename std::iterator_traits<Iter>::iterator_category, std::output_iterator_tag>::value,
55 "std::iterator_traits::iterator_category is not properly defined!");
56}
57
65template<class Iter, class Opt>
66int testForwardIterator(Iter begin, Iter end, Opt& opt)
67{
68 // Return status
69 int ret=0;
70
71 // Test whether iterator is can be value-initialized.
72 // These object will go out of scope at the end of this method, and hence
73 // it will also test whether these objects are destructible.
74 Iter defaultConstructedIterator1{}, defaultConstructedIterator2{};
75
76 // Since C++14, value-initialized forward iterators are specified as the
77 // end iterator of the same, empty sequence. Hence, they should compare equal.
78 // Notice that value-initialization and default-initialization are not the
79 // same for raw pointers. Since these are POD, value-initialization leads
80 // to zero-initialization while default-initialization would leave them
81 // uninitialized such that the comparison is undefined behaviour.
82 if (defaultConstructedIterator1 != defaultConstructedIterator2) {
83 std::cerr<<"Default constructed iterators do not compare equal for "+Dune::className<Iter>()+"."<<std::endl;
84 ret=1;
85 }
86
87 // Test whether iterator is copy-constructible
88 Iter tmp1(begin);
89
90 // Test whether iterator is copy-assignable
91 Iter tmp=begin;
92
93 // Test for inequality
94 if (tmp!=begin || tmp1!=begin || tmp!=tmp1) {
95 std::cerr<<" Copying iterator failed "<<__FILE__<<":"<<__LINE__<<std::endl;
96 ret=1;
97 }
98
99 // Test for equality
100 if (not (tmp==begin && tmp1==begin && tmp==tmp1)) {
101 std::cerr<<" Copying iterator failed "<<__FILE__<<":"<<__LINE__<<std::endl;
102 ret=1;
103 }
104
105 // Test whether pre-increment works
106 for(; begin!=end; ++begin)
107 // Test rvalue dereferencing
108 opt(*begin);
109
110 // Test whether post-increment works
111 for(; begin!=end; begin++)
112 opt(*begin);
113
114 // Test whether std::iterator_traits is properly specialized
115 // The is_same<A,A> construction allows one to test whether the type A exists at all,
116 // without assuming anything further about A.
117 static_assert(std::is_same<typename std::iterator_traits<Iter>::difference_type, typename std::iterator_traits<Iter>::difference_type>::value,
118 "std::iterator_traits::difference_type is not defined!");
119 static_assert(std::is_same<typename std::iterator_traits<Iter>::value_type, typename std::iterator_traits<Iter>::value_type>::value,
120 "std::iterator_traits::value_type is not defined!");
121 static_assert(std::is_same<typename std::iterator_traits<Iter>::pointer, typename std::iterator_traits<Iter>::pointer>::value,
122 "std::iterator_traits::pointer is not defined!");
123 static_assert(std::is_same<typename std::iterator_traits<Iter>::reference, typename std::iterator_traits<Iter>::reference>::value,
124 "std::iterator_traits::reference is not defined!");
125
126 // Make sure the iterator_category is properly set
127 static_assert(std::is_same<typename std::iterator_traits<Iter>::iterator_category, std::forward_iterator_tag>::value
128 or std::is_same<typename std::iterator_traits<Iter>::iterator_category, std::bidirectional_iterator_tag>::value
129 or std::is_same<typename std::iterator_traits<Iter>::iterator_category, std::random_access_iterator_tag>::value,
130 "std::iterator_traits::iterator_category is not properly defined!");
131
132 return ret;
133}
134
145template<class Iter, class Opt>
146int testBidirectionalIterator(Iter begin, Iter end, Opt opt)
147{
148 int ret=testForwardIterator(begin, end, opt);
149 for(Iter pre = end, post = end; pre != begin; )
150 {
151 if(pre != post--)
152 {
153 std::cerr << "Postdecrement did not return the old iterator"
154 << std::endl;
155 ++ret;
156 }
157 if(--pre != post)
158 {
159 std::cerr << "Predecrement did not return the new iterator"
160 << std::endl;
161 ++ret;
162 }
163 opt(*pre);
164 }
165
166 typename Iter::difference_type size = std::distance(begin, end);
167 srand(300);
168
169 int no= (size>10) ? 10 : size;
170
171 for(int i=0; i < no; i++)
172 {
173 int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
174 int backwards=size-index;
175 Iter tbegin = begin;
176 Iter tend = end;
177 for(int j=0; j < index; j++) ++tbegin;
178 for(int j=0; j < backwards; j++) --tend;
179
180 if(tbegin != tend)
181 {
182 std::cerr<<"Did not reach same index by starting forward from "
183 <<"begin and backwards from end."<<std::endl;
184 ++ret;
185 }
186 }
187 return ret;
188}
189
190template<class Iter, class Opt>
191int testRandomAccessIterator(Iter begin, Iter end, Opt opt){
192 int ret=testBidirectionalIterator(begin, end, opt);
193
194 typename Iter::difference_type size = end-begin;
195
196 srand(300);
197
198 int no= (size>10) ? 10 : size;
199
200 for(int i=0; i < no; i++)
201 {
202 int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
203 opt(begin[index]);
204 }
205
206 // Test the less than operator
207 if(begin != end &&!( begin<end))
208 {
209 std::cerr<<"! (begin()<end())"<<std::endl;
210 ret++;
211 }
212
213 if(begin != end) {
214 if(begin-end >= 0) {
215 std::cerr<<"begin!=end, but begin-end >= 0!"<<std::endl;
216 ret++;
217 }
218 if(end-begin <= 0) {
219 std::cerr<<"begin!=end, but end-begin <= 0!"<<std::endl;
220 ret++;
221 }
222 }
223
224 for(int i=0; i < no; i++)
225 {
226 int index = static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
227 Iter rand(begin), test(begin), res{};
228 rand+=index;
229
230 if((res=begin+index) != rand)
231 {
232 std::cerr << " i+n should have the result i+=n, where i is the "
233 <<"iterator and n is the difference type!" <<std::endl;
234 ret++;
235 }
236 for(int j = 0; j < index; j++)
237 ++test;
238
239 if(test != rand)
240 {
241 std::cerr << "i+=n should have the same result as applying the "
242 << "increment operator n times!"<< std::endl;
243 ret++;
244 }
245
246 rand=end, test=end;
247 rand-=index;
248
249
250 if((end-index) != rand)
251 {
252 std::cerr << " i-n should have the result i-=n, where i is the "
253 <<"iterator and n is the difference type!" <<std::endl;
254 ret++;
255 }
256 for(int j = 0; j < index; j++)
257 --test;
258
259 if(test != rand)
260 {
261 std::cerr << "i-=n should have the same result as applying the "
262 << "decrement operator n times!"<< std::endl;
263 ret++;
264 }
265 }
266
267 for(int i=0; i < no; i++)
268 {
269 Iter iter1 = begin+static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
270 Iter iter2 = begin+static_cast<int>(size*(rand()/(RAND_MAX+1.0)));
271 typename Iter::difference_type diff = iter2 -iter1;
272 if((iter1+diff)!=iter2) {
273 std::cerr<< "i+(j-i) = j should hold, where i,j are iterators!"<<std::endl;
274 ret++;
275 }
276 }
277
278 return ret;
279}
280
281template<class Iter, class Opt, typename iterator_category>
282int testIterator(Iter& begin, Iter& end, Opt& opt, iterator_category cat);
283
284template<class Iter, class Opt>
285int testIterator(Iter& begin, Iter& end, Opt& opt, std::forward_iterator_tag)
286{
287 return testForwardIterator(begin, end, opt);
288}
289
290template<class Iter, class Opt>
291int testIterator(Iter& begin, Iter& end, Opt& opt, std::bidirectional_iterator_tag)
292{
293 return testBidirectionalIterator(begin, end, opt);
294}
295
296template<class Iter, class Opt>
297int testIterator(Iter& begin, Iter& end, Opt& opt, std::random_access_iterator_tag)
298{
299 // std::cout << "Testing iterator ";
300 int ret = testRandomAccessIterator(begin, end, opt);
301 //std::cout<<std::endl;
302 return ret;
303}
304
305template<class Iter, class Opt>
306int testConstIterator(Iter& begin, Iter& end, Opt& opt)
307{
308 //std::cout << "Testing constant iterator: ";
309 int ret=testIterator(begin, end, opt, typename std::iterator_traits<Iter>::iterator_category());
310 //std::cout<<std::endl;
311 return ret;
312}
313
314template<bool>
315struct TestSorting
316{
317 template<class Container, typename IteratorTag>
318 static void testSorting(Container&, IteratorTag)
319 {}
320 template<class Container>
321 static void testSorting(Container& c, std::random_access_iterator_tag)
322 {
323 std::sort(c.begin(), c.end());
324 }
325}
326;
327
328template<>
329struct TestSorting<false>
330{
331 template<class Container>
332 static void testSorting(Container&, std::random_access_iterator_tag)
333 {}
334 template<class Container, typename IteratorTag>
335 static void testSorting(Container&, IteratorTag)
336 {}
337};
338
339
340template<class Container, class Opt, bool testSort>
341int testIterator(Container& c, Opt& opt)
342{
343 typename Container::iterator begin=c.begin(), end=c.end();
344 typename Container::const_iterator cbegin(begin);
345 [[maybe_unused]] typename Container::const_iterator cbegin1 = begin;
346 typename Container::const_iterator cend=c.end();
347 int ret = 0;
348
349 TestSorting<testSort>::testSorting(c, typename std::iterator_traits<typename Container::iterator>::iterator_category());
350
351 if(end!=cend || cend!=end)
352 {
353 std::cerr<<"constant and mutable iterators should be equal!"<<std::endl;
354 ret=1;
355 }
356 ret += testConstIterator(cbegin, cend, opt);
357 if(testSort)
358 ret += testIterator(begin,end,opt);
359
360 return ret;
361}
362
363template<class Container, class Opt>
364int testIterator(Container& c, Opt& opt)
365{
366 return testIterator<Container,Opt,true>(c,opt);
367}
368
369template<class Iter, class Opt>
370void testAssignment(Iter begin, Iter end, Opt&)
371{
372 //std::cout << "Assignment: ";
373 for(; begin!=end; begin++)
374 *begin=typename std::iterator_traits<Iter>::value_type();
375 //std::cout<<" Done."<< std::endl;
376}
377
378template<class Iter, class Opt>
379int testIterator(Iter& begin, Iter& end, Opt& opt)
380{
381 testAssignment(begin, end, opt);
382 return testConstIterator(begin, end, opt);
383}
384
385
386template<class T>
387class Printer {
388 typename std::remove_const<T>::type res;
389public:
390 Printer() : res(0){}
391 void operator()(const T& t){
392 res+=t;
393 // std::cout << t <<" ";
394 }
395};
396
397template<class Container, class Opt>
398int testIterator(const Container& c, Opt& opt)
399{
400 typename Container::const_iterator begin=c.begin(), end=c.end();
401 return testConstIterator(begin,end, opt);
402}
403
404
405template<class Container>
406int testIterator(Container& c)
407{
408 Printer<typename std::iterator_traits<typename Container::iterator>::value_type> print;
409 return testIterator(c,print);
410}
411
412#endif
A free function to provide the demangled class name of a given object or type as a string.
template which always yields a true value
Definition: typetraits.hh:134
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)