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