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) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
29 #include "lib/test/run.hpp"
30 #include "lib/test/test-helper.hpp"
31 #include "lib/util.hpp"
32 #include "lib/util-foreach.hpp"
33 #include "lib/format-cout.hpp"
34 
35 #include "lib/iter-adapter.hpp"
37 
38 #include <boost/lexical_cast.hpp>
39 #include <vector>
40 
41 
42 
43 namespace lib {
44 namespace test{
45 
46  using ::Test;
47  using lumiera::error::LERR_(ITER_EXHAUST);
48  using boost::lexical_cast;
49  using util::for_each;
50  using util::isnil;
51  using std::vector;
52 
53 
54  namespace {
55 
56  uint NUM_ELMS = 10;
57 
62  {
63  vector<int> data_;
64 
65  WrappedVector(uint num)
66  {
67  while (num)
68  data_.push_back(num--);
69  }
70 
71  typedef vector<int>::iterator sourceIter;
73 
74  typedef vector<int>::const_iterator const_sourceIter;
76 
77  iterator begin() { return iterator(data_.begin(),data_.end()); }
78  iterator end() { return iterator(); }
79  const_iterator begin() const { return const_iterator(data_.begin(),data_.end()); }
80  const_iterator end() const { return const_iterator(); }
81  };
82 
83 
93  {
94  typedef vector<int *> _Vec;
95 
96  _Vec numberz_;
97 
98  static void killIt (int *it) { delete it; }
99 
100 
101  public:
102  TestContainer (uint count)
103  : numberz_(count)
104  {
105  for (uint i=0; i<count; ++i)
106  numberz_[i] = new int(i);
107  }
108 
109  ~TestContainer ()
110  {
111  for_each (numberz_, killIt);
112  }
113 
114 
115  /* ==== Exposing Iterator interface(s) for the clients ====== */
116 
119 
122 
123 
124  iterator begin () { return iterator (this, numberz_.begin()); }
125  const_iterator begin () const { return const_iterator (this, numberz_.begin()); }
126  ref_iterator begin_ref () { return ref_iterator (begin()); }
127  const_ref_iter begin_ref () const { return const_ref_iter (begin()); }
128 
129  iterator end () { return iterator(); }
130  const_iterator end () const { return const_iterator(); }
131 
132  size_t size() const { return numberz_.size(); }
133 
134 
135 
136  protected: /* ==== API for the IterAdapter ==== */
137 
144  template<class ITER>
145  friend void
146  iterNext (const TestContainer*, ITER& pos)
147  {
148  ++pos;
149  }
150 
161  template<class ITER>
162  friend bool
163  checkPoint (const TestContainer* src, ITER& pos)
164  {
165  REQUIRE (src);
166  if ((pos != ITER()) && (pos != src->numberz_.end()))
167  return true;
168  else
169  {
170  pos = ITER();
171  return false;
172  } }
173  };
174 
175  } // (END) impl test dummy container
176 
177 
178 
179 
180 
181 
182 
183  /*****************************************************************/
193  class IterAdapter_test : public Test
194  {
195 
196  virtual void
197  run (Arg arg)
198  {
199  if (0 < arg.size()) NUM_ELMS = lexical_cast<uint> (arg[1]);
200 
201  useSimpleWrappedContainer ();
202 
203  enumerate();
204  wrapIterRange();
205  TestContainer testElms (NUM_ELMS);
206  simpleUsage (testElms);
207 
208  iterTypeVariations (testElms);
209  verifyComparisons (testElms);
210  exposeDataAddresses();
211  }
212 
213 
215  void
217  {
218  long sum=0;
219  const int N = NUM_ELMS;
220  auto i = eachNum(1, N);
221  while (i)
222  {
223  sum += *i;
224  ++i;
225  }
226 
227  CHECK (sum == (N-1)*N / 2);
228 
229  CHECK (!i);
230  VERIFY_ERROR (ITER_EXHAUST, *i );
231  VERIFY_ERROR (ITER_EXHAUST, ++i );
232 
233  i = eachNum (N, 2*N);
234  CHECK (i);
235  CHECK (N == *i);
236  ++i;
237  CHECK (N+1 == *i);
238  for ( ; i; ++i)
239  cout << "++" << *i;
240  cout << endl;
241 
242  CHECK (!i);
243  }
244 
245 
250  void
252  {
253  vector<int> iVec (NUM_ELMS);
254  for (uint i=0; i < NUM_ELMS; ++i)
255  iVec[i] = i;
256 
257  typedef vector<int>::iterator I;
258  typedef RangeIter<I> Range;
259 
260  Range range (iVec.begin(), iVec.end());
261  CHECK (!isnil (range) || !NUM_ELMS);
262 
263  // now for example the client could....
264  while ( range )
265  {
266  cout << "::" << *range;
267  ++range;
268  }
269 
270  cout << endl;
271  CHECK (isnil (range));
272  CHECK (range == Range());
273  }
274 
275 
276 
278  template<class CON>
279  void
280  simpleUsage (CON& elms)
281  {
282  for_each (elms, showIntP);
283  cout << endl;
284  }
285 
286  static void showIntP (int* elm) { cout << "::" << *elm; }
287  static void showInt (int elm) { cout << "::" << elm; }
288 
289 
290 
291  void
292  useSimpleWrappedContainer ()
293  {
294  WrappedVector testVec (NUM_ELMS);
295  for_each (testVec, showInt);
296  cout << endl;
297 
298  WrappedVector const& ref (testVec);
299  for_each (ref, showInt); // uses const_iterator
300  cout << endl;
301  }
302 
303 
306  void
307  iterTypeVariations (TestContainer& elms)
308  {
309  TestContainer const& const_elms (elms);
310 
311  int i = 0;
312  for (TestContainer::iterator iter = elms.begin();
313  iter; ++iter, ++i
314  )
315  {
316  CHECK (iter);
317  CHECK (iter != elms.end());
318  CHECK (**iter == i);
319  --(**iter);
320  CHECK (**iter == i-1);
321  }
322 
323  i = 0;
324  for (TestContainer::const_iterator iter = const_elms.begin();
325  iter; ++iter, ++i
326  )
327  {
328  CHECK (iter);
329  CHECK (iter != elms.end());
330  CHECK (**iter == i-1);
331 
332  // note: the previous run indeed modified
333  // the element within the container.
334 
335  // ++(*iter); // doesn't compile, because it yields a "* const"
336  }
337 
338  i = 0;
339  for (TestContainer::ref_iterator iter = elms.begin_ref();
340  iter; ++iter, ++i
341  )
342  {
343  CHECK (iter);
344  CHECK ((*iter) == i-1);
345  ++(*iter);
346  CHECK ((*iter) == i);
347  }
348 
349  i = 0;
350  for (TestContainer::const_ref_iter iter = const_elms.begin_ref();
351  iter; ++iter, ++i
352  )
353  {
354  CHECK (iter);
355  CHECK ((*iter) == i);
356 
357  // *iter = i+1; ///////////TODO this should be const, but it isn't
358  }
359 
360 
361  //---- verify support for C++11 element iteration
362  i = 0;
363  for (auto& elm : elms) // NOTE: TestContainer exposes pointers
364  {
365  ++elm; // can indeed modify contents
366  --elm;
367  CHECK (*elm == i);
368  ++i;
369  }
370  CHECK (size_t(i) == elms.size());
371 
372  i = 0;
373  for (auto const& elm : elms)
374  {
375  CHECK (*elm == i);
376  // ++elm; // can not modify contents
377  ++i;
378  }
379  CHECK (size_t(i) == elms.size());
380 
381  i = 0;
382  for (auto const& elm : const_elms)
383  {
384  CHECK (*elm == i);
385  // ++elm; // can not modify contents
386  ++i;
387  }
388  CHECK (size_t(i) == elms.size());
389  }
390 
391 
394  void
396  {
397  vector<int> numbz;
398  for (uint i=0; i < NUM_ELMS; ++i)
399  numbz.push_back(i);
400 
401  typedef vector<int>::iterator RawIter;
402  typedef RangeIter<RawIter> Range;
403  typedef AddressExposingIter<Range> AddrIter;
404 
405  AddrIter ii(Range(numbz.begin(), numbz.end()));
406  for (uint i=0; i < numbz.size(); ++i)
407  {
408  CHECK (ii);
409  int* p = *ii;
410  CHECK (p == & numbz[i]);
411  ++ii;
412  }
413  CHECK (!ii);
414 
415  // building a const iterator needs to be done in a somewhat weird way;
416  // since we're exposing the pointer as value, the solution is to add
417  // the const on the immediately wrapped iterator type
418  typedef vector<int>::const_iterator ConstRawIter;
419  typedef RangeIter<ConstRawIter> ConstRange;
420  typedef AddressExposingIter<ConstRange> ConstAddrIter;
421 
422  ConstAddrIter iic(ConstRange(Range(numbz.begin(), numbz.end())));
423  for (uint i=0; i < numbz.size(); ++i)
424  {
425  CHECK (iic);
426  const int* p = *iic;
427  CHECK (p == & numbz[i]);
428  ++iic;
429  }
430  CHECK (!iic);
431  }
432 
433 
434 
435 
437  void
438  verifyComparisons (TestContainer& elms)
439  {
440  TestContainer::ref_iterator rI (elms.begin_ref());
441 
442  CHECK (0 == *rI );
443  ++rI;
444  CHECK (1 == *rI );
445  CHECK (2 == *++rI);
446 
447  TestContainer const& const_elms (elms);
448  TestContainer::const_ref_iter rI2 (const_elms.begin_ref());
449 
450  CHECK (rI2 != rI);
451  CHECK (rI2 == elms.begin_ref());
452  CHECK (rI2 == const_elms.begin_ref());
453 
454  ++++rI2;
455 
456  CHECK (rI2 == rI);
457  CHECK (rI2 != ++rI);
458  CHECK (!isnil (rI2));
459 
460  CHECK (TestContainer::iterator() == elms.end());
461  CHECK (!(TestContainer::iterator()));
462  CHECK (!(elms.end()));
463  CHECK (isnil (elms.end()));
464 
465  CHECK (elms.begin());
466  CHECK (!isnil (elms.begin()));
467  }
468 
469 
470  };
471 
472  LAUNCHER (IterAdapter_test, "unit common");
473 
474 
475 }} // namespace lib::test
476 
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 ...
NumIter< INT > eachNum(INT start, INT end)
convenience function to iterate "each number"
Definition: run.hpp:49
Helper template(s) for creating Lumiera Forward Iterators.
void iterTypeVariations(TestContainer &elms)
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify 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.
Simple 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. ...