![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 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 // Most of the compilers remove cv-qualifiers from non-reference function argument types. 00055 // But unfortunately there are those that don't. 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 } // namespace internal 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 /*override*/ 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 }; // class do_iteration_task 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 /*override*/ 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 }; // class do_iteration_task_iter 00153 00155 00157 template<class Body, typename Item> 00158 class parallel_do_feeder_impl : public parallel_do_feeder<Item> 00159 { 00160 /*override*/ 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 }; // class parallel_do_feeder_impl 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 /*override*/ 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 }; // class do_group_task_forward 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 /*override*/ 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 }; // class do_group_task_input 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 /* Do not merge run(xxx) and run_xxx() methods. They are separated in order 00295 to make sure that compilers will eliminate unused argument of type xxx 00296 (that is will not put it on stack). The sole purpose of this argument 00297 is overload resolution. 00298 00299 An alternative could be using template functions, but explicit specialization 00300 of member function templates is not supported for non specialized class 00301 templates. Besides template functions would always fall back to the least 00302 efficient variant (the one for input iterators) in case of iterators having 00303 custom tags derived from basic ones. */ 00304 /*override*/ 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 }; // class do_task_iter 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 // __TBB_TASK_GROUP_CONTEXT 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 // __TBB_TASK_GROUP_CONTEXT 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 } // namespace internal 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 // __TBB_TASK_GROUP_CONTEXT 00489 ); 00490 } 00491 00492 #if __TBB_TASK_GROUP_CONTEXT 00493 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 } // namespace 00507 00508 #endif /* __TBB_parallel_do_H */
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.