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