File indexing completed on 2025-01-18 10:12:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB_parallel_do_H
0018 #define __TBB_parallel_do_H
0019
0020 #define __TBB_parallel_do_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022
0023 #include "internal/_range_iterator.h"
0024 #include "internal/_template_helpers.h"
0025 #include "task.h"
0026 #include "aligned_space.h"
0027 #include <iterator>
0028
0029 namespace tbb {
0030 namespace interface9 {
0031
0032 namespace internal {
0033 template<typename Body, typename Item> class parallel_do_feeder_impl;
0034 }
0035
0036
0037
0038
0039 template<typename Item>
0040 class parallel_do_feeder: ::tbb::internal::no_copy
0041 {
0042 parallel_do_feeder() {}
0043 virtual ~parallel_do_feeder () {}
0044 virtual void internal_add_copy( const Item& item ) = 0;
0045 #if __TBB_CPP11_RVALUE_REF_PRESENT
0046 virtual void internal_add_move( Item&& item ) = 0;
0047 #endif
0048 template<typename Body_, typename Item_> friend class internal::parallel_do_feeder_impl;
0049 public:
0050
0051 void add( const Item& item ) {internal_add_copy(item);}
0052 #if __TBB_CPP11_RVALUE_REF_PRESENT
0053 void add( Item&& item ) {internal_add_move(std::move(item));}
0054 #endif
0055 };
0056
0057
0058 namespace internal {
0059 template<typename Body> class do_group_task;
0060
0061
0062
0063
0064 template<class Body, typename Item>
0065 class parallel_do_operator_selector
0066 {
0067 typedef parallel_do_feeder<Item> Feeder;
0068 template<typename A1, typename A2, typename CvItem >
0069 static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2&, void (Body::*)(CvItem) const ) {
0070 obj(tbb::internal::forward<A1>(arg1));
0071 }
0072 template<typename A1, typename A2, typename CvItem >
0073 static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2, void (Body::*)(CvItem, parallel_do_feeder<Item>&) const ) {
0074 obj(tbb::internal::forward<A1>(arg1), arg2);
0075 }
0076 template<typename A1, typename A2, typename CvItem >
0077 static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2&, void (Body::*)(CvItem&) const ) {
0078 obj(arg1);
0079 }
0080 template<typename A1, typename A2, typename CvItem >
0081 static void internal_call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2, void (Body::*)(CvItem&, parallel_do_feeder<Item>&) const ) {
0082 obj(arg1, arg2);
0083 }
0084 public:
0085 template<typename A1, typename A2>
0086 static void call( const Body& obj, __TBB_FORWARDING_REF(A1) arg1, A2& arg2 )
0087 {
0088 internal_call( obj, tbb::internal::forward<A1>(arg1), arg2, &Body::operator() );
0089 }
0090 };
0091
0092
0093
0094
0095 template<typename Body, typename Item>
0096 class do_iteration_task: public task
0097 {
0098 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
0099
0100 Item my_value;
0101 feeder_type& my_feeder;
0102
0103 do_iteration_task( const Item& value, feeder_type& feeder ) :
0104 my_value(value), my_feeder(feeder)
0105 {}
0106
0107 #if __TBB_CPP11_RVALUE_REF_PRESENT
0108 do_iteration_task( Item&& value, feeder_type& feeder ) :
0109 my_value(std::move(value)), my_feeder(feeder)
0110 {}
0111 #endif
0112
0113 task* execute() __TBB_override
0114 {
0115 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, tbb::internal::move(my_value), my_feeder);
0116 return NULL;
0117 }
0118
0119 template<typename Body_, typename Item_> friend class parallel_do_feeder_impl;
0120 };
0121
0122 template<typename Iterator, typename Body, typename Item>
0123 class do_iteration_task_iter: public task
0124 {
0125 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
0126
0127 Iterator my_iter;
0128 feeder_type& my_feeder;
0129
0130 do_iteration_task_iter( const Iterator& iter, feeder_type& feeder ) :
0131 my_iter(iter), my_feeder(feeder)
0132 {}
0133
0134 task* execute() __TBB_override
0135 {
0136 parallel_do_operator_selector<Body, Item>::call(*my_feeder.my_body, *my_iter, my_feeder);
0137 return NULL;
0138 }
0139
0140 template<typename Iterator_, typename Body_, typename Item_> friend class do_group_task_forward;
0141 template<typename Body_, typename Item_> friend class do_group_task_input;
0142 template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
0143 };
0144
0145
0146
0147
0148 template<class Body, typename Item>
0149 class parallel_do_feeder_impl : public parallel_do_feeder<Item>
0150 {
0151 #if __TBB_CPP11_RVALUE_REF_PRESENT
0152
0153 void internal_add_copy_impl(std::true_type, const Item& item) {
0154 typedef do_iteration_task<Body, Item> iteration_type;
0155 iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
0156 task::spawn(t);
0157 }
0158 void internal_add_copy_impl(std::false_type, const Item&) {
0159 __TBB_ASSERT(false, "Overloading for r-value reference doesn't work or it's not movable and not copyable object");
0160 }
0161 void internal_add_copy( const Item& item ) __TBB_override
0162 {
0163 #if __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT
0164 internal_add_copy_impl(typename std::is_copy_constructible<Item>::type(), item);
0165 #else
0166 internal_add_copy_impl(std::true_type(), item);
0167 #endif
0168 }
0169 void internal_add_move( Item&& item ) __TBB_override
0170 {
0171 typedef do_iteration_task<Body, Item> iteration_type;
0172 iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(std::move(item), *this);
0173 task::spawn(t);
0174 }
0175 #else
0176 void internal_add_copy(const Item& item) __TBB_override {
0177 typedef do_iteration_task<Body, Item> iteration_type;
0178 iteration_type& t = *new (task::allocate_additional_child_of(*my_barrier)) iteration_type(item, *this);
0179 task::spawn(t);
0180 }
0181 #endif
0182 public:
0183 const Body* my_body;
0184 empty_task* my_barrier;
0185
0186 parallel_do_feeder_impl()
0187 {
0188 my_barrier = new( task::allocate_root() ) empty_task();
0189 __TBB_ASSERT(my_barrier, "root task allocation failed");
0190 }
0191
0192 #if __TBB_TASK_GROUP_CONTEXT
0193 parallel_do_feeder_impl(tbb::task_group_context &context)
0194 {
0195 my_barrier = new( task::allocate_root(context) ) empty_task();
0196 __TBB_ASSERT(my_barrier, "root task allocation failed");
0197 }
0198 #endif
0199
0200 ~parallel_do_feeder_impl()
0201 {
0202 my_barrier->destroy(*my_barrier);
0203 }
0204 };
0205
0206
0207
0208
0209
0210
0211 template<typename Iterator, typename Body, typename Item>
0212 class do_group_task_forward: public task
0213 {
0214 static const size_t max_arg_size = 4;
0215
0216 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
0217
0218 feeder_type& my_feeder;
0219 Iterator my_first;
0220 size_t my_size;
0221
0222 do_group_task_forward( Iterator first, size_t size, feeder_type& feeder )
0223 : my_feeder(feeder), my_first(first), my_size(size)
0224 {}
0225
0226 task* execute() __TBB_override
0227 {
0228 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
0229 __TBB_ASSERT( my_size>0, NULL );
0230 task_list list;
0231 task* t;
0232 size_t k=0;
0233 for(;;) {
0234 t = new( allocate_child() ) iteration_type( my_first, my_feeder );
0235 ++my_first;
0236 if( ++k==my_size ) break;
0237 list.push_back(*t);
0238 }
0239 set_ref_count(int(k+1));
0240 spawn(list);
0241 spawn_and_wait_for_all(*t);
0242 return NULL;
0243 }
0244
0245 template<typename Iterator_, typename Body_, typename _Item> friend class do_task_iter;
0246 };
0247
0248 template<typename Body, typename Item>
0249 class do_group_task_input: public task
0250 {
0251 static const size_t max_arg_size = 4;
0252
0253 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
0254
0255 feeder_type& my_feeder;
0256 size_t my_size;
0257 aligned_space<Item, max_arg_size> my_arg;
0258
0259 do_group_task_input( feeder_type& feeder )
0260 : my_feeder(feeder), my_size(0)
0261 {}
0262
0263 task* execute() __TBB_override
0264 {
0265 #if __TBB_CPP11_RVALUE_REF_PRESENT
0266 typedef std::move_iterator<Item*> Item_iterator;
0267 #else
0268 typedef Item* Item_iterator;
0269 #endif
0270 typedef do_iteration_task_iter<Item_iterator, Body, Item> iteration_type;
0271 __TBB_ASSERT( my_size>0, NULL );
0272 task_list list;
0273 task* t;
0274 size_t k=0;
0275 for(;;) {
0276 t = new( allocate_child() ) iteration_type( Item_iterator(my_arg.begin() + k), my_feeder );
0277 if( ++k==my_size ) break;
0278 list.push_back(*t);
0279 }
0280 set_ref_count(int(k+1));
0281 spawn(list);
0282 spawn_and_wait_for_all(*t);
0283 return NULL;
0284 }
0285
0286 ~do_group_task_input(){
0287 for( size_t k=0; k<my_size; ++k)
0288 (my_arg.begin() + k)->~Item();
0289 }
0290
0291 template<typename Iterator_, typename Body_, typename Item_> friend class do_task_iter;
0292 };
0293
0294
0295
0296
0297 template<typename Iterator, typename Body, typename Item>
0298 class do_task_iter: public task
0299 {
0300 typedef parallel_do_feeder_impl<Body, Item> feeder_type;
0301
0302 public:
0303 do_task_iter( Iterator first, Iterator last , feeder_type& feeder ) :
0304 my_first(first), my_last(last), my_feeder(feeder)
0305 {}
0306
0307 private:
0308 Iterator my_first;
0309 Iterator my_last;
0310 feeder_type& my_feeder;
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322 task* execute() __TBB_override
0323 {
0324 typedef typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
0325 return run( (iterator_tag*)NULL );
0326 }
0327
0328
0329
0330 inline task* run( void* ) { return run_for_input_iterator(); }
0331
0332 task* run_for_input_iterator() {
0333 typedef do_group_task_input<Body, Item> block_type;
0334
0335 block_type& t = *new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(my_feeder);
0336 size_t k=0;
0337 while( !(my_first == my_last) ) {
0338
0339 new (t.my_arg.begin() + k) Item(*my_first);
0340 ++my_first;
0341 if( ++k==block_type::max_arg_size ) {
0342 if ( !(my_first == my_last) )
0343 recycle_to_reexecute();
0344 break;
0345 }
0346 }
0347 if( k==0 ) {
0348 destroy(t);
0349 return NULL;
0350 } else {
0351 t.my_size = k;
0352 return &t;
0353 }
0354 }
0355
0356 inline task* run( std::forward_iterator_tag* ) { return run_for_forward_iterator(); }
0357
0358 task* run_for_forward_iterator() {
0359 typedef do_group_task_forward<Iterator, Body, Item> block_type;
0360
0361 Iterator first = my_first;
0362 size_t k=0;
0363 while( !(my_first==my_last) ) {
0364 ++my_first;
0365 if( ++k==block_type::max_arg_size ) {
0366 if ( !(my_first==my_last) )
0367 recycle_to_reexecute();
0368 break;
0369 }
0370 }
0371 return k==0 ? NULL : new( allocate_additional_child_of(*my_feeder.my_barrier) ) block_type(first, k, my_feeder);
0372 }
0373
0374 inline task* run( std::random_access_iterator_tag* ) { return run_for_random_access_iterator(); }
0375
0376 task* run_for_random_access_iterator() {
0377 typedef do_group_task_forward<Iterator, Body, Item> block_type;
0378 typedef do_iteration_task_iter<Iterator, Body, Item> iteration_type;
0379
0380 size_t k = static_cast<size_t>(my_last-my_first);
0381 if( k > block_type::max_arg_size ) {
0382 Iterator middle = my_first + k/2;
0383
0384 empty_task& c = *new( allocate_continuation() ) empty_task;
0385 do_task_iter& b = *new( c.allocate_child() ) do_task_iter(middle, my_last, my_feeder);
0386 recycle_as_child_of(c);
0387
0388 my_last = middle;
0389 c.set_ref_count(2);
0390 c.spawn(b);
0391 return this;
0392 }else if( k != 0 ) {
0393 task_list list;
0394 task* t;
0395 size_t k1=0;
0396 for(;;) {
0397 t = new( allocate_child() ) iteration_type(my_first, my_feeder);
0398 ++my_first;
0399 if( ++k1==k ) break;
0400 list.push_back(*t);
0401 }
0402 set_ref_count(int(k+1));
0403 spawn(list);
0404 spawn_and_wait_for_all(*t);
0405 }
0406 return NULL;
0407 }
0408 };
0409
0410
0411
0412
0413 template<typename Iterator, typename Body, typename Item>
0414 void run_parallel_do( Iterator first, Iterator last, const Body& body
0415 #if __TBB_TASK_GROUP_CONTEXT
0416 , task_group_context& context
0417 #endif
0418 )
0419 {
0420 typedef do_task_iter<Iterator, Body, Item> root_iteration_task;
0421 #if __TBB_TASK_GROUP_CONTEXT
0422 parallel_do_feeder_impl<Body, Item> feeder(context);
0423 #else
0424 parallel_do_feeder_impl<Body, Item> feeder;
0425 #endif
0426 feeder.my_body = &body;
0427
0428 root_iteration_task &t = *new( feeder.my_barrier->allocate_child() ) root_iteration_task(first, last, feeder);
0429
0430 feeder.my_barrier->set_ref_count(2);
0431 feeder.my_barrier->spawn_and_wait_for_all(t);
0432 }
0433
0434
0435
0436
0437 template<typename Iterator, typename Body, typename Item>
0438 void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item) const
0439 #if __TBB_TASK_GROUP_CONTEXT
0440 , task_group_context& context
0441 #endif
0442 )
0443 {
0444 run_parallel_do<Iterator, Body, typename ::tbb::internal::strip<Item>::type>( first, last, body
0445 #if __TBB_TASK_GROUP_CONTEXT
0446 , context
0447 #endif
0448 );
0449 }
0450
0451
0452
0453
0454 template<typename Iterator, typename Body, typename Item, typename _Item>
0455 void select_parallel_do( Iterator first, Iterator last, const Body& body, void (Body::*)(Item, parallel_do_feeder<_Item>&) const
0456 #if __TBB_TASK_GROUP_CONTEXT
0457 , task_group_context& context
0458 #endif
0459 )
0460 {
0461 run_parallel_do<Iterator, Body, typename ::tbb::internal::strip<Item>::type>( first, last, body
0462 #if __TBB_TASK_GROUP_CONTEXT
0463 , context
0464 #endif
0465 );
0466 }
0467
0468 }
0469 }
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496 template<typename Iterator, typename Body>
0497 void parallel_do( Iterator first, Iterator last, const Body& body )
0498 {
0499 if ( first == last )
0500 return;
0501 #if __TBB_TASK_GROUP_CONTEXT
0502 task_group_context context(internal::PARALLEL_DO);
0503 #endif
0504 interface9::internal::select_parallel_do( first, last, body, &Body::operator()
0505 #if __TBB_TASK_GROUP_CONTEXT
0506 , context
0507 #endif
0508 );
0509 }
0510
0511 template<typename Range, typename Body>
0512 void parallel_do(Range& rng, const Body& body) {
0513 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body);
0514 }
0515
0516 template<typename Range, typename Body>
0517 void parallel_do(const Range& rng, const Body& body) {
0518 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body);
0519 }
0520
0521 #if __TBB_TASK_GROUP_CONTEXT
0522
0523
0524 template<typename Iterator, typename Body>
0525 void parallel_do( Iterator first, Iterator last, const Body& body, task_group_context& context )
0526 {
0527 if ( first == last )
0528 return;
0529 interface9::internal::select_parallel_do( first, last, body, &Body::operator(), context );
0530 }
0531
0532 template<typename Range, typename Body>
0533 void parallel_do(Range& rng, const Body& body, task_group_context& context) {
0534 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
0535 }
0536
0537 template<typename Range, typename Body>
0538 void parallel_do(const Range& rng, const Body& body, task_group_context& context) {
0539 parallel_do(tbb::internal::first(rng), tbb::internal::last(rng), body, context);
0540 }
0541
0542 #endif
0543
0544
0545
0546 using interface9::parallel_do_feeder;
0547
0548 }
0549
0550 #include "internal/_warning_suppress_disable_notice.h"
0551 #undef __TBB_parallel_do_H_include_area
0552
0553 #endif