Lumiera  0.pre.03
»edit your freedom«
iter-adapter-test.cpp
Go to the documentation of this file.
1 /*
2  IterAdapter(Test) - building various custom iterators for a given container
3 
4  Copyright (C)
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
20 #include "lib/test/run.hpp"
21 #include "lib/test/test-helper.hpp"
22 #include "lib/util.hpp"
23 #include "lib/util-foreach.hpp"
24 #include "lib/format-cout.hpp"
25 
26 #include "lib/iter-adapter.hpp"
28 
29 #include <boost/lexical_cast.hpp>
30 #include <vector>
31 
32 
33 
34 namespace lib {
35 namespace test{
36 
37  using ::Test;
38  using LERR_(ITER_EXHAUST);
39  using boost::lexical_cast;
40  using util::for_each;
41  using util::isnil;
42  using std::vector;
43 
44 
45  namespace {
51  {
52  vector<int> data_;
53 
54  WrappedVector(uint num)
55  {
56  while (num)
57  data_.push_back(num--);
58  }
59 
60  typedef vector<int>::iterator sourceIter;
62 
63  typedef vector<int>::const_iterator const_sourceIter;
65 
66  iterator begin() { return iterator(data_.begin(),data_.end()); }
67  iterator end() { return iterator(); }
68  const_iterator begin() const { return const_iterator(data_.begin(),data_.end()); }
69  const_iterator end() const { return const_iterator(); }
70  };
71 
72 
82  {
83  typedef vector<int *> _Vec;
84 
85  _Vec numberz_;
86 
87  static void killIt (int *it) { delete it; }
88 
89 
90  public:
91  TestContainer (uint count)
92  : numberz_(count)
93  {
94  for (uint i=0; i<count; ++i)
95  numberz_[i] = new int(i);
96  }
97 
98  ~TestContainer ()
99  {
100  for_each (numberz_, killIt);
101  }
102 
103 
104  /* ==== Exposing Iterator interface(s) for the clients ====== */
105 
108 
111 
112 
113  iterator begin () { return iterator (this, numberz_.begin()); }
114  const_iterator begin () const { return const_iterator (this, numberz_.begin()); }
115  ref_iterator begin_ref () { return ref_iterator (begin()); }
116  const_ref_iter begin_ref () const { return const_ref_iter (begin()); }
117 
118  iterator end () { return iterator(); }
119  const_iterator end () const { return const_iterator(); }
120 
121  size_t size() const { return numberz_.size(); }
122 
123 
124 
125  protected: /* ==== API for the IterAdapter ==== */
126 
133  template<class ITER>
134  friend void
135  iterNext (const TestContainer*, ITER& pos)
136  {
137  ++pos;
138  }
139 
150  template<class ITER>
151  friend bool
152  checkPoint (const TestContainer* src, ITER& pos)
153  {
154  REQUIRE (src);
155  if ((pos != ITER()) && (pos != src->numberz_.end()))
156  return true;
157  else
158  {
159  pos = ITER();
160  return false;
161  } }
162  };
163 
164  } // (END) impl test dummy container
165 
166 
167 
168 
169 
170 
171 
172  /*****************************************************************/
182  class IterAdapter_test : public Test
183  {
184  uint NUM_ELMS{0};
185 
186  virtual void
187  run (Arg arg)
188  {
189  NUM_ELMS = firstVal (arg, 10);
190 
191  useSimpleWrappedContainer ();
192 
193  enumerate();
194  wrapIterRange();
195  TestContainer testElms (NUM_ELMS);
196  simpleUsage (testElms);
197 
198  iterTypeVariations (testElms);
199  verifyComparisons (testElms);
200  exposeDataAddresses();
201  }
202 
203 
205  void
207  {
208  long sum=0;
209  const int N = NUM_ELMS;
210  auto i = eachNum(1, N);
211  while (i)
212  {
213  sum += *i;
214  ++i;
215  }
216 
217  CHECK (sum == (N-1)*N / 2);
218 
219  CHECK (!i);
220  VERIFY_ERROR (ITER_EXHAUST, *i );
221  VERIFY_ERROR (ITER_EXHAUST, ++i );
222 
223  i = eachNum (N, 2*N);
224  CHECK (i);
225  CHECK (N == *i);
226  ++i;
227  CHECK (N+1 == *i);
228  for ( ; i; ++i)
229  cout << "++" << *i;
230  cout << endl;
231 
232  CHECK (!i);
233  }
234 
235 
240  void
242  {
243  vector<int> iVec (NUM_ELMS);
244  for (uint i=0; i < NUM_ELMS; ++i)
245  iVec[i] = i;
246 
247  typedef vector<int>::iterator I;
248  typedef RangeIter<I> Range;
249 
250  Range range (iVec.begin(), iVec.end());
251  CHECK (!isnil (range) || !NUM_ELMS);
252 
253  // now for example the client could....
254  while ( range )
255  {
256  cout << "::" << *range;
257  ++range;
258  }
259 
260  cout << endl;
261  CHECK (isnil (range));
262  CHECK (range == Range());
263  }
264 
265 
266 
268  template<class CON>
269  void
270  simpleUsage (CON& elms)
271  {
272  for_each (elms, showIntP);
273  cout << endl;
274  }
275 
276  static void showIntP (int* elm) { cout << "::" << *elm; }
277  static void showInt (int elm) { cout << "::" << elm; }
278 
279 
280 
281  void
282  useSimpleWrappedContainer ()
283  {
284  WrappedVector testVec (NUM_ELMS);
285  for_each (testVec, showInt);
286  cout << endl;
287 
288  WrappedVector const& ref (testVec);
289  for_each (ref, showInt); // uses const_iterator
290  cout << endl;
291  }
292 
293 
296  void
297  iterTypeVariations (TestContainer& elms)
298  {
299  TestContainer const& const_elms (elms);
300 
301  int i = 0;
302  for (TestContainer::iterator iter = elms.begin();
303  iter; ++iter, ++i
304  )
305  {
306  CHECK (iter);
307  CHECK (iter != elms.end());
308  CHECK (**iter == i);
309  --(**iter);
310  CHECK (**iter == i-1);
311  }
312 
313  i = 0;
314  for (TestContainer::const_iterator iter = const_elms.begin();
315  iter; ++iter, ++i
316  )
317  {
318  CHECK (iter);
319  CHECK (iter != elms.end());
320  CHECK (**iter == i-1);
321 
322  // note: the previous run indeed modified
323  // the element within the container.
324 
325  // ++(*iter); // doesn't compile, because it yields a "* const"
326  }
327 
328  i = 0;
329  for (TestContainer::ref_iterator iter = elms.begin_ref();
330  iter; ++iter, ++i
331  )
332  {
333  CHECK (iter);
334  CHECK ((*iter) == i-1);
335  ++(*iter);
336  CHECK ((*iter) == i);
337  }
338 
339  i = 0;
340  for (TestContainer::const_ref_iter iter = const_elms.begin_ref();
341  iter; ++iter, ++i
342  )
343  {
344  CHECK (iter);
345  CHECK ((*iter) == i);
346 
347  // *iter = i+1; ///////////TODO this should be const, but it isn't
348  }
349 
350 
351  //---- verify support for C++11 element iteration
352  i = 0;
353  for (auto& elm : elms) // NOTE: TestContainer exposes pointers
354  {
355  ++elm; // can indeed modify contents
356  --elm;
357  CHECK (*elm == i);
358  ++i;
359  }
360  CHECK (size_t(i) == elms.size());
361 
362  i = 0;
363  for (auto const& elm : elms)
364  {
365  CHECK (*elm == i);
366  // ++elm; // can not modify contents
367  ++i;
368  }
369  CHECK (size_t(i) == elms.size());
370 
371  i = 0;
372  for (auto const& elm : const_elms)
373  {
374  CHECK (*elm == i);
375  // ++elm; // can not modify contents
376  ++i;
377  }
378  CHECK (size_t(i) == elms.size());
379  }
380 
381 
384  void
386  {
387  vector<int> numbz;
388  for (uint i=0; i < NUM_ELMS; ++i)
389  numbz.push_back(i);
390 
391  typedef vector<int>::iterator RawIter;
392  typedef RangeIter<RawIter> Range;
393  typedef AddressExposingIter<Range> AddrIter;
394 
395  AddrIter ii(Range(numbz.begin(), numbz.end()));
396  for (uint i=0; i < numbz.size(); ++i)
397  {
398  CHECK (ii);
399  int* p = *ii;
400  CHECK (p == & numbz[i]);
401  ++ii;
402  }
403  CHECK (!ii);
404 
405  // building a const iterator needs to be done in a somewhat weird way;
406  // since we're exposing the pointer as value, the solution is to add
407  // the const on the immediately wrapped iterator type
408  typedef vector<int>::const_iterator ConstRawIter;
409  typedef RangeIter<ConstRawIter> ConstRange;
410  typedef AddressExposingIter<ConstRange> ConstAddrIter;
411 
412  ConstAddrIter iic(ConstRange(Range(numbz.begin(), numbz.end())));
413  for (uint i=0; i < numbz.size(); ++i)
414  {
415  CHECK (iic);
416  const int* p = *iic;
417  CHECK (p == & numbz[i]);
418  ++iic;
419  }
420  CHECK (!iic);
421  }
422 
423 
424 
425 
427  void
428  verifyComparisons (TestContainer& elms)
429  {
430  TestContainer::ref_iterator rI (elms.begin_ref());
431 
432  CHECK (0 == *rI );
433  ++rI;
434  CHECK (1 == *rI );
435  CHECK (2 == *++rI);
436 
437  TestContainer const& const_elms (elms);
438  TestContainer::const_ref_iter rI2 (const_elms.begin_ref());
439 
440  CHECK (rI2 != rI);
441  CHECK (rI2 == elms.begin_ref());
442  CHECK (rI2 == const_elms.begin_ref());
443 
444  ++++rI2;
445 
446  CHECK (rI2 == rI);
447  CHECK (rI2 != ++rI);
448  CHECK (!isnil (rI2));
449 
450  CHECK (TestContainer::iterator() == elms.end());
451  CHECK (!(TestContainer::iterator()));
452  CHECK (!(elms.end()));
453  CHECK (isnil (elms.end()));
454 
455  CHECK (elms.begin());
456  CHECK (!isnil (elms.begin()));
457  }
458 
459 
460  };
461 
462  LAUNCHER (IterAdapter_test, "unit common");
463 
464 
465 }} // namespace lib::test
466 
wrapper for an existing Iterator type, automatically dereferencing the output of the former...
Automatically use custom string conversion in C++ stream output.
Extension adapter for Lumiera Forward Iterators to dereference any pointer values automatically...
Example of a more elaborate custom container exposing an iteration API.
example of simply wrapping an STL container and exposing a range as Lumiera Forward Iterator ...
Definition: run.hpp:40
Helper template(s) for creating Lumiera Forward Iterators.
void iterTypeVariations(TestContainer &elms)
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Implementation namespace for support and library code.
wrapper for an existing Iterator type to expose the address of each value yielded.
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
A collection of frequently used helper functions to support unit testing.
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
friend bool checkPoint(const TestContainer *src, ITER &pos)
Implementation of Iteration-logic: detect iteration end.
friend void iterNext(const TestContainer *, ITER &pos)
Implementation of Iteration-logic: pull next element.
void verifyComparisons(TestContainer &elms)
Perform operations "for each element" of a collection.
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
NumIter< INT > eachNum(INT start=std::numeric_limits< INT >::min(), INT end=std::numeric_limits< INT >::max())
convenience function to iterate "each number"