Lumiera  0.pre.03
»edit your freedom«
util-foreach-test.cpp
Go to the documentation of this file.
1 /*
2  UtilForeach(Test) - helpers to perform something for each element
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 
19 #include "lib/test/run.hpp"
20 #include "lib/util-foreach.hpp"
21 #include "lib/iter-adapter.hpp"
22 
23 
24 #include <boost/lexical_cast.hpp>
25 #include <functional>
26 #include <iostream>
27 #include <vector>
28 
29 
30 using ::Test;
31 
32 using util::for_each;
33 using util::has_any;
34 using util::and_all;
35 
36 using boost::lexical_cast;
37 using std::function;
38 using std::ref;
39 using std::cout;
40 using std::endl;
41 
42 
43 namespace util {
44 namespace test {
45 
46  typedef std::vector<int> VecI;
47  typedef lib::RangeIter<VecI::iterator> RangeI;
48 
49 
50 
51  namespace{ // Test data and operations
52 
53  // Placeholder for argument in bind-expressions
54  std::_Placeholder<1> _1;
55 
56 
57  VecI
58  buildTestNumberz (uint count)
59  {
60  VecI numbers;
61  numbers.reserve(count);
62  while (count)
63  numbers.push_back(count--);
64 
65  return numbers;
66  }
67 
68 
69  /* == functions to bind and invoke == */
70  bool
71  plainFunc (int i)
72  {
73  cout <<':'<< i;
74  return i;
75  }
76 
77  bool
78  function1 (int i, int j)
79  {
80  return plainFunc(i+j);
81  }
82 
83  bool
84  function2 (int i, int j, int& k)
85  {
86  k += i + j;
87  return plainFunc(k);
88  }
89 
90 
91 #define _NL_ cout << endl;
92 #define ANNOUNCE(_LABEL_) cout << "---:" << STRINGIFY(_LABEL_) << endl;
93 
94  } // (End) test data and operations
95 
96 
97 
98  /*****************************************************************/
112  class UtilForeach_test : public Test
113  {
114  uint NUM_ELMS{0};
115 
116  virtual void
117  run (Arg arg)
118  {
119  NUM_ELMS = firstVal (arg, 10);
120  VecI container = buildTestNumberz (NUM_ELMS);
121  RangeI iterator(container.begin(), container.end());
122 
123  check_foreach_plain (container);
124  check_foreach_plain (iterator);
125 
126  check_foreach_bind (container);
127  check_foreach_bind (iterator);
128 
129  check_foreach_bind_const (container);
130 
131  check_foreach_memFun (container);
132  check_foreach_memFun (iterator);
133 
134  check_foreach_lambda (container);
135  check_foreach_lambda (iterator);
136 
137  check_existence_quant (container);
138  check_existence_quant (iterator);
139 
140  CHECK (int(NUM_ELMS) ==container[0]);
141 
142  check_ref_argument_bind (container);
143  CHECK (int(NUM_ELMS) ==container[0]);
144 
145  check_ref_argument_bind (iterator);
146  CHECK (90+int(NUM_ELMS) ==container[0]);
147  // changes got propagated through the iterator
148 
150 
152  }
153 
154 
159  template<typename CO>
160  void
162  {
163  ANNOUNCE (check_foreach_plain);
164  function<bool(int)> func(plainFunc);
165 
166  for_each (coll, plainFunc); _NL_
167  for_each (coll, &plainFunc); _NL_
168  for_each (coll, func); _NL_
169 
170  and_all (coll, plainFunc); _NL_
171  and_all (coll, &plainFunc); _NL_
172  and_all (coll, func); _NL_
173 
174  has_any (coll, plainFunc); _NL_
175  has_any (coll, &plainFunc); _NL_
176  has_any (coll, func); _NL_
177  }
178 
179 
183  template<typename CO>
184  void
186  {
187  ANNOUNCE (check_foreach_bind);
188  function<bool(int,int)> fun1(function1);
189 
190  for_each (coll, function1, 10, _1 ); _NL_
191  for_each (coll, &function1,10, _1 ); _NL_
192  for_each (coll, fun1, 10, _1 ); _NL_
193 
194  and_all (coll, function1, 10, _1 ); _NL_
195  and_all (coll, &function1, 10, _1 ); _NL_
196  and_all (coll, fun1, 10, _1 ); _NL_
197 
198  has_any (coll, function1, 10, _1 ); _NL_
199  has_any (coll, &function1, 10, _1 ); _NL_
200  has_any (coll, fun1, 10, _1 ); _NL_
201 
202  for_each (coll, function1, _1, _1 ); _NL_
203  for_each (coll, &function1,_1, _1 ); _NL_
204  for_each (coll, fun1, _1, _1 ); _NL_
205 
206  and_all (coll, function1, _1, _1 ); _NL_
207  and_all (coll, &function1, _1, _1 ); _NL_
208  and_all (coll, fun1, _1, _1 ); _NL_
209 
210  has_any (coll, function1, _1, _1 ); _NL_
211  has_any (coll, &function1, _1, _1 ); _NL_
212  has_any (coll, fun1, _1, _1 ); _NL_
213 
214  //does not compile.....
215  // for_each (coll, function1, 10, 20, _1 );
216  // for_each (coll, function1, _1, _2 );
217  // for_each (coll, function1, 10 );
218  }
219 
220 
234  template<typename CO>
235  void
237  {
238  ANNOUNCE (assign_to_input);
239  function<bool(int,int,int&)> fun2(function2);
240 
241  for_each (coll, function2, 5, 5, _1 ); _NL_
242  for_each (coll, &function2,5, 5, _1 ); _NL_
243 
244  and_all (coll, function2, 5, 5, _1 ); _NL_
245  and_all (coll, &function2, 5, 5, _1 ); _NL_
246 
247  has_any (coll, function2, 5, 5, _1 ); _NL_
248  has_any (coll, &function2, 5, 5, _1 ); _NL_
249 
250  // note: in C++11, the reference parameters are passed through
251  // even when wrapping the function or function pointer into a function object,
252  for_each (coll,fun2, 5, 5, _1 ); _NL_
253  and_all (coll, fun2, 5, 5, _1 ); _NL_
254  has_any (coll, fun2, 5, 5, _1 ); _NL_
255  // at that point we have added 9 * (5+5) to the value at position zero.
256  // (note that the has_any only evaluates the function once)
257 
258 
259  // the following test assigns the sum via the ref argument to a local variable.
260  int sum=0;
261  ANNOUNCE (assign_to_var);
262  for_each (coll, function2, -10, _1, ref(sum) ); _NL_
263  for_each (coll, &function2,-10, _1, ref(sum) ); _NL_
264  for_each (coll, fun2, -10, _1, ref(sum) ); _NL_
265  cout << "sum=" << sum << endl;
266 
267  sum=0;
268  and_all (coll, function2, -10, _1, ref(sum) ); _NL_
269  and_all (coll, &function2, -10, _1, ref(sum) ); _NL_
270  and_all (coll, fun2, -10, _1, ref(sum) ); _NL_
271  cout << "sum=" << sum << endl;
272 
273  sum=0;
274  has_any (coll, function2, -10, _1, ref(sum) ); _NL_
275  has_any (coll, &function2, -10, _1, ref(sum) ); _NL_
276  has_any (coll, fun2, -10, _1, ref(sum) ); _NL_
277  cout << "sum=" << sum << endl;
278  }
279 
280 
284  template<typename CO>
285  void
286  check_foreach_bind_const (CO const& coll)
287  {
288  ANNOUNCE (check_foreach_bind_const);
289 
290  for_each (coll,function1, 10, _1 ); _NL_
291  and_all (coll, function1, 10, _1 ); _NL_
292  has_any (coll, function1, 10, _1 ); _NL_
293 
294  for_each (coll,function1, _1, _1 ); _NL_
295  and_all (coll, function1, _1, _1 ); _NL_
296  has_any (coll, function1, _1, _1 ); _NL_
297 
298  int sum=0;
299 
300  for_each (coll,function2, _1, _1, ref(sum) ); _NL_
301  and_all (coll, function2, _1, _1, ref(sum) ); _NL_
302  has_any (coll, function2, _1, _1, ref(sum) ); _NL_
303  }
304 
305 
306 
307  struct Dummy
308  {
309  int sum_;
310 
311  bool
312  fun (int i)
313  {
314  sum_ += i;
315  return plainFunc (sum_);
316  }
317  };
318 
320  template<typename CO>
321  void
323  {
324  ANNOUNCE (check_foreach_memFun);
325 
326  Dummy dummy;
327  dummy.sum_ = 0;
328 
329  for_each (coll, &Dummy::fun, dummy, _1 ); _NL_
330  and_all (coll, &Dummy::fun, dummy, _1 ); _NL_
331  has_any (coll, &Dummy::fun, dummy, _1 ); _NL_
332 
333  for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_
334  and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_
335  has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_
336 
337  cout << "sum=" << dummy.sum_ << endl;
338  }
339 
340 
342  template<typename CO>
343  void
345  {
346  ANNOUNCE (check_foreach_lambda);
347  uint sum(0);
348 
349  for_each (coll, [&sum] (uint entry) { sum += entry; });
350 
351  CHECK (sum == (NUM_ELMS+1) * NUM_ELMS/2);
352 
353  CHECK (!and_all (coll, [] (uint elm) { return elm - 1; }));
354  CHECK ( has_any (coll, [] (uint elm) { return elm + 1; }));
355  }
356 
357 
360  template<typename CO>
361  void
363  {
364  ANNOUNCE (check_existence_quant);
365 
366  CHECK ( and_all (coll, [] (uint elm) { return 0 < elm; }));
367  CHECK (!and_all (coll, [] (uint elm) { return 1 < elm; }));
368 
369  CHECK ( has_any (coll, [] (uint elm) { return 0 < elm; }));
370  CHECK ( has_any (coll, [this](uint elm) { return elm == NUM_ELMS; }));
371  CHECK (!has_any (coll, [this](uint elm) { return elm > NUM_ELMS; }));
372  }
373 
374 
375  struct TestElm
376  {
377  uint n_;
378  TestElm(uint i) : n_(i) {}
379 
380  bool operation() { return plainFunc (n_); }
381  };
382 
383 
387  void
389  {
390  ANNOUNCE (check_invoke_on_each);
391 
392  std::vector<TestElm> elms;
393  for (uint i=0; i<6; ++i)
394  elms.push_back (TestElm(i));
395 
396  std::vector<TestElm*> elmPtrs;
397  for (uint i=0; i<6; ++i)
398  elmPtrs.push_back (& elms[i]);
399 
400  // fed the element pointer as "this" pointer of the member function
401  for_each (elmPtrs, &TestElm::operation, _1 ); _NL_
402  and_all (elmPtrs, &TestElm::operation, _1 ); _NL_
403  has_any (elmPtrs, &TestElm::operation, _1 ); _NL_
404 
405  // the same works with copies of the elements as well...
406  for_each (elms, &TestElm::operation, _1 ); _NL_
407  and_all (elms, &TestElm::operation, _1 ); _NL_
408  has_any (elms, &TestElm::operation, _1 ); _NL_
409 
410  // note: it seems not to be possible to create a binder, which takes the "*this"-Argument by ref
411  }
412 
413 
425  void
427  {
428  ANNOUNCE (wrapped_container_passing);
429 
430 #define SHOW_CONTAINER for_each (coll, plainFunc); _NL_
431 
432  int counter = NUM_ELMS;
433  auto assign_and_decrement = [&] (int& entry)
434  {
435  entry = counter--;
436  };
437 
438  // use a const reference to pass the container...
439  VecI const& passByConstRef (coll);
440 
441  for_each (passByConstRef, assign_and_decrement );
442 
443  SHOW_CONTAINER
444  // indeed got modifications into the original container!
445  CHECK (0 == counter);
446 
447  // passing anonymous temporary
448  for_each (buildTestNumberz(NUM_ELMS), assign_and_decrement );
449 
450  // passing a smart-ptr managed copy
451  std::shared_ptr<VecI> bySmartPtr (new VecI (coll));
452 
453  for_each (bySmartPtr, assign_and_decrement );
454 
455  // both didn't influence the original container
456  SHOW_CONTAINER
457  CHECK (-2*int(NUM_ELMS) == counter);
458  CHECK (bySmartPtr->back() == counter+1);
459 
460  // passing the container by pointer is also possible
461  const VecI * const passByConstPointer (&coll);
462 
463  for_each (passByConstPointer, assign_and_decrement );
464  SHOW_CONTAINER
465  // ...and does indeed influence the original container
466  }
467 
468  };
469 
470 
471 
472 
473  LAUNCHER (UtilForeach_test, "unit common");
474 
475 
476 }} // namespace util::test
477 
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:40
Helper template(s) for creating Lumiera Forward Iterators.
bool and_all(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
bool has_any(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
Simplistic test class runner.
disable_if< can_IterForEach< Container >, FUN > for_each(Container const &coll, FUN doIt)
operate on all elements of a STL container.
void check_wrapped_container_passing(VecI coll)
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
bool has_any(IT i, IT end, FUN predicate)
Existential quantification: check if any element of a collection satisfies the given predicate...
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
bool and_all(IT i, IT end, FUN predicate)
All quantification: check if all elements of a collection satisfy the given predicate.
Perform operations "for each element" of a collection.
void check_foreach_bind_const(CO const &coll)