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