]> git.sesse.net Git - casparcg/blob - tbb/include/tbb/parallel_invoke.h
Removed GLEE from dependencies.
[casparcg] / tbb / include / tbb / parallel_invoke.h
1 /*
2     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB_parallel_invoke_H
30 #define __TBB_parallel_invoke_H
31
32 #include "task.h"
33
34 namespace tbb {
35
36 #if !__TBB_TASK_GROUP_CONTEXT
37     /** Dummy to avoid cluttering the bulk of the header with enormous amount of ifdefs. **/
38     struct task_group_context {};
39 #endif /* __TBB_TASK_GROUP_CONTEXT */
40
41 //! @cond INTERNAL
42 namespace internal {
43     // Simple task object, executing user method
44     template<typename function>
45     class function_invoker : public task{
46     public:
47         function_invoker(const function& _function) : my_function(_function) {}
48     private:
49         const function &my_function;
50         /*override*/
51         task* execute()
52         {
53             my_function();
54             return NULL;
55         }
56     };
57
58     // The class spawns two or three child tasks
59     template <size_t N, typename function1, typename function2, typename function3>
60     class spawner : public task {
61     private:
62         const function1& my_func1;
63         const function2& my_func2;
64         const function3& my_func3;
65         bool is_recycled;
66
67         task* execute (){
68             if(is_recycled){
69                 return NULL;
70             }else{
71                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
72                 set_ref_count(N);
73                 recycle_as_safe_continuation();
74                 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
75                 __TBB_ASSERT(invoker2, "Child task allocation failed");
76                 spawn(*invoker2);
77                 size_t n = N; // To prevent compiler warnings
78                 if (n>2) {
79                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
80                     __TBB_ASSERT(invoker3, "Child task allocation failed");
81                     spawn(*invoker3);
82                 }
83                 my_func1();
84                 is_recycled = true;
85                 return NULL;
86             }
87         } // execute
88
89     public:
90         spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
91     };
92
93     // Creates and spawns child tasks
94     class parallel_invoke_helper : public empty_task {
95     public:
96         // Dummy functor class
97         class parallel_invoke_noop {
98         public:
99             void operator() () const {}
100         };
101         // Creates a helper object with user-defined number of children expected
102         parallel_invoke_helper(int number_of_children)
103         {
104             set_ref_count(number_of_children + 1);
105         }
106         // Adds child task and spawns it
107         template <typename function>
108         void add_child (const function &_func)
109         {
110             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
111             __TBB_ASSERT(invoker, "Child task allocation failed");
112             spawn(*invoker);
113         }
114
115         // Adds a task with multiple child tasks and spawns it
116         // two arguments
117         template <typename function1, typename function2>
118         void add_children (const function1& _func1, const function2& _func2)
119         {
120             // The third argument is dummy, it is ignored actually.
121             parallel_invoke_noop noop;
122             internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
123             spawn(sub_root);
124         }
125         // three arguments
126         template <typename function1, typename function2, typename function3>
127         void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
128         {
129             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
130             spawn(sub_root);
131         }
132
133         // Waits for all child tasks
134         template <typename F0>
135         void run_and_finish(const F0& f0)
136         {
137             internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
138             __TBB_ASSERT(invoker, "Child task allocation failed");
139             spawn_and_wait_for_all(*invoker);
140         }
141     };
142     // The class destroys root if exception occured as well as in normal case
143     class parallel_invoke_cleaner: internal::no_copy { 
144     public:
145 #if __TBB_TASK_GROUP_CONTEXT
146         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context)
147             : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
148 #else
149         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&)
150             : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children))
151 #endif /* !__TBB_TASK_GROUP_CONTEXT */
152         {}
153
154         ~parallel_invoke_cleaner(){
155             root.destroy(root);
156         }
157         internal::parallel_invoke_helper& root;
158     };
159 } // namespace internal
160 //! @endcond
161
162 /** \name parallel_invoke
163     **/
164 //@{
165 //! Executes a list of tasks in parallel and waits for all tasks to complete.
166 /** @ingroup algorithms */
167
168 // parallel_invoke with user-defined context
169 // two arguments
170 template<typename F0, typename F1 >
171 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
172     internal::parallel_invoke_cleaner cleaner(2, context);
173     internal::parallel_invoke_helper& root = cleaner.root;
174
175     root.add_child(f1);
176
177     root.run_and_finish(f0);
178 }
179
180 // three arguments
181 template<typename F0, typename F1, typename F2 >
182 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
183     internal::parallel_invoke_cleaner cleaner(3, context);
184     internal::parallel_invoke_helper& root = cleaner.root;
185
186     root.add_child(f2);
187     root.add_child(f1);
188
189     root.run_and_finish(f0);
190 }
191
192 // four arguments
193 template<typename F0, typename F1, typename F2, typename F3>
194 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
195                      tbb::task_group_context& context)
196 {
197     internal::parallel_invoke_cleaner cleaner(4, context);
198     internal::parallel_invoke_helper& root = cleaner.root;
199
200     root.add_child(f3);
201     root.add_child(f2);
202     root.add_child(f1);
203
204     root.run_and_finish(f0);
205 }
206
207 // five arguments
208 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
209 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
210                      tbb::task_group_context& context)
211 {
212     internal::parallel_invoke_cleaner cleaner(3, context);
213     internal::parallel_invoke_helper& root = cleaner.root;
214
215     root.add_children(f4, f3);
216     root.add_children(f2, f1);
217
218     root.run_and_finish(f0);
219 }
220
221 // six arguments
222 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
223 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
224                      tbb::task_group_context& context)
225 {
226     internal::parallel_invoke_cleaner cleaner(3, context);
227     internal::parallel_invoke_helper& root = cleaner.root;
228
229     root.add_children(f5, f4, f3);
230     root.add_children(f2, f1);
231
232     root.run_and_finish(f0);
233 }
234
235 // seven arguments
236 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
237 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
238                      const F5& f5, const F6& f6,
239                      tbb::task_group_context& context)
240 {
241     internal::parallel_invoke_cleaner cleaner(3, context);
242     internal::parallel_invoke_helper& root = cleaner.root;
243
244     root.add_children(f6, f5, f4);
245     root.add_children(f3, f2, f1);
246
247     root.run_and_finish(f0);
248 }
249
250 // eight arguments
251 template<typename F0, typename F1, typename F2, typename F3, typename F4,
252          typename F5, typename F6, typename F7>
253 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
254                      const F5& f5, const F6& f6, const F7& f7,
255                      tbb::task_group_context& context)
256 {
257     internal::parallel_invoke_cleaner cleaner(4, context);
258     internal::parallel_invoke_helper& root = cleaner.root;
259
260     root.add_children(f7, f6, f5);
261     root.add_children(f4, f3);
262     root.add_children(f2, f1);
263
264     root.run_and_finish(f0);
265 }
266
267 // nine arguments
268 template<typename F0, typename F1, typename F2, typename F3, typename F4,
269          typename F5, typename F6, typename F7, typename F8>
270 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
271                      const F5& f5, const F6& f6, const F7& f7, const F8& f8,
272                      tbb::task_group_context& context)
273 {
274     internal::parallel_invoke_cleaner cleaner(4, context);
275     internal::parallel_invoke_helper& root = cleaner.root;
276
277     root.add_children(f8, f7, f6);
278     root.add_children(f5, f4, f3);
279     root.add_children(f2, f1);
280
281     root.run_and_finish(f0);
282 }
283
284 // ten arguments
285 template<typename F0, typename F1, typename F2, typename F3, typename F4,
286          typename F5, typename F6, typename F7, typename F8, typename F9>
287 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
288                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
289                      tbb::task_group_context& context)
290 {
291     internal::parallel_invoke_cleaner cleaner(4, context);
292     internal::parallel_invoke_helper& root = cleaner.root;
293
294     root.add_children(f9, f8, f7);
295     root.add_children(f6, f5, f4);
296     root.add_children(f3, f2, f1);
297
298     root.run_and_finish(f0);
299 }
300
301 // two arguments
302 template<typename F0, typename F1>
303 void parallel_invoke(const F0& f0, const F1& f1) {
304     task_group_context context;
305     parallel_invoke<F0, F1>(f0, f1, context);
306 }
307 // three arguments
308 template<typename F0, typename F1, typename F2>
309 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
310     task_group_context context;
311     parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
312 }
313 // four arguments
314 template<typename F0, typename F1, typename F2, typename F3 >
315 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
316     task_group_context context;
317     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
318 }
319 // five arguments
320 template<typename F0, typename F1, typename F2, typename F3, typename F4>
321 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
322     task_group_context context;
323     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
324 }
325 // six arguments
326 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
327 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
328     task_group_context context;
329     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
330 }
331 // seven arguments
332 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
333 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
334                      const F5& f5, const F6& f6)
335 {
336     task_group_context context;
337     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
338 }
339 // eigth arguments
340 template<typename F0, typename F1, typename F2, typename F3, typename F4, 
341          typename F5, typename F6, typename F7>
342 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
343                      const F5& f5, const F6& f6, const F7& f7)
344 {
345     task_group_context context;
346     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
347 }
348 // nine arguments
349 template<typename F0, typename F1, typename F2, typename F3, typename F4,
350          typename F5, typename F6, typename F7, typename F8>
351 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
352                      const F5& f5, const F6& f6, const F7& f7, const F8& f8)
353 {
354     task_group_context context;
355     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
356 }
357 // ten arguments
358 template<typename F0, typename F1, typename F2, typename F3, typename F4,
359          typename F5, typename F6, typename F7, typename F8, typename F9>
360 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
361                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
362 {
363     task_group_context context;
364     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
365 }
366
367 //@}
368
369 } // namespace
370
371 #endif /* __TBB_parallel_invoke_H */