c++-gtk-utils
parallel.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 and 2014 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_PARALLEL_H
40 #define CGU_PARALLEL_H
41 
42 #include <utility> // for std::move, std::forward and std::pair
43 #include <memory> // for std::unique_ptr
44 #include <iterator> // for std::iterator_traits and std::distance
45 #include <exception> // for std::exception
46 #include <functional> // for std::bind
47 #include <type_traits> // for std::remove_reference and std::remove_const
48 #include <limits> // for std::numeric_limits
49 #include <algorithm> // for std::min
50 #include <tuple>
51 
52 #include <c++-gtk-utils/callback.h>
54 #include <c++-gtk-utils/mutex.h>
56 
57 namespace Cgu {
58 
59 namespace Thread {
60 
61 struct ParallelError: public std::exception {
62  virtual const char* what() const throw() {return "ParallelError\n";}
63 };
64 
65 #ifndef DOXYGEN_PARSING
66 
67 // in version 2.0.19, this was the ParallelHelper namespace. Because
68 // the meaning of the DiffType* argument of these functions has
69 // changed in version 2.0.20 (it is incremented rather than
70 // decremented), this is now the ParallelHelper2 namespace so that no
71 // ODR issues arise on library linking with old binaries
72 namespace ParallelHelper2 {
73 
74 template <class ArgRefType, class DiffType, class Iterator>
75 void for_each_cb_func(const Cgu::Callback::SafeFunctorArg<ArgRefType>& s_task,
76  Iterator iter,
77  Mutex* m, Cond* cond,
78  DiffType* done_count) {
79  s_task(*iter);
80  Mutex::Lock l{*m};
81  ++*done_count;
82  cond->signal();
83 }
84 
85 template <class FType, class ArgRefType, class DestType>
86 void transform1_func(const FType& func,
87  ArgRefType arg,
88  DestType& res) {
89  res = func(arg);
90 }
91 
92 
93 template <class ArgRefType, class DestType, class DiffType, class SourceIterator>
94 void transform1_cb_func(const Cgu::Callback::SafeFunctorArg<ArgRefType, DestType&>& s_task,
95  SourceIterator source_iter,
96  Mutex* m, Cond* cond,
97  DiffType* done_count,
98  DestType* results,
99  DiffType index) {
100  DestType res;
101  s_task(*source_iter, res);
102  Mutex::Lock l{*m};
103  // move to 'results' within the mutex because g++ <= 4.7 does not
104  // correctly implement the C++11 memory model on some 64 bit
105  // platforms (this is a slight pessimization for gcc >= 4.8)
106  results[index] = std::move(res);
107  ++*done_count;
108  cond->signal();
109 }
110 
111 template <class FType, class Arg1RefType,
112  class Arg2RefType, class DestType>
113 void transform2_func(const FType& func,
114  Arg1RefType arg1,
115  Arg2RefType arg2,
116  DestType& res) {
117  res = func(arg1, arg2);
118 }
119 
120 
121 template <class Arg1RefType, class Arg2RefType, class DestType,
122  class DiffType, class SourceIterator1, class SourceIterator2>
123 void transform2_cb_func(const Cgu::Callback::SafeFunctorArg<Arg1RefType, Arg2RefType, DestType&>& s_task,
124  SourceIterator1 source_iter1,
125  SourceIterator2 source_iter2,
126  Mutex* m, Cond* cond,
127  DiffType* done_count,
128  DestType* results,
129  DiffType index) {
130  DestType res;
131  s_task(*source_iter1, *source_iter2, res);
132  Mutex::Lock l{*m};
133  // move to 'results' within the mutex because g++ <= 4.7 does not
134  // correctly implement the C++11 memory model on some 64 bit
135  // platforms (this is a slight pessimization for gcc >= 4.8)
136  results[index] = std::move(res);
137  ++*done_count;
138  cond->signal();
139 }
140 
141 template <class DiffType>
142 void fail_func(Mutex* m, Cond* cond,
143  bool* error, DiffType* done_count) {
144  Mutex::Lock l{*m};
145  ++*done_count;
146  *error = true;
147  cond->signal();
148 }
149 
150 inline void fail_cb_func(const Cgu::Callback::SafeFunctor& s_fail) {
151  s_fail();
152 }
153 
154 } // namespace ParallelHelper2
155 
156 #endif // DOXYGEN_PARSING
157 
158 /**
159  * \#include <c++-gtk-utils/parallel.h>
160  * @sa Cgu::IntIter
161  *
162  * This function applies a callable object to each element of a
163  * container in the range ['first', 'last'), by executing each such
164  * application as a task of a Thread::TaskManager object. Tasks are
165  * added to the Thread::TaskManager object in the order in which the
166  * respective elements appear in the container (and if a task mutates
167  * its argument, it will do so in respect of the correct element of
168  * the container), but no other ordering arises, and the tasks will
169  * execute in parallel to the extent that the Thread::TaskManager
170  * object has sufficient threads available to do so.
171  *
172  * Apart from that, and that this function returns void, it does the
173  * same as std::for_each(). It can mutate container elements if the
174  * callable object takes its argument by non-const reference. It will
175  * not return until the callable object has been applied to all of the
176  * elements in the range ['first', 'last').
177  *
178  * This function can be called by a task running on the same
179  * TaskManager object. However if that is done, as the task would end
180  * up blocking on its sub-tasks, the maximum number of threads running
181  * on the TaskManager object should be incremented by one temporarily
182  * while this function is executing using the TaskManager::IncHandle
183  * scoped handle class in order to prevent any deadlock through thread
184  * starvation.
185  *
186  * @param tm The Thread::TaskManager object on which the tasks will
187  * run.
188  * @param first The beginning of the range to which 'func' is to be
189  * applied.
190  * @param last One past the last element to which 'func' is to be
191  * applied.
192  * @param func A callable object to be applied to each element in the
193  * range ['first', 'last'), such as formed by a lambda expression or
194  * the result of std::bind. It should take a single unbound argument
195  * of the value type of the container to which 'first' and 'last'
196  * relate or a const or non-const reference to that type. Any return
197  * value is discarded. If an exception propagates from 'func', the
198  * exception will be consumed while the for each loop is running, and
199  * an attempt will still be made to apply 'func' to all remaining
200  * elements in the range ['first', 'last'), and only after that
201  * attempt has completed will the exception Cgu::Thread::ParallelError
202  * be thrown.
203  * @exception std::bad_alloc This exception will be thrown if memory
204  * is exhausted and the system throws in that case. (On systems with
205  * over-commit/lazy-commit combined with virtual memory (swap), it is
206  * rarely useful to check for memory exhaustion). If this exception
207  * is thrown, some tasks may nonetheless have already started by
208  * virtue of the call to this function, but subsequent ones will not.
209  * @exception Cgu::Thread::TaskError This exception will be thrown if
210  * stop_all() has previously been called on the Thread::TaskManager
211  * object, or if another thread calls stop_all() after this method is
212  * called but before it has returned. It will also be thrown if the
213  * Thread::TaskManager object's is_error() method would return true
214  * because its internal thread pool loop implementation has thrown
215  * std::bad_alloc, or a thread has failed to start correctly because
216  * pthread has run out of resources. (On systems with
217  * over-commit/lazy-commit combined with virtual memory (swap), it is
218  * rarely useful to check for memory exhaustion, and if a reasonable
219  * maximum thread count has been chosen for the Thread::TaskManager
220  * object pthread should not run out of other resources, but there may
221  * be some specialized cases where the return value of is_error() is
222  * useful.) If this exception is thrown, some tasks may nonetheless
223  * have already started by virtue of the call to this function.
224  * @exception Cgu::Thread::ParallelError This exception will be thrown
225  * if an exception propagates from the 'func' callable object when it
226  * executes on being applied to one or more elements of the container.
227  * Such an exception will not stop an attempt being made to apply
228  * 'func' (successfully or unsuccessfully) to all elements in the
229  * range ['first', 'last'). Cgu::Thread::ParallelError will be thrown
230  * after such attempted application has finished.
231  * @exception Cgu::Thread::MutexError This exception will be thrown if
232  * initialization of a mutex used by this function fails. (It is
233  * often not worth checking for this, as it means either memory is
234  * exhausted or pthread has run out of other resources to create new
235  * mutexes.) If this exception is thrown, no tasks will start.
236  * @exception Cgu::Thread::CondError This exception will be thrown if
237  * initialization of a condition variable used by this function fails.
238  * (It is often not worth checking for this, as it means either memory
239  * is exhausted or pthread has run out of other resources to create
240  * new condition variables.) If this exception is thrown, no tasks
241  * will start.
242  * @note 1. An exception might also be thrown if the copy or move
243  * constructor of the 'func' callable objects throws. If such an
244  * exception is thrown, no tasks will start.
245  * @note 2. Prior to version 2.0.27, this function could not take a
246  * source iterator to const. This was fixed in version 2.0.27.
247  *
248  * Since 2.0.19
249  */
250 template <class Iterator, class Func>
252  Iterator first,
253  Iterator last,
254  Func&& func) {
255 
256  typedef typename std::iterator_traits<Iterator>::reference ArgRefType;
257  typedef typename std::iterator_traits<Iterator>::difference_type DiffType;
258 
259  Mutex mutex;
260  Cond cond;
261  DiffType start_count = 0;
262  DiffType done_count = 0;
263  bool error = false;
264 
265  // construct SafeFunctorArg objects so that they can be shared
266  // between different tasks
268  Cgu::Callback::lambda<ArgRefType>(std::forward<Func>(func))
269  };
271  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
272  &mutex,
273  &cond,
274  &error,
275  &done_count)
276  };
277 
278  for (; first != last; ++first, ++start_count) {
279 #ifdef CGU_USE_AUTO_PTR
280  typedef std::auto_ptr<const Callback::Callback> CbPtr;
281 #else
282  typedef std::unique_ptr<const Callback::Callback> CbPtr;
283 #endif
284 
285  CbPtr task_cb(
286  Cgu::Callback::make_ref(&ParallelHelper2::for_each_cb_func<ArgRefType, DiffType, Iterator>,
287  s_task,
288  first,
289  &mutex,
290  &cond,
291  &done_count)
292  );
293  CbPtr fail_cb(
294  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
295  );
296 
297  tm.add_task(std::move(task_cb), std::move(fail_cb));
298  }
299 
300  Mutex::Lock l{mutex};
301  while (start_count > done_count) cond.wait(mutex);
302  if (error) throw ParallelError();
303 }
304 
305 /**
306  * \#include <c++-gtk-utils/parallel.h>
307  * @sa Cgu::IntIter
308  *
309  * This function maps over a container in the range ['first', 'last'),
310  * applying a unary callable object to each element of the container
311  * in that range and storing the result in the destination range, by
312  * executing each such application as a task of a Thread::TaskManager
313  * object. Tasks are added to the Thread::TaskManager object in the
314  * order in which the respective elements appear in the source
315  * container, and the final result appears in the destination
316  * container in the same order as the source range from which it is
317  * generated (including if a back_inserter iterator is used), but no
318  * other ordering arises, and the tasks will execute in parallel to
319  * the extent that the Thread::TaskManager object has sufficient
320  * threads available to do so.
321  *
322  * Apart from that, this function does the same as the version of
323  * std::transform() taking a unary function, except that it returns
324  * void (see Thread::parallel_transform_partial() for a function which
325  * returns a destination iterator and an iterator to the source
326  * range). It will not return until the callable object has been
327  * applied to all of the elements in the range ['first', 'last').
328  *
329  * This function can be called by a task running on the same
330  * TaskManager object, perhaps with a view to delivering a result
331  * asynchronously to a glib main loop. However if that is done, as
332  * the task would end up blocking on its sub-tasks, the maximum number
333  * of threads running on the TaskManager object should be incremented
334  * by one temporarily while this function is executing using the
335  * TaskManager::IncHandle scoped handle class in order to prevent any
336  * deadlock through thread starvation.
337  *
338  * A task can carry out a map-reduce operation by passing the result
339  * of calling this function to std::accumulate() to perform a
340  * fold-left or fold-right on that result.
341  *
342  * A separate overload of this function takes a binary callable
343  * object.
344  *
345  * Here is a trivial example of a map-reduce operation which maps over
346  * a vector by multiplying each element by 2 in separate tasks, and
347  * then folds-left using std::accumulate() (std::accumulate() can fold
348  * using any callable object, but in this example the default of
349  * addition is used):
350  *
351  * @code
352  * using namespace Cgu;
353  * std::vector<int> v{1, 2, 3, 4, 5};
354  * Thread::TaskManager tm;
355  *
356  * Thread::parallel_transform(tm,
357  * v.begin(),
358  * v.end(),
359  * v.begin(),
360  * [] (int elt) {return elt * 2;});
361  * // res will be equal to 30
362  * int res = std::accumulate(v.begin(), v.end(), 0);
363  * @endcode
364  *
365  * @param tm The Thread::TaskManager object on which the tasks will
366  * run.
367  * @param first The beginning of the range to which 'func' is to be
368  * applied.
369  * @param last One past the last element to which 'func' is to be
370  * applied.
371  * @param dest The beginning of the range to which the result of
372  * applying 'func' to the elements in the range ['first', 'last') is
373  * to be stored. As in the case of std::transform, this can overlap
374  * with or be the same as the source range. It may also be an insert
375  * iterator.
376  * @param func A unary callable object to be applied to each element
377  * in the range ['first', 'last'), such as formed by a lambda
378  * expression or the result of std::bind. It should take a single
379  * unbound argument of the value type of the container to which
380  * 'first' and 'last' relate or a const or non-const reference to that
381  * type. If an exception propagates from 'func', the exception will
382  * be consumed while the transform loop is running, and an attempt
383  * will still be made to apply 'func' to all remaining elements in the
384  * range ['first', 'last'), and only after that attempt has completed
385  * will the exception Cgu::Thread::ParallelError be thrown.
386  * @exception std::bad_alloc This exception will be thrown if memory
387  * is exhausted and the system throws in that case. (On systems with
388  * over-commit/lazy-commit combined with virtual memory (swap), it is
389  * rarely useful to check for memory exhaustion). If this exception
390  * is thrown, some tasks may nonetheless have already started by
391  * virtue of the call to this function, but subsequent ones will not.
392  * @exception Cgu::Thread::TaskError This exception will be thrown if
393  * stop_all() has previously been called on the Thread::TaskManager
394  * object, or if another thread calls stop_all() after this method is
395  * called but before it has returned. It will also be thrown if the
396  * Thread::TaskManager object's is_error() method would return true
397  * because its internal thread pool loop implementation has thrown
398  * std::bad_alloc, or a thread has failed to start correctly because
399  * pthread has run out of resources. (On systems with
400  * over-commit/lazy-commit combined with virtual memory (swap), it is
401  * rarely useful to check for memory exhaustion, and if a reasonable
402  * maximum thread count has been chosen for the Thread::TaskManager
403  * object pthread should not run out of other resources, but there may
404  * be some specialized cases where the return value of is_error() is
405  * useful.) If this exception is thrown, some tasks may nonetheless
406  * have already started by virtue of the call to this function.
407  * @exception Cgu::Thread::ParallelError This exception will be thrown
408  * if an exception propagates from the 'func' callable object when it
409  * executes on being applied to one or more elements of the source
410  * container. Such an exception will not stop an attempt being made
411  * to apply 'func' (successfully or unsuccessfully) to all elements in
412  * the range ['first', 'last'). Cgu::Thread::ParallelError will be
413  * thrown after such attempted application has finished.
414  * @exception Cgu::Thread::MutexError This exception will be thrown if
415  * initialization of a mutex used by this function fails. (It is
416  * often not worth checking for this, as it means either memory is
417  * exhausted or pthread has run out of other resources to create new
418  * mutexes.) If this exception is thrown, no tasks will start.
419  * @exception Cgu::Thread::CondError This exception will be thrown if
420  * initialization of a condition variable used by this function fails.
421  * (It is often not worth checking for this, as it means either memory
422  * is exhausted or pthread has run out of other resources to create
423  * new condition variables.) If this exception is thrown, no tasks
424  * will start.
425  * @note 1. An exception might also be thrown if the copy or move
426  * constructor of the 'func' callable objects throws. If such an
427  * exception is thrown, no tasks will start.
428  * @note 2. Prior to version 2.0.27, this function could not take a
429  * source iterator to const. This was fixed in version 2.0.27.
430  *
431  * Since 2.0.19
432  */
433 template <class SourceIterator, class DestIterator, class Func>
435  SourceIterator first,
436  SourceIterator last,
437  DestIterator dest,
438  Func&& func) {
439 
440  if (first == last) return;
441 
442  typedef typename std::iterator_traits<SourceIterator>::reference ArgRefType;
443  typedef typename std::iterator_traits<SourceIterator>::difference_type DiffType;
444  typedef typename std::remove_const<typename std::remove_reference<Func>::type>::type FType;
445  typedef decltype(func(*first)) DestType;
446 
447  Mutex mutex;
448  Cond cond;
449  DiffType start_count = 0;
450  DiffType done_count = 0;
451  bool error = false;
452 
453  // intermediate results have to be held in an array so destination
454  // ordering can be enforced when using insert interators. This
455  // causes some inefficiency for non-random access iterators
456  std::unique_ptr<DestType[]> results(new DestType[std::distance(first, last)]);
457 
458  // construct SafeFunctorArg objects so that they can be shared
459  // between different tasks
461  Cgu::Callback::make_ref(&ParallelHelper2::transform1_func<FType, ArgRefType, DestType>,
462  std::forward<Func>(func))
463  };
465  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
466  &mutex,
467  &cond,
468  &error,
469  &done_count)
470  };
471 
472  for (; first != last; ++first, ++start_count) {
473 #ifdef CGU_USE_AUTO_PTR
474  typedef std::auto_ptr<const Callback::Callback> CbPtr;
475 #else
476  typedef std::unique_ptr<const Callback::Callback> CbPtr;
477 #endif
478  CbPtr task_cb(
479  Cgu::Callback::lambda<>(std::bind(&ParallelHelper2::transform1_cb_func<ArgRefType, DestType, DiffType, SourceIterator>,
480  s_task,
481  first,
482  &mutex,
483  &cond,
484  &done_count,
485  results.get(),
486  start_count))
487  );
488  CbPtr fail_cb(
489  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
490  );
491 
492  tm.add_task(std::move(task_cb), std::move(fail_cb));
493  }
494 
495  Mutex::Lock l{mutex};
496  while (start_count > done_count) cond.wait(mutex);
497  if (error) throw ParallelError();
498  for (DiffType index = 0; index < start_count; ++dest, ++index) {
499  *dest = std::move(results[index]);
500  }
501 }
502 
503 /**
504  * \#include <c++-gtk-utils/parallel.h>
505  * @sa Cgu::IntIter
506  *
507  * This function maps over two containers, one in the range ['first1',
508  * 'last1') and the other beginning at 'first2', applying a binary
509  * callable object to each element of the containers in those ranges
510  * and storing the result in the destination range, by executing each
511  * such application as a task of a Thread::TaskManager object. Tasks
512  * are added to the Thread::TaskManager object in the order in which
513  * the respective elements appear in the source containers, and the
514  * final result appears in the destination container in the same order
515  * as the source ranges from which it is generated (including if a
516  * back_inserter iterator is used), but no other ordering arises, and
517  * the tasks will execute in parallel to the extent that the
518  * Thread::TaskManager object has sufficient threads available to do
519  * so.
520  *
521  * Apart from that, this function does the same as the version of
522  * std::transform() taking a binary function, except that it returns
523  * void (see Thread::parallel_transform_partial() for a function which
524  * returns a destination iterator and iterators to the source ranges).
525  * It will not return until the callable object has been applied to
526  * all of the elements in the source ranges.
527  *
528  * This function can be called by a task running on the same
529  * TaskManager object, perhaps with a view to delivering a result
530  * asynchronously to a glib main loop. However if that is done, as
531  * the task would end up blocking on its sub-tasks, the maximum number
532  * of threads running on the TaskManager object should be incremented
533  * by one temporarily while this function is executing using the
534  * TaskManager::IncHandle scoped handle class in order to prevent any
535  * deadlock through thread starvation.
536  *
537  * A task can carry out a map-reduce operation by passing the result
538  * of calling this function to std::accumulate() to perform a
539  * fold-left or fold-right on that result.
540  *
541  * A separate overload of this function takes a unary callable object.
542  *
543  * Here is a trivial example of a map-reduce operation which maps over
544  * two vectors by adding respective elements of the vectors in
545  * separate tasks, and then folds-left using std::accumulate()
546  * (std::accumulate() can fold using any callable object, but in this
547  * example the default of addition is used):
548  *
549  * @code
550  * using namespace Cgu;
551  * std::vector<int> v1{2, 4, 6, 8, 10};
552  * std::vector<int> v2{10, 20, 30, 40, 50};
553  * std::vector<int> v3;
554  * Thread::TaskManager tm;
555  *
556  * Thread::parallel_transform(tm,
557  * v1.begin(),
558  * v1.end(),
559  * v2.begin(),
560  * std::back_inserter(v3),
561  * std::plus<int>());
562  * // res will be equal to 180
563  * int res = std::accumulate(v3.begin(), v3.end(), 0);
564  * @endcode
565  *
566  * @param tm The Thread::TaskManager object on which the tasks will
567  * run.
568  * @param first1 The beginning of the range which is to be passed as
569  * the first argument of 'func'.
570  * @param last1 One past the last element of the range which is to be
571  * passed as the first argument of 'func'.
572  * @param first2 The beginning of the range which is to be passed as
573  * the second argument of 'func'.
574  * @param dest The beginning of the range to which the result of
575  * applying 'func' to the elements in the source ranges is to be
576  * stored. As in the case of std::transform, this can overlap with or
577  * be the same as one of the source ranges. It may also be an insert
578  * iterator.
579  * @param func A binary callable object to be applied to each element
580  * in the source ranges, such as formed by a lambda expression or the
581  * result of std::bind. It should take two unbound arguments of the
582  * value types of the containers to which 'first1' and 'first2' relate
583  * or const or non-const references to those types. If an exception
584  * propagates from 'func', the exception will be consumed while the
585  * transform loop is running, and an attempt will still be made to
586  * apply 'func' to all remaining elements of the source ranges, and
587  * only after that attempt has completed will the exception
588  * Cgu::Thread::ParallelError be thrown.
589  * @exception std::bad_alloc This exception will be thrown if memory
590  * is exhausted and the system throws in that case. (On systems with
591  * over-commit/lazy-commit combined with virtual memory (swap), it is
592  * rarely useful to check for memory exhaustion). If this exception
593  * is thrown, some tasks may nonetheless have already started by
594  * virtue of the call to this function, but subsequent ones will not.
595  * @exception Cgu::Thread::TaskError This exception will be thrown if
596  * stop_all() has previously been called on the Thread::TaskManager
597  * object, or if another thread calls stop_all() after this method is
598  * called but before it has returned. It will also be thrown if the
599  * Thread::TaskManager object's is_error() method would return true
600  * because its internal thread pool loop implementation has thrown
601  * std::bad_alloc, or a thread has failed to start correctly because
602  * pthread has run out of resources. (On systems with
603  * over-commit/lazy-commit combined with virtual memory (swap), it is
604  * rarely useful to check for memory exhaustion, and if a reasonable
605  * maximum thread count has been chosen for the Thread::TaskManager
606  * object pthread should not run out of other resources, but there may
607  * be some specialized cases where the return value of is_error() is
608  * useful.) If this exception is thrown, some tasks may nonetheless
609  * have already started by virtue of the call to this function.
610  * @exception Cgu::Thread::ParallelError This exception will be thrown
611  * if an exception propagates from the 'func' callable object when it
612  * executes on being applied to one or more elements of the source
613  * ranges. Such an exception will not stop an attempt being made to
614  * apply 'func' (successfully or unsuccessfully) to all elements in
615  * the source ranges. Cgu::Thread::ParallelError will be thrown after
616  * such attempted application has finished.
617  * @exception Cgu::Thread::MutexError This exception will be thrown if
618  * initialization of a mutex used by this function fails. (It is
619  * often not worth checking for this, as it means either memory is
620  * exhausted or pthread has run out of other resources to create new
621  * mutexes.) If this exception is thrown, no tasks will start.
622  * @exception Cgu::Thread::CondError This exception will be thrown if
623  * initialization of a condition variable used by this function fails.
624  * (It is often not worth checking for this, as it means either memory
625  * is exhausted or pthread has run out of other resources to create
626  * new condition variables.) If this exception is thrown, no tasks
627  * will start.
628  * @note 1. An exception might also be thrown if the copy or move
629  * constructor of the 'func' callable objects throws. If such an
630  * exception is thrown, no tasks will start.
631  * @note 2. Prior to version 2.0.27, this function could not take a
632  * source iterator to const. This was fixed in version 2.0.27.
633  *
634  * Since 2.0.19
635  */
636 template <class SourceIterator1, class SourceIterator2, class DestIterator, class Func>
638  SourceIterator1 first1,
639  SourceIterator1 last1,
640  SourceIterator2 first2,
641  DestIterator dest,
642  Func&& func) {
643 
644  if (first1 == last1) return;
645 
646  typedef typename std::iterator_traits<SourceIterator1>::reference Arg1RefType;
647  typedef typename std::iterator_traits<SourceIterator1>::difference_type DiffType;
648  typedef typename std::iterator_traits<SourceIterator2>::reference Arg2RefType;
649  typedef typename std::remove_const<typename std::remove_reference<Func>::type>::type FType;
650  typedef decltype(func(*first1, *first2)) DestType;
651 
652  Mutex mutex;
653  Cond cond;
654  DiffType start_count = 0;
655  DiffType done_count = 0;
656  bool error = false;
657 
658  // intermediate results have to be held in an array so destination
659  // ordering can be enforced when using insert interators. This
660  // causes some inefficiency for non-random access iterators
661  std::unique_ptr<DestType[]> results(new DestType[std::distance(first1, last1)]);
662 
663  // construct SafeFunctorArg objects so that they can be shared
664  // between different tasks
666  Cgu::Callback::make_ref(&ParallelHelper2::transform2_func<FType, Arg1RefType, Arg2RefType, DestType>,
667  std::forward<Func>(func))
668  };
670  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
671  &mutex,
672  &cond,
673  &error,
674  &done_count)
675  };
676 
677  for (; first1 != last1; ++first1, ++first2, ++start_count) {
678 #ifdef CGU_USE_AUTO_PTR
679  typedef std::auto_ptr<const Callback::Callback> CbPtr;
680 #else
681  typedef std::unique_ptr<const Callback::Callback> CbPtr;
682 #endif
683  CbPtr task_cb(
684  Cgu::Callback::lambda<>(std::bind(&ParallelHelper2::transform2_cb_func<Arg1RefType, Arg2RefType, DestType, DiffType, SourceIterator1, SourceIterator2>,
685  s_task,
686  first1,
687  first2,
688  &mutex,
689  &cond,
690  &done_count,
691  results.get(),
692  start_count))
693  );
694  CbPtr fail_cb(
695  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
696  );
697 
698  tm.add_task(std::move(task_cb), std::move(fail_cb));
699  }
700 
701  Mutex::Lock l{mutex};
702  while (start_count > done_count) cond.wait(mutex);
703  if (error) throw ParallelError();
704  for (DiffType index = 0; index < start_count; ++dest, ++index) {
705  *dest = std::move(results[index]);
706  }
707 }
708 
709 /**
710  * \#include <c++-gtk-utils/parallel.h>
711  * @sa Cgu::IntIter
712  *
713  * This function applies a callable object to each element of a
714  * container in the range ['first', 'last') subject to a maximum, by
715  * executing each such application as a task of a Thread::TaskManager
716  * object. Tasks are added to the Thread::TaskManager object in the
717  * order in which the respective elements appear in the container (and
718  * if a task mutates its argument, it will do so in respect of the
719  * correct element of the container), but no other ordering arises,
720  * and the tasks will execute in parallel to the extent that the
721  * Thread::TaskManager object has sufficient threads available to do
722  * so.
723  *
724  * This function does the same as Thread::parallel_for_each(), except
725  * that it returns an iterator to the element past the last element to
726  * which the callable object has been applied, and it has a 'max'
727  * parameter to limit the maximum number of elements to which the
728  * callable object will be applied on any one call to this function
729  * even if the range ['first', 'last') is greater than this maximum.
730  * Whether this limitation has had effect on any one call can be
731  * tested by checking whether the return value is equal to the 'last'
732  * parameter. If it is not, a further call to this function can be
733  * made.
734  *
735  * The main purpose of this additional function is to enable the
736  * application of the callable object to the elements of a container
737  * to be dealt with in chunks, possibly to enable other tasks to be
738  * interleaved at reasonable intervals. For a container which does
739  * not support random access iterators, the 'last' parameter can be
740  * set to, say, the end of the container and the chunk size set with
741  * the 'max' paramater, with the return value being used as the
742  * 'first' parameter for subsequent calls to this function. This
743  * avoids having to increment the iterator for each "chunk" by
744  * stepping through the container by hand. In this usage, it
745  * therefore represents a minor efficiency improvement.
746  *
747  * @param tm The Thread::TaskManager object on which the tasks will
748  * run.
749  * @param first The beginning of the range to which 'func' is to be
750  * applied.
751  * @param last One past the last element to which 'func' is to be
752  * applied, subject to any maximum specified as the 'max' parameter.
753  * @param max The maximum number of elements of the source container
754  * to which 'func' will be applied on this call. It is not an error
755  * if it is greater than the distance between 'first' and 'last'. If
756  * it is equal to or greater than that distance, it follows that the
757  * iterator returned will be equal to 'last'. The same results if
758  * 'max' is a negative number (in that case no maximum will take
759  * effect and each element in the range ['first', 'last') will have
760  * 'func' applied to it).
761  * @param func A callable object to be applied (subject to the
762  * maximum) to each element in the range ['first', 'last'), such as
763  * formed by a lambda expression or the result of std::bind. It
764  * should take a single unbound argument of the value type of the
765  * container to which 'first' and 'last' relate or a const or
766  * non-const reference to that type. Any return value is discarded.
767  * If an exception propagates from 'func', the exception will be
768  * consumed while the for each loop is running, and an attempt will
769  * still be made to apply 'func' to all remaining elements in the
770  * range ['first', 'last') subject to the maximum, and only after that
771  * attempt has completed will the exception Cgu::Thread::ParallelError
772  * be thrown.
773  * @return An iterator representing the element past the last element
774  * of the range to which 'func' was applied, which may be passed as
775  * the 'first' argument of a subsequent call to this function.
776  * @exception std::bad_alloc This exception will be thrown if memory
777  * is exhausted and the system throws in that case. (On systems with
778  * over-commit/lazy-commit combined with virtual memory (swap), it is
779  * rarely useful to check for memory exhaustion). If this exception
780  * is thrown, some tasks may nonetheless have already started by
781  * virtue of the call to this function, but subsequent ones will not.
782  * @exception Cgu::Thread::TaskError This exception will be thrown if
783  * stop_all() has previously been called on the Thread::TaskManager
784  * object, or if another thread calls stop_all() after this method is
785  * called but before it has returned. It will also be thrown if the
786  * Thread::TaskManager object's is_error() method would return true
787  * because its internal thread pool loop implementation has thrown
788  * std::bad_alloc, or a thread has failed to start correctly because
789  * pthread has run out of resources. (On systems with
790  * over-commit/lazy-commit combined with virtual memory (swap), it is
791  * rarely useful to check for memory exhaustion, and if a reasonable
792  * maximum thread count has been chosen for the Thread::TaskManager
793  * object pthread should not run out of other resources, but there may
794  * be some specialized cases where the return value of is_error() is
795  * useful.) If this exception is thrown, some tasks may nonetheless
796  * have already started by virtue of the call to this function.
797  * @exception Cgu::Thread::ParallelError This exception will be thrown
798  * if an exception propagates from the 'func' callable object when it
799  * executes on being applied to one or more elements of the container.
800  * Such an exception will not stop an attempt being made to apply
801  * 'func' (successfully or unsuccessfully) to all elements in the
802  * range ['first', 'last') subject to the maximum.
803  * Cgu::Thread::ParallelError will be thrown after such attempted
804  * application has finished.
805  * @exception Cgu::Thread::MutexError This exception will be thrown if
806  * initialization of a mutex used by this function fails. (It is
807  * often not worth checking for this, as it means either memory is
808  * exhausted or pthread has run out of other resources to create new
809  * mutexes.) If this exception is thrown, no tasks will start.
810  * @exception Cgu::Thread::CondError This exception will be thrown if
811  * initialization of a condition variable used by this function fails.
812  * (It is often not worth checking for this, as it means either memory
813  * is exhausted or pthread has run out of other resources to create
814  * new condition variables.) If this exception is thrown, no tasks
815  * will start.
816  * @note 1. An exception might also be thrown if the copy or move
817  * constructor of the 'func' callable objects throws. If such an
818  * exception is thrown, no tasks will start.
819  * @note 2. Prior to version 2.0.27, this function could not take a
820  * source iterator to const. This was fixed in version 2.0.27.
821  *
822  * Since 2.0.20
823  */
824 template <class Iterator, class Func>
826  Iterator first,
827  Iterator last,
828  int max,
829  Func&& func) {
830 
831  if (first == last || !max) return first;
832 
833  typedef typename std::iterator_traits<Iterator>::reference ArgRefType;
834  typedef typename std::iterator_traits<Iterator>::difference_type DiffType;
835 
836  Mutex mutex;
837  Cond cond;
838  DiffType start_count = 0;
839  DiffType done_count = 0;
840  bool error = false;
841 
842  // a specialization of std::numeric_limits::max() for all arithmetic
843  // types is required by §3.9.1/8 of the standard. The iterator
844  // difference type must be a signed integer type (§24.2.1/1). All
845  // signed integer types are arithmetic types (§3.9.1/2, §3.9.1/7 and
846  // §3.9.1/8).
847  const DiffType local_max =
848  (max >= 0) ? max : std::numeric_limits<DiffType>::max();
849 
850  // construct SafeFunctorArg objects so that they can be shared
851  // between different tasks
853  Cgu::Callback::lambda<ArgRefType>(std::forward<Func>(func))
854  };
856  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
857  &mutex,
858  &cond,
859  &error,
860  &done_count)
861  };
862 
863  for (; first != last && start_count < local_max; ++first, ++start_count) {
864 #ifdef CGU_USE_AUTO_PTR
865  typedef std::auto_ptr<const Callback::Callback> CbPtr;
866 #else
867  typedef std::unique_ptr<const Callback::Callback> CbPtr;
868 #endif
869  CbPtr task_cb(
870  Cgu::Callback::make_ref(&ParallelHelper2::for_each_cb_func<ArgRefType, DiffType, Iterator>,
871  s_task,
872  first,
873  &mutex,
874  &cond,
875  &done_count)
876  );
877  CbPtr fail_cb(
878  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
879  );
880 
881  tm.add_task(std::move(task_cb), std::move(fail_cb));
882  }
883 
884  Mutex::Lock l{mutex};
885  while (start_count > done_count) cond.wait(mutex);
886  if (error) throw ParallelError();
887  return first;
888 }
889 
890 /**
891  * \#include <c++-gtk-utils/parallel.h>
892  * @sa Cgu::IntIter
893  *
894  * This function maps over a container in the range ['first', 'last')
895  * subject to a maximum, applying a unary callable object to each
896  * element of the container in that range (subject to the maximum) and
897  * storing the result in the destination range, by executing each such
898  * application as a task of a Thread::TaskManager object. Tasks are
899  * added to the Thread::TaskManager object in the order in which the
900  * respective elements appear in the source container, and the final
901  * result appears in the destination container in the same order as
902  * the source range from which it is generated (including if a
903  * back_inserter iterator is used), but no other ordering arises, and
904  * the tasks will execute in parallel to the extent that the
905  * Thread::TaskManager object has sufficient threads available to do
906  * so.
907  *
908  * A separate overload of this function takes a binary callable
909  * object.
910  *
911  * This function does the same as the version of
912  * Thread::parallel_transform() taking a unary callable object, except
913  * that it returns a std::pair object containing an iterator to the
914  * element past the last element of the source range transformed, and
915  * a destination iterator to the element past the last element stored
916  * in the destination range, and it has a 'max' parameter to limit the
917  * maximum number of elements which will be so transformed on any one
918  * call to this function. Whether this limitation has had effect on
919  * any one call can be tested by checking whether the first value of
920  * the pair returned is equal to the 'last' parameter. If it is not,
921  * a further call to this function can be made.
922  *
923  * The main purpose of this additional function is to enable the
924  * parallel transform of the elements of a container to be dealt with
925  * in chunks, possibly to enable other tasks to be interleaved at
926  * reasonable intervals. For source or destination containers which
927  * do not support random access iterators, the 'last' parameter can be
928  * set to, say, the end of the container and the chunk size set with
929  * the 'max' paramater, with the values of the returned pair being
930  * used as the 'first' and 'dest' parameters for subsequent calls to
931  * this function. This avoids having to increment the source and
932  * destination iterators for each "chunk" by stepping through the
933  * respective containers by hand. In this usage, it therefore
934  * represents a minor efficiency improvement.
935  *
936  * @param tm The Thread::TaskManager object on which the tasks will
937  * run.
938  * @param first The beginning of the range to which 'func' is to be
939  * applied.
940  * @param last One past the last element to which 'func' is to be
941  * applied, subject to any maximum specified as the 'max' parameter.
942  * @param dest The beginning of the range to which the result of
943  * applying 'func' to the elements in the source range is to be
944  * stored. As in the case of std::transform, this can overlap with or
945  * be the same as the source range. It may also be an insert
946  * iterator.
947  * @param max The maximum number of elements of the source container
948  * which will be transformed on this call. It is not an error if it
949  * is greater than the distance between 'first' and 'last'. If it is
950  * equal to or greater than that distance, it follows that the first
951  * value of the pair returned by this function will be equal to
952  * 'last'. The same results if 'max' is a negative number (in that
953  * case no maximum will take effect and all elements in the range
954  * ['first', 'last') will be transformed), so passing -1 might be
955  * useful as a means of obtaining a destination iterator (the second
956  * value) for other purposes, particularly where it is not a random
957  * access iterator).
958  * @param func A unary callable object to be applied (subject to the
959  * maximum) to each element in the range ['first', 'last'), such as
960  * formed by a lambda expression or the result of std::bind. It
961  * should take a single unbound argument of the value type of the
962  * container to which 'first' and 'last' relate or a const or
963  * non-const reference to that type. If an exception propagates from
964  * 'func', the exception will be consumed while the transform loop is
965  * running, and an attempt will still be made to apply 'func' to all
966  * remaining elements in the range ['first', 'last') subject to the
967  * maximum, and only after that attempt has completed will the
968  * exception Cgu::Thread::ParallelError be thrown.
969  * @return A std::pair object. Its first member is an iterator
970  * representing the element past the last element of the source range
971  * transformed, which may be passed as the 'first' argument of a
972  * subsequent call to this function; and its second member is an
973  * iterator representing the element past the last element stored in
974  * the destination range, which may be passed as the 'dest' argument
975  * of the subsequent call.
976  * @exception std::bad_alloc This exception will be thrown if memory
977  * is exhausted and the system throws in that case. (On systems with
978  * over-commit/lazy-commit combined with virtual memory (swap), it is
979  * rarely useful to check for memory exhaustion). If this exception
980  * is thrown, some tasks may nonetheless have already started by
981  * virtue of the call to this function, but subsequent ones will not.
982  * @exception Cgu::Thread::TaskError This exception will be thrown if
983  * stop_all() has previously been called on the Thread::TaskManager
984  * object, or if another thread calls stop_all() after this method is
985  * called but before it has returned. It will also be thrown if the
986  * Thread::TaskManager object's is_error() method would return true
987  * because its internal thread pool loop implementation has thrown
988  * std::bad_alloc, or a thread has failed to start correctly because
989  * pthread has run out of resources. (On systems with
990  * over-commit/lazy-commit combined with virtual memory (swap), it is
991  * rarely useful to check for memory exhaustion, and if a reasonable
992  * maximum thread count has been chosen for the Thread::TaskManager
993  * object pthread should not run out of other resources, but there may
994  * be some specialized cases where the return value of is_error() is
995  * useful.) If this exception is thrown, some tasks may nonetheless
996  * have already started by virtue of the call to this function.
997  * @exception Cgu::Thread::ParallelError This exception will be thrown
998  * if an exception propagates from the 'func' callable object when it
999  * executes on being applied to one or more elements of the source
1000  * container. Such an exception will not stop an attempt being made
1001  * to apply 'func' (successfully or unsuccessfully) to all elements in
1002  * the range ['first', 'last') subject to the maximum.
1003  * Cgu::Thread::ParallelError will be thrown after such attempted
1004  * application has finished.
1005  * @exception Cgu::Thread::MutexError This exception will be thrown if
1006  * initialization of a mutex used by this function fails. (It is
1007  * often not worth checking for this, as it means either memory is
1008  * exhausted or pthread has run out of other resources to create new
1009  * mutexes.) If this exception is thrown, no tasks will start.
1010  * @exception Cgu::Thread::CondError This exception will be thrown if
1011  * initialization of a condition variable used by this function fails.
1012  * (It is often not worth checking for this, as it means either memory
1013  * is exhausted or pthread has run out of other resources to create
1014  * new condition variables.) If this exception is thrown, no tasks
1015  * will start.
1016  * @note 1. An exception might also be thrown if the copy or move
1017  * constructor of the 'func' callable objects throws. If such an
1018  * exception is thrown, no tasks will start.
1019  * @note 2. Prior to version 2.0.27, this function could not take a
1020  * source iterator to const. This was fixed in version 2.0.27.
1021  *
1022  * Since 2.0.20
1023  */
1024 template <class SourceIterator, class DestIterator, class Func>
1025 std::pair<SourceIterator, DestIterator>
1027  SourceIterator first,
1028  SourceIterator last,
1029  DestIterator dest,
1030  int max,
1031  Func&& func) {
1032 
1033  if (first == last || !max) return {first, dest};
1034 
1035  typedef typename std::iterator_traits<SourceIterator>::reference ArgRefType;
1036  typedef typename std::iterator_traits<SourceIterator>::difference_type DiffType;
1037  typedef typename std::remove_const<typename std::remove_reference<Func>::type>::type FType;
1038  typedef decltype(func(*first)) DestType;
1039 
1040  Mutex mutex;
1041  Cond cond;
1042  DiffType start_count = 0;
1043  DiffType done_count = 0;
1044  bool error = false;
1045 
1046  // a specialization of std::numeric_limits::max() for all arithmetic
1047  // types is required by §3.9.1/8 of the standard. The iterator
1048  // difference type must be a signed integer type (§24.2.1/1). All
1049  // signed integer types are arithmetic types (§3.9.1/2, §3.9.1/7 and
1050  // §3.9.1/8).
1051  const DiffType local_max =
1052  (max >= 0) ? max : std::numeric_limits<DiffType>::max();
1053 
1054  // intermediate results have to be held in an array so destination
1055  // ordering can be enforced when using insert interators. This
1056  // causes some inefficiency for non-random access iterators
1057  std::unique_ptr<DestType[]> results(new DestType[std::min(local_max,
1058  std::distance(first, last))]);
1059 
1060  // construct SafeFunctorArg objects so that they can be shared
1061  // between different tasks
1063  Cgu::Callback::make_ref(&ParallelHelper2::transform1_func<FType, ArgRefType, DestType>,
1064  std::forward<Func>(func))
1065  };
1067  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
1068  &mutex,
1069  &cond,
1070  &error,
1071  &done_count)
1072  };
1073 
1074  for (; first != last && start_count < local_max; ++first, ++start_count) {
1075 #ifdef CGU_USE_AUTO_PTR
1076  typedef std::auto_ptr<const Callback::Callback> CbPtr;
1077 #else
1078  typedef std::unique_ptr<const Callback::Callback> CbPtr;
1079 #endif
1080  CbPtr task_cb(
1081  Cgu::Callback::lambda<>(std::bind(&ParallelHelper2::transform1_cb_func<ArgRefType, DestType, DiffType, SourceIterator>,
1082  s_task,
1083  first,
1084  &mutex,
1085  &cond,
1086  &done_count,
1087  results.get(),
1088  start_count))
1089  );
1090  CbPtr fail_cb(
1091  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
1092  );
1093 
1094  tm.add_task(std::move(task_cb), std::move(fail_cb));
1095  }
1096 
1097  Mutex::Lock l{mutex};
1098  while (start_count > done_count) cond.wait(mutex);
1099  if (error) throw ParallelError();
1100  for (DiffType index = 0; index < start_count; ++dest, ++index) {
1101  *dest = std::move(results[index]);
1102  }
1103  return {first, dest};
1104 }
1105 
1106 /**
1107  * \#include <c++-gtk-utils/parallel.h>
1108  * @sa Cgu::IntIter
1109  *
1110  * This function maps over two containers, one in the range ['first1',
1111  * 'last1') subject to a maximum, and the other beginning at 'first2',
1112  * applying a binary callable object to each element of the containers
1113  * in those ranges (subject to the maximum) and storing the result in
1114  * the destination range, by executing each such application as a task
1115  * of a Thread::TaskManager object. Tasks are added to the
1116  * Thread::TaskManager object in the order in which the respective
1117  * elements appear in the source containers, and the final result
1118  * appears in the destination container in the same order as the
1119  * source ranges from which it is generated (including if a
1120  * back_inserter iterator is used), but no other ordering arises, and
1121  * the tasks will execute in parallel to the extent that the
1122  * Thread::TaskManager object has sufficient threads available to do
1123  * so.
1124  *
1125  * A separate overload of this function takes a unary callable object.
1126  *
1127  * This function does the same as the version of
1128  * Thread::parallel_transform() taking a binary callable object,
1129  * except that it returns a std::tuple object containing iterators to
1130  * the element past the last elements of the source ranges
1131  * transformed, and a destination iterator to the element past the
1132  * last element stored in the destination range, and it has a 'max'
1133  * parameter to limit the maximum number of elements which will be so
1134  * transformed on any one call to this function. Whether this
1135  * limitation has had effect on any one call can be tested by checking
1136  * whether the first value of the tuple returned is equal to the
1137  * 'last' parameter. If it is not, a further call to this function
1138  * can be made.
1139  *
1140  * The main purpose of this additional function is to enable the
1141  * parallel transform of the elements of a container to be dealt with
1142  * in chunks, possibly to enable other tasks to be interleaved at
1143  * reasonable intervals. For source or destination containers which
1144  * do not support random access iterators, the 'last' parameter can be
1145  * set to, say, the end of the container and the chunk size set with
1146  * the 'max' paramater, with the values of the returned tuple being
1147  * used as the 'first1', 'first2' and 'dest' parameters for subsequent
1148  * calls to this function. This avoids having to increment the source
1149  * and destination iterators for each "chunk" by stepping through the
1150  * respective containers by hand. In this usage, it therefore
1151  * represents a minor efficiency improvement.
1152  *
1153  * @param tm The Thread::TaskManager object on which the tasks will
1154  * run.
1155  * @param first1 The beginning of the range which is to be passed as
1156  * the first argument of 'func'.
1157  * @param last1 One past the last element of the range which is to be
1158  * passed as the first argument of 'func', subject to any maximum
1159  * specified as the 'max' parameter.
1160  * @param first2 The beginning of the range which is to be passed as
1161  * the second argument of 'func'.
1162  * @param dest The beginning of the range to which the result of
1163  * applying 'func' to the elements in the source ranges is to be
1164  * stored. As in the case of std::transform, this can overlap with or
1165  * be the same as one of the source ranges. It may also be an insert
1166  * iterator.
1167  * @param max The maximum number of elements of the source containers
1168  * which will be transformed on this call. It is not an error if it
1169  * is greater than the distance between 'first1' and 'last1'. If it
1170  * is equal to or greater than that distance, it follows that the
1171  * first value of the tuple returned by this function will be equal to
1172  * 'last1'. The same results if 'max' is a negative number (in that
1173  * case no maximum will take effect and all elements in the range
1174  * ['first1', 'last1') will be transformed), so passing -1 might be
1175  * useful as a means of obtaining a second source iterator (the second
1176  * value of the tuple) or destination iterator (the third value) for
1177  * other purposes, particularly where they are not random access
1178  * iterators.
1179  * @param func A binary callable object to be applied (subject to the
1180  * maximum) to each element in the source ranges, such as formed by a
1181  * lambda expression or the result of std::bind. It should take two
1182  * unbound arguments of the value types of the containers to which
1183  * 'first1' and 'first2' relate or const or non-const references to
1184  * those types. If an exception propagates from 'func', the exception
1185  * will be consumed while the transform loop is running, and an
1186  * attempt will still be made to apply 'func' to all remaining
1187  * elements of the source ranges subject to the maximum, and only
1188  * after that attempt has completed will the exception
1189  * Cgu::Thread::ParallelError be thrown.
1190  * @return A std::tuple object. Its first value is an iterator
1191  * representing the element past the last element of the first source
1192  * range transformed, which may be passed as the 'first1' argument of
1193  * a subsequent call to this function; its second value is an iterator
1194  * representing the element past the last element of the second source
1195  * range transformed, which may be passed as the 'first2' argument of
1196  * the subsequent call; and its third value is an iterator
1197  * representing the element past the last element stored in the
1198  * destination range, which may be passed as the 'dest' argument of
1199  * the subsequent call.
1200  * @exception std::bad_alloc This exception will be thrown if memory
1201  * is exhausted and the system throws in that case. (On systems with
1202  * over-commit/lazy-commit combined with virtual memory (swap), it is
1203  * rarely useful to check for memory exhaustion). If this exception
1204  * is thrown, some tasks may nonetheless have already started by
1205  * virtue of the call to this function, but subsequent ones will not.
1206  * @exception Cgu::Thread::TaskError This exception will be thrown if
1207  * stop_all() has previously been called on the Thread::TaskManager
1208  * object, or if another thread calls stop_all() after this method is
1209  * called but before it has returned. It will also be thrown if the
1210  * Thread::TaskManager object's is_error() method would return true
1211  * because its internal thread pool loop implementation has thrown
1212  * std::bad_alloc, or a thread has failed to start correctly because
1213  * pthread has run out of resources. (On systems with
1214  * over-commit/lazy-commit combined with virtual memory (swap), it is
1215  * rarely useful to check for memory exhaustion, and if a reasonable
1216  * maximum thread count has been chosen for the Thread::TaskManager
1217  * object pthread should not run out of other resources, but there may
1218  * be some specialized cases where the return value of is_error() is
1219  * useful.) If this exception is thrown, some tasks may nonetheless
1220  * have already started by virtue of the call to this function.
1221  * @exception Cgu::Thread::ParallelError This exception will be thrown
1222  * if an exception propagates from the 'func' callable object when it
1223  * executes on being applied to one or more elements of the source
1224  * ranges. Such an exception will not stop an attempt being made to
1225  * apply 'func' (successfully or unsuccessfully) to all elements in
1226  * the source ranges subject to the maximum.
1227  * Cgu::Thread::ParallelError will be thrown after such attempted
1228  * application has finished.
1229  * @exception Cgu::Thread::MutexError This exception will be thrown if
1230  * initialization of a mutex used by this function fails. (It is
1231  * often not worth checking for this, as it means either memory is
1232  * exhausted or pthread has run out of other resources to create new
1233  * mutexes.) If this exception is thrown, no tasks will start.
1234  * @exception Cgu::Thread::CondError This exception will be thrown if
1235  * initialization of a condition variable used by this function fails.
1236  * (It is often not worth checking for this, as it means either memory
1237  * is exhausted or pthread has run out of other resources to create
1238  * new condition variables.) If this exception is thrown, no tasks
1239  * will start.
1240  * @note 1. An exception might also be thrown if the copy or move
1241  * constructor of the 'func' callable objects throws. If such an
1242  * exception is thrown, no tasks will start.
1243  * @note 2. Prior to version 2.0.27, this function could not take a
1244  * source iterator to const. This was fixed in version 2.0.27.
1245  *
1246  * Since 2.0.20
1247  */
1248 template <class SourceIterator1, class SourceIterator2, class DestIterator, class Func>
1249 std::tuple<SourceIterator1, SourceIterator2, DestIterator>
1251  SourceIterator1 first1,
1252  SourceIterator1 last1,
1253  SourceIterator2 first2,
1254  DestIterator dest,
1255  int max,
1256  Func&& func) {
1257 
1258  if (first1 == last1 || !max) return std::make_tuple(first1, first2, dest);
1259 
1260  typedef typename std::iterator_traits<SourceIterator1>::reference Arg1RefType;
1261  typedef typename std::iterator_traits<SourceIterator1>::difference_type DiffType;
1262  typedef typename std::iterator_traits<SourceIterator2>::reference Arg2RefType;
1263  typedef typename std::remove_const<typename std::remove_reference<Func>::type>::type FType;
1264  typedef decltype(func(*first1, *first2)) DestType;
1265 
1266  Mutex mutex;
1267  Cond cond;
1268  DiffType start_count = 0;
1269  DiffType done_count = 0;
1270  bool error = false;
1271 
1272  // a specialization of std::numeric_limits::max() for all arithmetic
1273  // types is required by §3.9.1/8 of the standard. The iterator
1274  // difference type must be a signed integer type (§24.2.1/1). All
1275  // signed integer types are arithmetic types (§3.9.1/2, §3.9.1/7 and
1276  // §3.9.1/8).
1277  const DiffType local_max =
1278  (max >= 0) ? max : std::numeric_limits<DiffType>::max();
1279 
1280  // intermediate results have to be held in an array so destination
1281  // ordering can be enforced when using insert interators. This
1282  // causes some inefficiency for non-random access iterators
1283  std::unique_ptr<DestType[]> results(new DestType[std::min(local_max,
1284  std::distance(first1, last1))]);
1285 
1286  // construct SafeFunctorArg objects so that they can be shared
1287  // between different tasks
1289  Cgu::Callback::make_ref(&ParallelHelper2::transform2_func<FType, Arg1RefType, Arg2RefType, DestType>,
1290  std::forward<Func>(func))
1291  };
1293  Cgu::Callback::make(&ParallelHelper2::fail_func<DiffType>,
1294  &mutex,
1295  &cond,
1296  &error,
1297  &done_count)
1298  };
1299 
1300  for (; first1 != last1 && start_count < local_max; ++first1, ++first2, ++start_count) {
1301 #ifdef CGU_USE_AUTO_PTR
1302  typedef std::auto_ptr<const Callback::Callback> CbPtr;
1303 #else
1304  typedef std::unique_ptr<const Callback::Callback> CbPtr;
1305 #endif
1306  CbPtr task_cb(
1307  Cgu::Callback::lambda<>(std::bind(&ParallelHelper2::transform2_cb_func<Arg1RefType, Arg2RefType, DestType, DiffType, SourceIterator1, SourceIterator2>,
1308  s_task,
1309  first1,
1310  first2,
1311  &mutex,
1312  &cond,
1313  &done_count,
1314  results.get(),
1315  start_count))
1316  );
1317  CbPtr fail_cb(
1318  Cgu::Callback::make_ref(&ParallelHelper2::fail_cb_func, s_fail)
1319  );
1320 
1321  tm.add_task(std::move(task_cb), std::move(fail_cb));
1322  }
1323 
1324  Mutex::Lock l{mutex};
1325  while (start_count > done_count) cond.wait(mutex);
1326  if (error) throw ParallelError();
1327  for (DiffType index = 0; index < start_count; ++dest, ++index) {
1328  *dest = std::move(results[index]);
1329  }
1330  return std::make_tuple(first1, first2, dest);
1331 }
1332 
1333 } // namespace Thread
1334 
1335 /**
1336  * @defgroup IntIterHelpers IntIterHelpers
1337  *
1338  * @class IntIter parallel.h c++-gtk-utils/parallel.h
1339  * @brief An iterator class providing a lazy integer range over a virtual container.
1340  * @sa IntIterHelpers
1341  *
1342  * This class acts as an iterator which iterates over a range of
1343  * integers lazily, as if over a virtual container of incrementing
1344  * ints constructed using std::iota. It is principally intended for
1345  * use in constructing parallel for loops using
1346  * Cgu::Thread::parallel_for_each() or
1347  * Cgu::Thread::parallel_transform(), which is why it is in the
1348  * c++-gtk-utils/parallel.h header, but it can be used whenever a lazy
1349  * range of integers is required.
1350  *
1351  * It behaves as a random access iterator to const int, and has the
1352  * normal increment, decrement and other random access functions.
1353  * When used with Cgu::Thread::parallel_for_each() and
1354  * Cgu::Thread::parallel_transform(), because it acts as an iterator
1355  * to const int, the callable object passed to those functions must
1356  * take an int or const int& argument. Any IntIter object compares
1357  * equal to any other IntIter object which at the time in question
1358  * references the same int value, so it can be used as the beginning
1359  * iterator or end iterator of a range for a standard algorithm; and
1360  * one IntIter object is less than another IntIter object if it
1361  * references an int value less than the other, and so on as regards
1362  * the other comparison operators.
1363  *
1364  * Here is an example of its use with
1365  * Cgu::Thread::parallel_transform(), as a parallelized equivalent of
1366  * a for loop which increments a count integer on each iteration
1367  * through the loop. In this example, the count integer, as
1368  * incremented on each iteration, is squared and the result stored in
1369  * a std::vector object (in practice you would not want to use this
1370  * construction for such a trivial case as it would be slower than the
1371  * single threaded version - it is for use where some significant work
1372  * is done in the for loop, here represented by the lambda
1373  * expression):
1374  *
1375  * @code
1376  * using namespace Cgu;
1377  * std::vector<int> v;
1378  * Thread::TaskManager tm{4};
1379  * Thread::parallel_transform(tm,
1380  * IntIter{0}, // beginning of range
1381  * IntIter{10}, // one past end of range
1382  * std::back_inserter(v),
1383  * [](int i) {return i * i;});
1384  * for (auto elt: v) std::cout << elt << ' ';
1385  * std::cout << std::endl;
1386  * @endcode
1387  *
1388  * Although unlikely to be useful very often, the iterator can count
1389  * backwards using std::reverse_iterator:
1390  *
1391  * @code
1392  * using namespace Cgu;
1393  * typedef std::reverse_iterator<IntIter> RIntIter;
1394  * std::vector<int> v;
1395  * Thread::TaskManager tm{4};
1396  * Thread::parallel_transform(tm,
1397  * RIntIter{IntIter{10}}, // one past beginning of range
1398  * RIntIter{IntIter{0}}, // end of range
1399  * std::back_inserter(v),
1400  * [](int i) {return i * i;});
1401  * for (auto elt: v) std::cout << elt << ' ';
1402  * std::cout << std::endl;
1403  * @endcode
1404  *
1405  * @ingroup IntIterHelpers
1406  *
1407  * Since 2.0.27.
1408  */
1409 class IntIter {
1410 public:
1411  typedef int value_type;
1412  typedef int reference; // read only
1413  typedef void pointer; // read only
1414  typedef int difference_type;
1415  typedef std::random_access_iterator_tag iterator_category;
1416 private:
1417  int val;
1418 public:
1419  /**
1420  * This constructor acts as both a default constructor and an
1421  * initializing constructor. It does not throw.
1422  *
1423  * Since 2.0.27.
1424  */
1425  explicit IntIter(value_type val_ = 0): val(val_) {}
1426 
1427  /**
1428  * The copy constructor does not throw.
1429  *
1430  * Since 2.0.27.
1431  */
1432  IntIter(const IntIter&) = default;
1433 
1434  /**
1435  * The copy assignment operator does not throw.
1436  *
1437  * Since 2.0.27.
1438  */
1439  IntIter& operator=(const IntIter&) = default;
1440 
1441  /**
1442  * The pre-increment operator does not throw. No locking is carried
1443  * out, so if the iterator is accessed in more than one thread and
1444  * one calls a non-const method, the user must provide
1445  * synchronization (but Cgu::Thread::parallel_for_each(),
1446  * Cgu::Thread::parallel_for_each_partial(),
1447  * Cgu::Thread::parallel_transform() and
1448  * Cgu::Thread::parallel_transform_partial() only access source and
1449  * destination iterators in the thread which calls the functions, so
1450  * use of an IntIter object only by one of those functions does not
1451  * require synchronization).
1452  * @return A reference to the iterator after being incremented.
1453  *
1454  * Since 2.0.27.
1455  */
1456  IntIter& operator++() {++val; return *this;}
1457 
1458  /**
1459  * The post-increment operator does not throw. No locking is
1460  * carried out, so if the iterator is accessed in more than one
1461  * thread and one calls a non-const method, the user must provide
1462  * synchronization (but Cgu::Thread::parallel_for_each(),
1463  * Cgu::Thread::parallel_for_each_partial(),
1464  * Cgu::Thread::parallel_transform() and
1465  * Cgu::Thread::parallel_transform_partial() only access source and
1466  * destination iterators in the thread which calls the functions, so
1467  * use of an IntIter object only by one of those functions does not
1468  * require synchronization).
1469  * @return A copy of the iterator prior to being incremented.
1470  *
1471  * Since 2.0.27.
1472  */
1473  IntIter operator++(int) {IntIter tmp = *this; ++val; return tmp;}
1474 
1475  /**
1476  * The pre-decrement operator does not throw. No locking is carried
1477  * out, so if the iterator is accessed in more than one thread and
1478  * one calls a non-const method, the user must provide
1479  * synchronization (but Cgu::Thread::parallel_for_each(),
1480  * Cgu::Thread::parallel_for_each_partial(),
1481  * Cgu::Thread::parallel_transform() and
1482  * Cgu::Thread::parallel_transform_partial() only access source and
1483  * destination iterators in the thread which calls the functions, so
1484  * use of an IntIter object only by one of those functions does not
1485  * require synchronization).
1486  * @return A reference to the iterator after being decremented.
1487  *
1488  * Since 2.0.27.
1489  */
1490  IntIter& operator--() {--val; return *this;}
1491 
1492  /**
1493  * The post-decrement operator does not throw. No locking is
1494  * carried out, so if the iterator is accessed in more than one
1495  * thread, the user must provide synchronization (but
1496  * Cgu::Thread::parallel_for_each(),
1497  * Cgu::Thread::parallel_for_each_partial(),
1498  * Cgu::Thread::parallel_transform() and
1499  * Cgu::Thread::parallel_transform_partial() only access source and
1500  * destination iterators in the thread which calls the functions, so
1501  * use of an IntIter object only by one of those functions does not
1502  * require synchronization).
1503  * @return A copy of the iterator prior to being decremented.
1504  *
1505  * Since 2.0.27.
1506  */
1507  IntIter operator--(int) {IntIter tmp = *this; --val; return tmp;}
1508 
1509  /**
1510  * This operator adds the value of the argument to the integer value
1511  * currently represented by the iterator. It does not throw. No
1512  * locking is carried out, so if the iterator is accessed in more
1513  * than one thread and one calls a non-const method, the user must
1514  * provide synchronization (but Cgu::Thread::parallel_for_each(),
1515  * Cgu::Thread::parallel_for_each_partial(),
1516  * Cgu::Thread::parallel_transform() and
1517  * Cgu::Thread::parallel_transform_partial() only access source and
1518  * destination iterators in the thread which calls the functions, so
1519  * use of an IntIter object only by one of those functions does not
1520  * require synchronization).
1521  * @return A reference to the iterator after addition.
1522  *
1523  * Since 2.0.27.
1524  */
1525  IntIter& operator+=(difference_type n) {val += n; return *this;}
1526 
1527  /**
1528  * This operator subtracts the value of the argument from the
1529  * integer value currently represented by the iterator. It does not
1530  * throw. No locking is carried out, so if the iterator is accessed
1531  * in more than one thread, the user must provide synchronization
1532  * (but Cgu::Thread::parallel_for_each(),
1533  * Cgu::Thread::parallel_for_each_partial(),
1534  * Cgu::Thread::parallel_transform() and
1535  * Cgu::Thread::parallel_transform_partial() only access source and
1536  * destination iterators in the thread which calls the functions, so
1537  * use of an IntIter object only by one of those functions does not
1538  * require synchronization).
1539  * @return A reference to the iterator after subtraction.
1540  *
1541  * Since 2.0.27.
1542  */
1543  IntIter& operator-=(difference_type n) {val -= n; return *this;}
1544 
1545  /**
1546  * The offset dereferencing operator does not throw. No locking is
1547  * carried out, so if the iterator is accessed in more than one
1548  * thread, the user must provide synchronization (but
1549  * Cgu::Thread::parallel_for_each(),
1550  * Cgu::Thread::parallel_for_each_partial(),
1551  * Cgu::Thread::parallel_transform() and
1552  * Cgu::Thread::parallel_transform_partial() only access source and
1553  * destination iterators in the thread which calls the functions, so
1554  * use of an IntIter object only by one of those functions does not
1555  * require synchronization).
1556  * @return The integer value at the given offset.
1557  *
1558  * Since 2.0.27.
1559  */
1560  reference operator[](difference_type n) const {return val + n;}
1561 
1562  /**
1563  * The dereferencing operator does not throw. No locking is carried
1564  * out, so if the iterator is accessed in more than one thread, the
1565  * user must provide synchronization (but
1566  * Cgu::Thread::parallel_for_each(),
1567  * Cgu::Thread::parallel_for_each_partial(),
1568  * Cgu::Thread::parallel_transform() and
1569  * Cgu::Thread::parallel_transform_partial() only access source and
1570  * destination iterators in the thread which calls the functions, so
1571  * use of an IntIter object only by one of those functions does not
1572  * require synchronization).
1573  * @return The integer value currently represented by the iterator.
1574  *
1575  * Since 2.0.27.
1576  */
1577  reference operator*() const {return val;}
1578 
1579 /* Only has effect if --with-glib-memory-slices-compat or
1580  * --with-glib-memory-slices-no-compat option picked */
1582 };
1583 
1584 /**
1585  * @ingroup IntIterHelpers
1586  *
1587  * This comparison operator does not throw. No locking is carried
1588  * out, so if one of the iterators is accessed in more than one
1589  * thread, the user must provide synchronization (but
1590  * Cgu::Thread::parallel_for_each(),
1591  * Cgu::Thread::parallel_for_each_partial(),
1592  * Cgu::Thread::parallel_transform() and
1593  * Cgu::Thread::parallel_transform_partial() only access source and
1594  * destination iterators in the thread which calls those functions, so
1595  * use of an IntIter object only by one of those functions does not
1596  * require synchronization).
1597  *
1598  * Since 2.0.27.
1599  */
1600 inline bool operator==(IntIter iter1, IntIter iter2) {
1601  return *iter1 == *iter2;
1602 }
1603 
1604 /**
1605  * @ingroup IntIterHelpers
1606  *
1607  * This comparison operator does not throw. No locking is carried
1608  * out, so if one of the iterators is accessed in more than one
1609  * thread, the user must provide synchronization (but
1610  * Cgu::Thread::parallel_for_each(),
1611  * Cgu::Thread::parallel_for_each_partial(),
1612  * Cgu::Thread::parallel_transform() and
1613  * Cgu::Thread::parallel_transform_partial() only access source and
1614  * destination iterators in the thread which calls those functions, so
1615  * use of an IntIter object only by one of those functions does not
1616  * require synchronization).
1617  *
1618  * Since 2.0.27.
1619  */
1620 inline bool operator!=(IntIter iter1, IntIter iter2) {
1621  return !(iter1 == iter2);
1622 }
1623 
1624 /**
1625  * @ingroup IntIterHelpers
1626  *
1627  * This comparison operator does not throw. No locking is carried
1628  * out, so if one of the iterators is accessed in more than one
1629  * thread, the user must provide synchronization (but
1630  * Cgu::Thread::parallel_for_each(),
1631  * Cgu::Thread::parallel_for_each_partial(),
1632  * Cgu::Thread::parallel_transform() and
1633  * Cgu::Thread::parallel_transform_partial() only access source and
1634  * destination iterators in the thread which calls those functions, so
1635  * use of an IntIter object only by one of those functions does not
1636  * require synchronization).
1637  *
1638  * Since 2.0.27.
1639  */
1640 inline bool operator<(IntIter iter1, IntIter iter2) {
1641  return *iter1 < *iter2;
1642 }
1643 
1644 /**
1645  * @ingroup IntIterHelpers
1646  *
1647  * This comparison operator does not throw. No locking is carried
1648  * out, so if one of the iterators is accessed in more than one
1649  * thread, the user must provide synchronization (but
1650  * Cgu::Thread::parallel_for_each(),
1651  * Cgu::Thread::parallel_for_each_partial(),
1652  * Cgu::Thread::parallel_transform() and
1653  * Cgu::Thread::parallel_transform_partial() only access source and
1654  * destination iterators in the thread which calls those functions, so
1655  * use of an IntIter object only by one of those functions does not
1656  * require synchronization).
1657  *
1658  * Since 2.0.27.
1659  */
1660 inline bool operator>(IntIter iter1, IntIter iter2) {
1661  return iter2 < iter1;
1662 }
1663 
1664 /**
1665  * @ingroup IntIterHelpers
1666  *
1667  * This comparison operator does not throw. No locking is carried
1668  * out, so if one of the iterators is accessed in more than one
1669  * thread, the user must provide synchronization (but
1670  * Cgu::Thread::parallel_for_each(),
1671  * Cgu::Thread::parallel_for_each_partial(),
1672  * Cgu::Thread::parallel_transform() and
1673  * Cgu::Thread::parallel_transform_partial() only access source and
1674  * destination iterators in the thread which calls the functions, so
1675  * use of an IntIter object only by one of those functions does not
1676  * require synchronization).
1677  *
1678  * Since 2.0.27.
1679  */
1680 inline bool operator<=(IntIter iter1, IntIter iter2) {
1681  return !(iter1 > iter2);
1682 }
1683 
1684 /**
1685  * @ingroup IntIterHelpers
1686  *
1687  * This comparison operator does not throw. No locking is carried
1688  * out, so if one of the iterators is accessed in more than one
1689  * thread, the user must provide synchronization (but
1690  * Cgu::Thread::parallel_for_each(),
1691  * Cgu::Thread::parallel_for_each_partial(),
1692  * Cgu::Thread::parallel_transform() and
1693  * Cgu::Thread::parallel_transform_partial() only access source and
1694  * destination iterators in the thread which calls those functions, so
1695  * use of an IntIter object only by one of those functions does not
1696  * require synchronization).
1697  *
1698  * Since 2.0.27.
1699  */
1700 inline bool operator>=(IntIter iter1, IntIter iter2) {
1701  return !(iter1 < iter2);
1702 }
1703 
1704 /**
1705  * @ingroup IntIterHelpers
1706  *
1707  * This comparison operator does not throw. No locking is carried
1708  * out, so if one of the iterators is accessed in more than one
1709  * thread, the user must provide synchronization (but
1710  * Cgu::Thread::parallel_for_each(),
1711  * Cgu::Thread::parallel_for_each_partial(),
1712  * Cgu::Thread::parallel_transform() and
1713  * Cgu::Thread::parallel_transform_partial() only access source and
1714  * destination iterators in the thread which calls those functions, so
1715  * use of an IntIter object only by one of those functions does not
1716  * require synchronization).
1717  *
1718  * Since 2.0.27.
1719  */
1721  return *iter1 - *iter2;
1722 }
1723 
1724 /**
1725  * @ingroup IntIterHelpers
1726  *
1727  * This comparison operator does not throw. No locking is carried
1728  * out, so if one of the iterators is accessed in more than one
1729  * thread, the user must provide synchronization (but
1730  * Cgu::Thread::parallel_for_each(),
1731  * Cgu::Thread::parallel_for_each_partial(),
1732  * Cgu::Thread::parallel_transform() and
1733  * Cgu::Thread::parallel_transform_partial() only access source and
1734  * destination iterators in the thread which calls those functions, so
1735  * use of an IntIter object only by one of those functions does not
1736  * require synchronization).
1737  *
1738  * Since 2.0.27.
1739  */
1741  return IntIter{*iter + n};
1742 }
1743 
1744 /**
1745  * @ingroup IntIterHelpers
1746  *
1747  * This comparison operator does not throw. No locking is carried
1748  * out, so if one of the iterators is accessed in more than one
1749  * thread, the user must provide synchronization (but
1750  * Cgu::Thread::parallel_for_each(),
1751  * Cgu::Thread::parallel_for_each_partial(),
1752  * Cgu::Thread::parallel_transform() and
1753  * Cgu::Thread::parallel_transform_partial() only access source and
1754  * destination iterators in the thread which calls those functions, so
1755  * use of an IntIter object only by one of those functions does not
1756  * require synchronization).
1757  *
1758  * Since 2.0.27.
1759  */
1761  return IntIter{*iter - n};
1762 }
1763 
1764 /**
1765  * @ingroup IntIterHelpers
1766  *
1767  * This comparison operator does not throw. No locking is carried
1768  * out, so if one of the iterators is accessed in more than one
1769  * thread, the user must provide synchronization (but
1770  * Cgu::Thread::parallel_for_each(),
1771  * Cgu::Thread::parallel_for_each_partial(),
1772  * Cgu::Thread::parallel_transform() and
1773  * Cgu::Thread::parallel_transform_partial() only access source and
1774  * destination iterators in the thread which calls those functions, so
1775  * use of an IntIter object only by one of those functions does not
1776  * require synchronization).
1777  *
1778  * Since 2.0.27.
1779  */
1781  return iter + n;
1782 }
1783 
1784 } // namespace Cgu
1785 
1786 #endif // CGU_PARALLEL_H