DUNE-FEM (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 for(int i=0; i < no-1; i++)
279 {
280 Iter iter1 = begin+i;
281 Iter iter2 = begin+i+1;
282
283 if (!(iter1 < iter2) || (iter1 < iter1)) {
284 std::cerr<< "i<j and !(i<i) should hold, where i,j=i+1 are iterators!"<<std::endl;
285 ret++;
286 }
287 if (!(iter1 <= iter2) || !(iter1 <= iter1)) {
288 std::cerr<< "i<=j and i<=i should hold, where i,j=i+1 are iterators!"<<std::endl;
289 ret++;
290 }
291 if (!(iter2 > iter1) || (iter1 > iter1)) {
292 std::cerr<< "j>i and !(i>i) should hold, where i,j=i+1 are iterators!"<<std::endl;
293 ret++;
294 }
295 if (!(iter2 >= iter1) || !(iter1 >= iter1)) {
296 std::cerr<< "j>=i and i>=i should hold, where i,j=i+1 are iterators!"<<std::endl;
297 ret++;
298 }
299 if (!(iter1 == iter1) || (iter1 != iter1)) {
300 std::cerr<< "i==i and !(i!=i) should hold, where i is an iterator!"<<std::endl;
301 ret++;
302 }
303 }
304
305 return ret;
306}
307
308template<class Iter, class Opt, typename iterator_category>
309int testIterator(Iter& begin, Iter& end, Opt& opt, iterator_category cat);
310
311template<class Iter, class Opt>
312int testIterator(Iter& begin, Iter& end, Opt& opt, std::forward_iterator_tag)
313{
314 return testForwardIterator(begin, end, opt);
315}
316
317template<class Iter, class Opt>
318int testIterator(Iter& begin, Iter& end, Opt& opt, std::bidirectional_iterator_tag)
319{
320 return testBidirectionalIterator(begin, end, opt);
321}
322
323template<class Iter, class Opt>
324int testIterator(Iter& begin, Iter& end, Opt& opt, std::random_access_iterator_tag)
325{
326 // std::cout << "Testing iterator ";
327 int ret = testRandomAccessIterator(begin, end, opt);
328 //std::cout<<std::endl;
329 return ret;
330}
331
332template<class Iter, class Opt>
333int testConstIterator(Iter& begin, Iter& end, Opt& opt)
334{
335 //std::cout << "Testing constant iterator: ";
336 int ret=testIterator(begin, end, opt, typename std::iterator_traits<Iter>::iterator_category());
337 //std::cout<<std::endl;
338 return ret;
339}
340
341template<bool>
342struct TestSorting
343{
344 template<class Container, typename IteratorTag>
345 static void testSorting(Container&, IteratorTag)
346 {}
347 template<class Container>
348 static void testSorting(Container& c, std::random_access_iterator_tag)
349 {
350 std::sort(c.begin(), c.end());
351 }
352}
353;
354
355template<>
356struct TestSorting<false>
357{
358 template<class Container>
359 static void testSorting(Container&, std::random_access_iterator_tag)
360 {}
361 template<class Container, typename IteratorTag>
362 static void testSorting(Container&, IteratorTag)
363 {}
364};
365
366
367template<class Container, class Opt, bool testSort>
368int testIterator(Container& c, Opt& opt)
369{
370 typename Container::iterator begin=c.begin(), end=c.end();
371 typename Container::const_iterator cbegin(begin);
372 [[maybe_unused]] typename Container::const_iterator cbegin1 = begin;
373 typename Container::const_iterator cend=c.end();
374 int ret = 0;
375
376 TestSorting<testSort>::testSorting(c, typename std::iterator_traits<typename Container::iterator>::iterator_category());
377
378 if(end!=cend || cend!=end)
379 {
380 std::cerr<<"constant and mutable iterators should be equal!"<<std::endl;
381 ret=1;
382 }
383 ret += testConstIterator(cbegin, cend, opt);
384 if(testSort)
385 ret += testIterator(begin,end,opt);
386
387 return ret;
388}
389
390template<class Container, class Opt>
391int testIterator(Container& c, Opt& opt)
392{
393 return testIterator<Container,Opt,true>(c,opt);
394}
395
396template<class Iter, class Opt>
397void testAssignment(Iter begin, Iter end, Opt&)
398{
399 //std::cout << "Assignment: ";
400 for(; begin!=end; begin++)
401 *begin=typename std::iterator_traits<Iter>::value_type();
402 //std::cout<<" Done."<< std::endl;
403}
404
405template<class Iter, class Opt>
406int testIterator(Iter& begin, Iter& end, Opt& opt)
407{
408 testAssignment(begin, end, opt);
409 return testConstIterator(begin, end, opt);
410}
411
412
413template<class T>
414class Printer {
415 typename std::remove_const<T>::type res;
416public:
417 Printer() : res(0){}
418 void operator()(const T& t){
419 res+=t;
420 // std::cout << t <<" ";
421 }
422};
423
424template<class Container, class Opt>
425int testIterator(const Container& c, Opt& opt)
426{
427 typename Container::const_iterator begin=c.begin(), end=c.end();
428 return testConstIterator(begin,end, opt);
429}
430
431
432template<class Container>
433int testIterator(Container& c)
434{
435 Printer<typename std::iterator_traits<typename Container::iterator>::value_type> print;
436 return testIterator(c,print);
437}
438
439#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 & Uni Heidelberg  |  generated with Hugo v0.111.3 (Sep 4, 22:38, 2025)