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) 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 
28 #include "lib/test/run.hpp"
29 #include "lib/util-foreach.hpp"
30 #include "lib/iter-adapter.hpp"
31 
32 
33 #include <boost/lexical_cast.hpp>
34 #include <functional>
35 #include <iostream>
36 #include <vector>
37 
38 
39 using ::Test;
40 
41 using util::for_each;
42 using util::has_any;
43 using util::and_all;
44 
45 using boost::lexical_cast;
46 using std::function;
47 using std::ref;
48 using std::cout;
49 using std::endl;
50 
51 
52 namespace util {
53 namespace test {
54 
55  typedef std::vector<int> VecI;
56  typedef lib::RangeIter<VecI::iterator> RangeI;
57 
58 
59 
60  namespace{ // Test data and operations
61 
62  uint NUM_ELMS = 10;
63 
64  // Placeholder for argument in bind-expressions
65  std::_Placeholder<1> _1;
66 
67 
68  VecI
69  buildTestNumberz (uint count)
70  {
71  VecI numbers;
72  numbers.reserve(count);
73  while (count)
74  numbers.push_back(count--);
75 
76  return numbers;
77  }
78 
79 
80  /* == functions to bind and invoke == */
81  bool
82  plainFunc (int i)
83  {
84  cout <<':'<< i;
85  return i;
86  }
87 
88  bool
89  function1 (int i, int j)
90  {
91  return plainFunc(i+j);
92  }
93 
94  bool
95  function2 (int i, int j, int& k)
96  {
97  k += i + j;
98  return plainFunc(k);
99  }
100 
101 
102 #define _NL_ cout << endl;
103 #define ANNOUNCE(_LABEL_) cout << "---:" << STRINGIFY(_LABEL_) << endl;
104 
105  } // (End) test data and operations
106 
107 
108 
109  /*****************************************************************/
123  class UtilForeach_test : public Test
124  {
125 
126  void
127  run (Arg arg)
128  {
129  if (0 < arg.size()) NUM_ELMS = lexical_cast<uint> (arg[1]);
130 
131  VecI container = buildTestNumberz (NUM_ELMS);
132  RangeI iterator(container.begin(), container.end());
133 
134  check_foreach_plain (container);
135  check_foreach_plain (iterator);
136 
137  check_foreach_bind (container);
138  check_foreach_bind (iterator);
139 
140  check_foreach_bind_const (container);
141 
142  check_foreach_memFun (container);
143  check_foreach_memFun (iterator);
144 
145  check_foreach_lambda (container);
146  check_foreach_lambda (iterator);
147 
148  check_existence_quant (container);
149  check_existence_quant (iterator);
150 
151  CHECK (int(NUM_ELMS) ==container[0]);
152 
153  check_ref_argument_bind (container);
154  CHECK (int(NUM_ELMS) ==container[0]);
155 
156  check_ref_argument_bind (iterator);
157  CHECK (90+int(NUM_ELMS) ==container[0]);
158  // changes got propagated through the iterator
159 
161 
163  }
164 
165 
170  template<typename CO>
171  void
173  {
174  ANNOUNCE (check_foreach_plain);
175  function<bool(int)> func(plainFunc);
176 
177  for_each (coll, plainFunc); _NL_
178  for_each (coll, &plainFunc); _NL_
179  for_each (coll, func); _NL_
180 
181  and_all (coll, plainFunc); _NL_
182  and_all (coll, &plainFunc); _NL_
183  and_all (coll, func); _NL_
184 
185  has_any (coll, plainFunc); _NL_
186  has_any (coll, &plainFunc); _NL_
187  has_any (coll, func); _NL_
188  }
189 
190 
194  template<typename CO>
195  void
197  {
198  ANNOUNCE (check_foreach_bind);
199  function<bool(int,int)> fun1(function1);
200 
201  for_each (coll, function1, 10, _1 ); _NL_
202  for_each (coll, &function1,10, _1 ); _NL_
203  for_each (coll, fun1, 10, _1 ); _NL_
204 
205  and_all (coll, function1, 10, _1 ); _NL_
206  and_all (coll, &function1, 10, _1 ); _NL_
207  and_all (coll, fun1, 10, _1 ); _NL_
208 
209  has_any (coll, function1, 10, _1 ); _NL_
210  has_any (coll, &function1, 10, _1 ); _NL_
211  has_any (coll, fun1, 10, _1 ); _NL_
212 
213  for_each (coll, function1, _1, _1 ); _NL_
214  for_each (coll, &function1,_1, _1 ); _NL_
215  for_each (coll, fun1, _1, _1 ); _NL_
216 
217  and_all (coll, function1, _1, _1 ); _NL_
218  and_all (coll, &function1, _1, _1 ); _NL_
219  and_all (coll, fun1, _1, _1 ); _NL_
220 
221  has_any (coll, function1, _1, _1 ); _NL_
222  has_any (coll, &function1, _1, _1 ); _NL_
223  has_any (coll, fun1, _1, _1 ); _NL_
224 
225  //does not compile.....
226  // for_each (coll, function1, 10, 20, _1 );
227  // for_each (coll, function1, _1, _2 );
228  // for_each (coll, function1, 10 );
229  }
230 
231 
245  template<typename CO>
246  void
248  {
249  ANNOUNCE (assign_to_input);
250  function<bool(int,int,int&)> fun2(function2);
251 
252  for_each (coll, function2, 5, 5, _1 ); _NL_
253  for_each (coll, &function2,5, 5, _1 ); _NL_
254 
255  and_all (coll, function2, 5, 5, _1 ); _NL_
256  and_all (coll, &function2, 5, 5, _1 ); _NL_
257 
258  has_any (coll, function2, 5, 5, _1 ); _NL_
259  has_any (coll, &function2, 5, 5, _1 ); _NL_
260 
261  // note: in C++11, the reference parameters are passed through
262  // even when wrapping the function or function pointer into a function object,
263  for_each (coll,fun2, 5, 5, _1 ); _NL_
264  and_all (coll, fun2, 5, 5, _1 ); _NL_
265  has_any (coll, fun2, 5, 5, _1 ); _NL_
266  // at that point we have added 9 * (5+5) to the value at position zero.
267  // (note that the has_any only evaluates the function once)
268 
269 
270  // the following test assigns the sum via the ref argument to a local variable.
271  int sum=0;
272  ANNOUNCE (assign_to_var);
273  for_each (coll, function2, -10, _1, ref(sum) ); _NL_
274  for_each (coll, &function2,-10, _1, ref(sum) ); _NL_
275  for_each (coll, fun2, -10, _1, ref(sum) ); _NL_
276  cout << "sum=" << sum << endl;
277 
278  sum=0;
279  and_all (coll, function2, -10, _1, ref(sum) ); _NL_
280  and_all (coll, &function2, -10, _1, ref(sum) ); _NL_
281  and_all (coll, fun2, -10, _1, ref(sum) ); _NL_
282  cout << "sum=" << sum << endl;
283 
284  sum=0;
285  has_any (coll, function2, -10, _1, ref(sum) ); _NL_
286  has_any (coll, &function2, -10, _1, ref(sum) ); _NL_
287  has_any (coll, fun2, -10, _1, ref(sum) ); _NL_
288  cout << "sum=" << sum << endl;
289  }
290 
291 
295  template<typename CO>
296  void
297  check_foreach_bind_const (CO const& coll)
298  {
299  ANNOUNCE (check_foreach_bind_const);
300 
301  for_each (coll,function1, 10, _1 ); _NL_
302  and_all (coll, function1, 10, _1 ); _NL_
303  has_any (coll, function1, 10, _1 ); _NL_
304 
305  for_each (coll,function1, _1, _1 ); _NL_
306  and_all (coll, function1, _1, _1 ); _NL_
307  has_any (coll, function1, _1, _1 ); _NL_
308 
309  int sum=0;
310 
311  for_each (coll,function2, _1, _1, ref(sum) ); _NL_
312  and_all (coll, function2, _1, _1, ref(sum) ); _NL_
313  has_any (coll, function2, _1, _1, ref(sum) ); _NL_
314  }
315 
316 
317 
318  struct Dummy
319  {
320  int sum_;
321 
322  bool
323  fun (int i)
324  {
325  sum_ += i;
326  return plainFunc (sum_);
327  }
328  };
329 
331  template<typename CO>
332  void
334  {
335  ANNOUNCE (check_foreach_memFun);
336 
337  Dummy dummy;
338  dummy.sum_ = 0;
339 
340  for_each (coll, &Dummy::fun, dummy, _1 ); _NL_
341  and_all (coll, &Dummy::fun, dummy, _1 ); _NL_
342  has_any (coll, &Dummy::fun, dummy, _1 ); _NL_
343 
344  for_each (coll, &Dummy::fun, &dummy, _1 ); _NL_
345  and_all (coll, &Dummy::fun, &dummy, _1 ); _NL_
346  has_any (coll, &Dummy::fun, &dummy, _1 ); _NL_
347 
348  cout << "sum=" << dummy.sum_ << endl;
349  }
350 
351 
353  template<typename CO>
354  void
356  {
357  ANNOUNCE (check_foreach_lambda);
358  uint sum(0);
359 
360  for_each (coll, [&sum] (uint entry) { sum += entry; });
361 
362  CHECK (sum == (NUM_ELMS+1) * NUM_ELMS/2);
363 
364  CHECK (!and_all (coll, [] (uint elm) { return elm - 1; }));
365  CHECK ( has_any (coll, [] (uint elm) { return elm + 1; }));
366  }
367 
368 
371  template<typename CO>
372  void
374  {
375  ANNOUNCE (check_existence_quant);
376 
377  CHECK ( and_all (coll, [] (uint elm) { return 0 < elm; }));
378  CHECK (!and_all (coll, [] (uint elm) { return 1 < elm; }));
379 
380  CHECK ( has_any (coll, [] (uint elm) { return 0 < elm; }));
381  CHECK ( has_any (coll, [] (uint elm) { return elm == NUM_ELMS; }));
382  CHECK (!has_any (coll, [] (uint elm) { return elm > NUM_ELMS; }));
383  }
384 
385 
386  struct TestElm
387  {
388  uint n_;
389  TestElm(uint i) : n_(i) {}
390 
391  bool operation() { return plainFunc (n_); }
392  };
393 
394 
398  void
400  {
401  ANNOUNCE (check_invoke_on_each);
402 
403  std::vector<TestElm> elms;
404  for (uint i=0; i<6; ++i)
405  elms.push_back (TestElm(i));
406 
407  std::vector<TestElm*> elmPtrs;
408  for (uint i=0; i<6; ++i)
409  elmPtrs.push_back (& elms[i]);
410 
411  // fed the element pointer as "this" pointer of the member function
412  for_each (elmPtrs, &TestElm::operation, _1 ); _NL_
413  and_all (elmPtrs, &TestElm::operation, _1 ); _NL_
414  has_any (elmPtrs, &TestElm::operation, _1 ); _NL_
415 
416  // the same works with copies of the elements as well...
417  for_each (elms, &TestElm::operation, _1 ); _NL_
418  and_all (elms, &TestElm::operation, _1 ); _NL_
419  has_any (elms, &TestElm::operation, _1 ); _NL_
420 
421  // note: it seems not to be possible to create a binder, which takes the "*this"-Argument by ref
422  }
423 
424 
436  void
438  {
439  ANNOUNCE (wrapped_container_passing);
440 
441 #define SHOW_CONTAINER for_each (coll, plainFunc); _NL_
442 
443  int counter = NUM_ELMS;
444  auto assign_and_decrement = [&] (int& entry)
445  {
446  entry = counter--;
447  };
448 
449  // use a const reference to pass the container...
450  VecI const& passByConstRef (coll);
451 
452  for_each (passByConstRef, assign_and_decrement );
453 
454  SHOW_CONTAINER
455  // indeed got modifications into the original container!
456  CHECK (0 == counter);
457 
458  // passing anonymous temporary
459  for_each (buildTestNumberz(NUM_ELMS), assign_and_decrement );
460 
461  // passing a smart-ptr managed copy
462  std::shared_ptr<VecI> bySmartPtr (new VecI (coll));
463 
464  for_each (bySmartPtr, assign_and_decrement );
465 
466  // both didn't influence the original container
467  SHOW_CONTAINER
468  CHECK (-2*int(NUM_ELMS) == counter);
469  CHECK (bySmartPtr->back() == counter+1);
470 
471  // passing the container by pointer is also possible
472  const VecI * const passByConstPointer (&coll);
473 
474  for_each (passByConstPointer, assign_and_decrement );
475  SHOW_CONTAINER
476  // ...and does indeed influence the original container
477  }
478 
479  };
480 
481 
482 
483 
484  LAUNCHER (UtilForeach_test, "unit common");
485 
486 
487 }} // namespace util::test
488 
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:49
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.
Simple 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)