00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_parallel_do_H
00030 #define __TBB_parallel_do_H
00031
00032 #include "task.h"
00033 #include "aligned_space.h"
00034 #include <iterator>
00035
00036 namespace tbb {
00037
00039 namespace internal {
00040 template<typename Body, typename Item> class parallel_do_feeder_impl;
00041 template<typename Body> class do_group_task;
00042
00044 template<typename T>
00045 struct strip { typedef T type; };
00046 template<typename T>
00047 struct strip<T&> { typedef T type; };
00048 template<typename T>
00049 struct strip<const T&> { typedef T type; };
00050 template<typename T>
00051 struct strip<volatile T&> { typedef T type; };
00052 template<typename T>
00053 struct strip<const volatile T&> { typedef T type; };
00054
00055
00056 template<typename T>
00057 struct strip<const T> { typedef T type; };
00058 template<typename T>
00059 struct strip<volatile T> { typedef T type; };
00060 template<typename T>
00061 struct strip<const volatile T> { typedef T type; };
00062 }
00064
00066
00067 template<typename Item>
00068 class parallel_do_feeder: internal::no_copy
00069 {
00070 parallel_do_feeder() {}
00071 virtual ~parallel_do_feeder () {}
00072 virtual void internal_add( const Item& item ) = 0;
00073 template<typename Body_, typename Item_> friend class internal::parallel_do_feeder_impl;
00074 public:
00076 void add( const Item& item ) {internal_add(item);}
00077 };
00078
00080 namespace internal {
00082
00084 template<class Body, typename Item>
00085 class parallel_do_operator_selector
00086 {
00087 typedef parallel_do_feeder<Item> Feeder;
00088 template<typename A1, typename A2, typename CvItem >
00089 static void internal_call( const Body& obj, A1& arg1, A2&, void (Body::*)(CvItem) const ) {
00090 obj(arg1);
00091 }
00092 template<typename A1, typename A2, typename CvItem >
00093 static void internal_call( const Body& obj, A1& arg1, A2& arg2, void (Body::*)(CvItem, parallel_do_feeder<Item>&) const ) {
00094 obj(arg1, arg2);
00095 }
00096
00097 public:
00098 template<typename A1, typename A2 >
00099 static void call( const Body& obj, A1& arg1, A2& arg2 )
00100 {
00101 internal_call( obj, arg1, arg2, &Body::operator() );
00102 }
00103 };
00104
00106
00108 template<typename Body, typename Item>
00109 class do_iteration_task: public task
00110 {
00111 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
00112
00113 Item my_value;
00114 feeder_type& my_feeder;
00115
00116 do_iteration_task( const Item& value, feeder_type& feeder ) :
00117 my_value(value), my_feeder(feeder)
00118 {}
00119
00120
00121 task* execute()
00122 {
00123 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, my_value, my_feeder);
00124 return NULL;
00125 }
00126
00127 template<typename Body_, typename Item_> friend class parallel_do_feeder_impl;
00128 };
00129
00130 template<typename Iterator, typename Body, typename Item>
00131 class do_iteration_task_iter: public task
00132 {
00133 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
00134
00135 Iterator my_iter;
00136 feeder_type& my_feeder;
00137
00138 do_iteration_task_iter( const Iterator& iter, feeder_type& feeder ) :
00139 my_iter(iter), my_feeder(feeder)
00140 {}
00141
00142
00143 task* execute()
00144 {
00145 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, *my_iter, my_feeder);
00146 return NULL;
00147 }
00148
00149 template<typename Iterator_, typename Body_, typename Item_> friend class do_group_task_forward;
00150 template<typename Body_, typename Item_> friend class do_group_task_input;
00151 template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
00152 };
00153
00155
00157 template<class Body, typename Item>
00158 class parallel_do_feeder_impl : public parallel_do_feeder<Item>
00159 {
00160
00161 void internal_add( const Item& item )
00162 {
00163 typedef do_iteration_task<Body, Item> iteration_type;
00164
00165 iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
00166
00167 t.spawn( t );
00168 }
00169 public:
00170 const Body* my_body;
00171 empty_task* my_barrier;
00172
00173 parallel_do_feeder_impl()
00174 {
00175 my_barrier = new( task::allocate_root() ) empty_task();
00176 __TBB_ASSERT(my_barrier, "root task allocation failed");
00177 }
00178
00179 #if __TBB_TASK_GROUP_CONTEXT
00180 parallel_do_feeder_impl(tbb::task_group_context &context)
00181 {
00182 my_barrier = new( task::allocate_root(context) ) empty_task();
00183 __TBB_ASSERT(my_barrier, "root task allocation failed");
00184 }
00185 #endif
00186
00187 ~parallel_do_feeder_impl()
00188 {
00189 my_barrier->destroy(*my_barrier);
00190 }
00191 };
00192
00193
00195
00198 template<typename Iterator, typename Body, typename Item>
00199 class do_group_task_forward: public task
00200 {
00201 static const size_t max_arg_size = 4;
00202
00203 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
00204
00205 feeder_type& my_feeder;
00206 Iterator my_first;
00207 size_t my_size;
00208
00209 do_group_task_forward( Iterator first, size_t size, feeder_type& feeder )
00210 : my_feeder(feeder), my_first(first), my_size(size)
00211 {}
00212
00213 task* execute()
00214 {
00215 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
00216 __TBB_ASSERT( my_size>0, NULL );
00217 task_list list;
00218 task* t;
00219 size_t k=0;
00220 for(;;) {
00221 t = new( allocate_child() ) iteration_type( my_first, my_feeder );
00222 ++my_first;
00223 if( ++k==my_size ) break;
00224 list.push_back(*t);
00225 }
00226 set_ref_count(int(k+1));
00227 spawn(list);
00228 spawn_and_wait_for_all(*t);
00229 return NULL;
00230 }
00231
00232 template<typename Iterator_, typename Body_, typename _Item> friend class do_task_iter;
00233 };
00234
00235 template<typename Body, typename Item>
00236 class do_group_task_input: public task
00237 {
00238 static const size_t max_arg_size = 4;
00239
00240 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
00241
00242 feeder_type& my_feeder;
00243 size_t my_size;
00244 aligned_space<Item, max_arg_size> my_arg;
00245
00246 do_group_task_input( feeder_type& feeder )
00247 : my_feeder(feeder), my_size(0)
00248 {}
00249
00250 task* execute()
00251 {
00252 typedef do_iteration_task_iter<Item*, Body, Item> iteration_type;
00253 __TBB_ASSERT( my_size>0, NULL );
00254 task_list list;
00255 task* t;
00256 size_t k=0;
00257 for(;;) {
00258 t = new( allocate_child() ) iteration_type( my_arg.begin() + k, my_feeder );
00259 if( ++k==my_size ) break;
00260 list.push_back(*t);
00261 }
00262 set_ref_count(int(k+1));
00263 spawn(list);
00264 spawn_and_wait_for_all(*t);
00265 return NULL;
00266 }
00267
00268 ~do_group_task_input(){
00269 for( size_t k=0; k<my_size; ++k)
00270 (my_arg.begin() + k)->~Item();
00271 }
00272
00273 template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
00274 };
00275
00277
00279 template<typename Iterator, typename Body, typename Item>
00280 class do_task_iter: public task
00281 {
00282 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
00283
00284 public:
00285 do_task_iter( Iterator first, Iterator last , feeder_type& feeder ) :
00286 my_first(first), my_last(last), my_feeder(feeder)
00287 {}
00288
00289 private:
00290 Iterator my_first;
00291 Iterator my_last;
00292 feeder_type& my_feeder;
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 task* execute()
00305 {
00306 typedef typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
00307 return run( (iterator_tag*)NULL );
00308 }
00309
00312 inline task* run( void* ) { return run_for_input_iterator(); }
00313
00314 task* run_for_input_iterator() {
00315 typedef do_group_task_input<Body, Item> block_type;
00316
00317 block_type& t = *new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(my_feeder);
00318 size_t k=0;
00319 while( !(my_first == my_last) ) {
00320 new (t.my_arg.begin() + k) Item(*my_first);
00321 ++my_first;
00322 if( ++k==block_type::max_arg_size ) {
00323 if ( !(my_first == my_last) )
00324 recycle_to_reexecute();
00325 break;
00326 }
00327 }
00328 if( k==0 ) {
00329 destroy(t);
00330 return NULL;
00331 } else {
00332 t.my_size = k;
00333 return &t;
00334 }
00335 }
00336
00337 inline task* run( std::forward_iterator_tag* ) { return run_for_forward_iterator(); }
00338
00339 task* run_for_forward_iterator() {
00340 typedef do_group_task_forward<Iterator, Body, Item> block_type;
00341
00342 Iterator first = my_first;
00343 size_t k=0;
00344 while( !(my_first==my_last) ) {
00345 ++my_first;
00346 if( ++k==block_type::max_arg_size ) {
00347 if ( !(my_first==my_last) )
00348 recycle_to_reexecute();
00349 break;
00350 }
00351 }
00352 return k==0 ? NULL : new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(first, k, my_feeder);
00353 }
00354
00355 inline task* run( std::random_access_iterator_tag* ) { return run_for_random_access_iterator(); }
00356
00357 task* run_for_random_access_iterator() {
00358 typedef do_group_task_forward<Iterator, Body, Item> block_type;
00359 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
00360
00361 size_t k = static_cast<size_t>(my_last-my_first);
00362 if( k > block_type::max_arg_size ) {
00363 Iterator middle = my_first + k/2;
00364
00365 empty_task& c = *new( allocate_continuation() ) empty_task;
00366 do_task_iter& b = *new( c.allocate_child() ) do_task_iter(middle, my_last, my_feeder);
00367 recycle_as_child_of(c);
00368
00369 my_last = middle;
00370 c.set_ref_count(2);
00371 c.spawn(b);
00372 return this;
00373 }else if( k != 0 ) {
00374 task_list list;
00375 task* t;
00376 size_t k1=0;
00377 for(;;) {
00378 t = new( allocate_child() ) iteration_type(my_first, my_feeder);
00379 ++my_first;
00380 if( ++k1==k ) break;
00381 list.push_back(*t);
00382 }
00383 set_ref_count(int(k+1));
00384 spawn(list);
00385 spawn_and_wait_for_all(*t);
00386 }
00387 return NULL;
00388 }
00389 };
00390
00392
00394 template<typename Iterator, typename Body, typename Item>
00395 void run_parallel_do( Iterator first, Iterator last, const Body& body
00396 #if __TBB_TASK_GROUP_CONTEXT
00397 , task_group_context& context
00398 #endif
00399 )
00400 {
00401 typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
00402 #if __TBB_TASK_GROUP_CONTEXT
00403 parallel_do_feeder_impl<Body, Item> feeder(context);
00404 #else
00405 parallel_do_feeder_impl<Body, Item> feeder;
00406 #endif
00407 feeder.my_body = &body;
00408
00409 root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
00410
00411 feeder.my_barrier->set_ref_count(2);
00412 feeder.my_barrier->spawn_and_wait_for_all(t);
00413 }
00414
00416
00418 template<typename Iterator, typename Body, typename Item>
00419 void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const
00420 #if __TBB_TASK_GROUP_CONTEXT
00421 , task_group_context& context
00422 #endif
00423 )
00424 {
00425 run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
00426 #if __TBB_TASK_GROUP_CONTEXT
00427 , context
00428 #endif // __TBB_TASK_GROUP_CONTEXT
00429 );
00430 }
00431
00433
00435 template<typename Iterator, typename Body, typename Item, typename _Item>
00436 void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
00437 #if __TBB_TASK_GROUP_CONTEXT
00438 , task_group_context& context
00439 #endif
00440 )
00441 {
00442 run_parallel_do<Iterator, Body, typename strip<Item>::type>( first, last, body
00443 #if __TBB_TASK_GROUP_CONTEXT
00444 , context
00445 #endif // __TBB_TASK_GROUP_CONTEXT
00446 );
00447 }
00448
00449 }
00451
00452
00475
00476
00477 template<typename Iterator, typename Body>
00478 void parallel_do( Iterator first, Iterator last, const Body& body )
00479 {
00480 if ( first == last )
00481 return;
00482 #if __TBB_TASK_GROUP_CONTEXT
00483 task_group_context context;
00484 #endif // __TBB_TASK_GROUP_CONTEXT
00485 internal::select_parallel_do( first, last, body, &Body::operator()
00486 #if __TBB_TASK_GROUP_CONTEXT
00487 , context
00488 #endif
00489 );
00490 }
00491
00492 #if __TBB_TASK_GROUP_CONTEXT
00494
00495 template<typename Iterator, typename Body>
00496 void parallel_do( Iterator first, Iterator last, const Body& body, task_group_context& context )
00497 {
00498 if ( first == last )
00499 return;
00500 internal::select_parallel_do( first, last, body, &Body::operator(), context );
00501 }
00502 #endif // __TBB_TASK_GROUP_CONTEXT
00503
00505
00506 }
00507
00508 #endif