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