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