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