00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_graph_H
00022 #define __TBB_graph_H
00023
00024 #if !TBB_PREVIEW_GRAPH
00025 #error Set TBB_PREVIEW_GRAPH to include graph.h
00026 #endif
00027
00028 #include "tbb_stddef.h"
00029 #include "atomic.h"
00030 #include "spin_mutex.h"
00031 #include "null_mutex.h"
00032 #include "spin_rw_mutex.h"
00033 #include "null_rw_mutex.h"
00034 #include "task.h"
00035 #include "concurrent_vector.h"
00036 #include "_aggregator_internal.h"
00037
00038
00039 #if TBB_IMPLEMENT_CPP0X && (!defined(_MSC_VER) || _MSC_VER < 1600)
00040 #define TBB_PREVIEW_TUPLE 1
00041 #include "compat/tuple"
00042 #else
00043 #include <tuple>
00044 #endif
00045
00046 #include<list>
00047 #include<queue>
00048
00049
00060 namespace tbb {
00061
00063 class graph_node {
00064 public:
00065 virtual ~graph_node() {}
00066 };
00067
00069 class continue_msg {};
00070
00071 template< typename T > class sender;
00072 template< typename T > class receiver;
00073 class continue_receiver;
00074
00076 template< typename T >
00077 class sender {
00078 public:
00080 typedef T output_type;
00081
00083 typedef receiver<T> successor_type;
00084
00085 virtual ~sender() {}
00086
00088 virtual bool register_successor( successor_type &r ) = 0;
00089
00091 virtual bool remove_successor( successor_type &r ) = 0;
00092
00094 virtual bool try_get( T & ) { return false; }
00095
00097 virtual bool try_reserve( T & ) { return false; }
00098
00100 virtual bool try_release( ) { return false; }
00101
00103 virtual bool try_consume( ) { return false; }
00104
00105 };
00106
00107
00109 template< typename T >
00110 class receiver {
00111 public:
00112
00114 typedef T input_type;
00115
00117 typedef sender<T> predecessor_type;
00118
00120 virtual ~receiver() {}
00121
00123 virtual bool try_put( T t ) = 0;
00124
00126 virtual bool register_predecessor( predecessor_type & ) { return false; }
00127
00129 virtual bool remove_predecessor( predecessor_type & ) { return false; }
00130
00131 };
00132
00134
00135 class continue_receiver : public receiver< continue_msg > {
00136 public:
00137
00139 typedef continue_msg input_type;
00140
00142 typedef sender< continue_msg > predecessor_type;
00143
00145 continue_receiver( int number_of_predecessors = 0 ) {
00146 my_predecessor_count = number_of_predecessors;
00147 my_current_count = 0;
00148 }
00149
00151 virtual ~continue_receiver() { }
00152
00154 bool register_predecessor( predecessor_type & ) {
00155 spin_mutex::scoped_lock l(my_mutex);
00156 ++my_predecessor_count;
00157 return true;
00158 }
00159
00161
00164 bool remove_predecessor( predecessor_type & ) {
00165 spin_mutex::scoped_lock l(my_mutex);
00166 --my_predecessor_count;
00167 return true;
00168 }
00169
00171
00173 bool try_put( input_type ) {
00174 {
00175 spin_mutex::scoped_lock l(my_mutex);
00176 if ( ++my_current_count < my_predecessor_count )
00177 return true;
00178 else
00179 my_current_count = 0;
00180 }
00181 execute();
00182 return true;
00183 }
00184
00185 protected:
00186
00187 spin_mutex my_mutex;
00188 int my_predecessor_count;
00189 int my_current_count;
00190
00192
00194 virtual void execute() = 0;
00195
00196 };
00197
00199 namespace internal {
00200
00202 enum node_state { node_state_idle=0, node_state_nonidle=1, node_state_inactive=2 };
00203
00204
00206 template< typename Output >
00207 class source_body : no_assign {
00208 public:
00209 virtual ~source_body() {}
00210 virtual bool operator()(Output &output) = 0;
00211 };
00212
00214 template< typename Output, typename Body>
00215 class source_body_leaf : public source_body<Output> {
00216 public:
00217 source_body_leaf( Body _body ) : body(_body) { }
00218 bool operator()(Output &output) { return body( output ); }
00219 private:
00220 Body body;
00221 };
00222
00224 template< typename Input, typename Output >
00225 class function_body : no_assign {
00226 public:
00227 virtual ~function_body() {}
00228 virtual Output operator()(Input input) = 0;
00229 };
00230
00232 template <typename Input, typename Output, typename B>
00233 class function_body_leaf : public function_body< Input, Output > {
00234 public:
00235 function_body_leaf( B _body ) : body(_body) { }
00236 Output operator()(Input i) { return body(i); }
00237
00238 private:
00239 B body;
00240 };
00241
00243 template <typename B>
00244 class function_body_leaf< continue_msg, continue_msg, B> : public function_body< continue_msg, continue_msg > {
00245 public:
00246 function_body_leaf( B _body ) : body(_body) { }
00247 continue_msg operator()( continue_msg i ) {
00248 body(i);
00249 return i;
00250 }
00251
00252 private:
00253 B body;
00254 };
00255
00257 template <typename Input, typename B>
00258 class function_body_leaf< Input, continue_msg, B> : public function_body< Input, continue_msg > {
00259 public:
00260 function_body_leaf( B _body ) : body(_body) { }
00261 continue_msg operator()(Input i) {
00262 body(i);
00263 return continue_msg();
00264 }
00265
00266 private:
00267 B body;
00268 };
00269
00271 template <typename Output, typename B>
00272 class function_body_leaf< continue_msg, Output, B > : public function_body< continue_msg, Output > {
00273 public:
00274 function_body_leaf( B _body ) : body(_body) { }
00275 Output operator()(continue_msg i) {
00276 return body(i);
00277 }
00278
00279 private:
00280 B body;
00281 };
00282
00284 template< typename NodeType >
00285 class forward_task : public task {
00286
00287 NodeType &my_node;
00288
00289 public:
00290
00291 forward_task( NodeType &n ) : my_node(n) {}
00292
00293 task *execute() {
00294 my_node.forward();
00295 return NULL;
00296 }
00297 };
00298
00300 template< typename NodeType, typename Input >
00301 class apply_body_task : public task {
00302
00303 NodeType &my_node;
00304 Input my_input;
00305
00306 public:
00307
00308 apply_body_task( NodeType &n, Input i ) : my_node(n), my_input(i) {}
00309
00310 task *execute() {
00311 my_node.apply_body( my_input );
00312 return NULL;
00313 }
00314 };
00315
00317 template< typename NodeType >
00318 class source_task : public task {
00319
00320 NodeType &my_node;
00321
00322 public:
00323
00324 source_task( NodeType &n ) : my_node(n) {}
00325
00326 task *execute() {
00327 my_node.apply_body( );
00328 return NULL;
00329 }
00330 };
00331
00333 template< typename Input, typename Output >
00334 struct empty_body {
00335 Output operator()( const Input & ) const { return Output(); }
00336 };
00337
00339 template< typename T, typename M=spin_mutex >
00340 class node_cache {
00341 public:
00342
00343 typedef size_t size_type;
00344
00345 bool empty() {
00346 typename my_mutex_type::scoped_lock lock( my_mutex );
00347 return internal_empty();
00348 }
00349
00350 void add( T &n ) {
00351 typename my_mutex_type::scoped_lock lock( my_mutex );
00352 internal_push(n);
00353 }
00354
00355 void remove( T &n ) {
00356 typename my_mutex_type::scoped_lock lock( my_mutex );
00357 for ( size_t i = internal_size(); i != 0; --i ) {
00358 T &s = internal_pop();
00359 if ( &s != &n ) {
00360 internal_push(s);
00361 }
00362 }
00363 }
00364
00365 protected:
00366
00367 typedef M my_mutex_type;
00368 my_mutex_type my_mutex;
00369 std::queue< T * > my_q;
00370
00371
00372 inline bool internal_empty( ) {
00373 return my_q.empty();
00374 }
00375
00376
00377 inline size_type internal_size( ) {
00378 return my_q.size();
00379 }
00380
00381
00382 inline void internal_push( T &n ) {
00383 my_q.push(&n);
00384 }
00385
00386
00387 inline T &internal_pop() {
00388 T *v = my_q.front();
00389 my_q.pop();
00390 return *v;
00391 }
00392
00393 };
00394
00396 template< typename T, typename M=spin_mutex >
00397 class predecessor_cache : public node_cache< sender<T>, M > {
00398 public:
00399 typedef M my_mutex_type;
00400 typedef T output_type;
00401 typedef sender<output_type> predecessor_type;
00402 typedef receiver<output_type> successor_type;
00403
00404 predecessor_cache( ) : my_owner( NULL ) { }
00405
00406 void set_owner( successor_type *owner ) { my_owner = owner; }
00407
00408 bool get_item( output_type &v ) {
00409
00410 bool msg = false;
00411
00412 do {
00413 predecessor_type *src;
00414 {
00415 typename my_mutex_type::scoped_lock lock(this->my_mutex);
00416 if ( this->internal_empty() ) {
00417 break;
00418 }
00419 src = &this->internal_pop();
00420 }
00421
00422
00423 msg = src->try_get( v );
00424
00425 if (msg == false) {
00426
00427 if ( my_owner)
00428 src->register_successor( *my_owner );
00429 } else {
00430
00431 this->add(*src);
00432 }
00433 } while ( msg == false );
00434 return msg;
00435 }
00436
00437 protected:
00438 successor_type *my_owner;
00439 };
00440
00442 template< typename T, typename M=spin_mutex >
00443 class reservable_predecessor_cache : public predecessor_cache< T, M > {
00444 public:
00445 typedef M my_mutex_type;
00446 typedef T output_type;
00447 typedef sender<T> predecessor_type;
00448 typedef receiver<T> successor_type;
00449
00450 reservable_predecessor_cache( ) : reserved_src(NULL) { }
00451
00452 bool
00453 try_reserve( output_type &v ) {
00454 bool msg = false;
00455
00456 do {
00457 {
00458 typename my_mutex_type::scoped_lock lock(this->my_mutex);
00459 if ( reserved_src || this->internal_empty() )
00460 return false;
00461
00462 reserved_src = &this->internal_pop();
00463 }
00464
00465
00466 msg = reserved_src->try_reserve( v );
00467
00468 if (msg == false) {
00469 typename my_mutex_type::scoped_lock lock(this->my_mutex);
00470
00471 reserved_src->register_successor( *this->my_owner );
00472 reserved_src = NULL;
00473 } else {
00474
00475 this->add( *reserved_src );
00476 }
00477 } while ( msg == false );
00478
00479 return msg;
00480 }
00481
00482 bool
00483 try_release( ) {
00484 reserved_src->try_release( );
00485 reserved_src = NULL;
00486 return true;
00487 }
00488
00489 bool
00490 try_consume( ) {
00491 reserved_src->try_consume( );
00492 reserved_src = NULL;
00493 return true;
00494 }
00495
00496 private:
00497 predecessor_type *reserved_src;
00498 };
00499
00500
00502 template<typename T, typename M=spin_rw_mutex >
00503 class successor_cache : no_copy {
00504 protected:
00505
00506 typedef M my_mutex_type;
00507 my_mutex_type my_mutex;
00508
00509 typedef std::list< receiver<T> * > my_successors_type;
00510 my_successors_type my_successors;
00511
00512 sender<T> *my_owner;
00513
00514 public:
00515
00516 successor_cache( ) : my_owner(NULL) {}
00517
00518 void set_owner( sender<T> *owner ) { my_owner = owner; }
00519
00520 virtual ~successor_cache() {}
00521
00522 void register_successor( receiver<T> &r ) {
00523 typename my_mutex_type::scoped_lock l(my_mutex, true);
00524 my_successors.push_back( &r );
00525 }
00526
00527 void remove_successor( receiver<T> &r ) {
00528 typename my_mutex_type::scoped_lock l(my_mutex, true);
00529 for ( typename my_successors_type::iterator i = my_successors.begin();
00530 i != my_successors.end(); ++i ) {
00531 if ( *i == & r ) {
00532 my_successors.erase(i);
00533 break;
00534 }
00535 }
00536 }
00537
00538 bool empty() {
00539 typename my_mutex_type::scoped_lock l(my_mutex, false);
00540 return my_successors.empty();
00541 }
00542
00543 virtual bool try_put( T t ) = 0;
00544 };
00545
00547 template<>
00548 class successor_cache< continue_msg > : no_copy {
00549 protected:
00550
00551 typedef spin_rw_mutex my_mutex_type;
00552 my_mutex_type my_mutex;
00553
00554 typedef std::list< receiver<continue_msg> * > my_successors_type;
00555 my_successors_type my_successors;
00556
00557 sender<continue_msg> *my_owner;
00558
00559 public:
00560
00561 successor_cache( ) : my_owner(NULL) {}
00562
00563 void set_owner( sender<continue_msg> *owner ) { my_owner = owner; }
00564
00565 virtual ~successor_cache() {}
00566
00567 void register_successor( receiver<continue_msg> &r ) {
00568 my_mutex_type::scoped_lock l(my_mutex, true);
00569 my_successors.push_back( &r );
00570 if ( my_owner )
00571 r.register_predecessor( *my_owner );
00572 }
00573
00574 void remove_successor( receiver<continue_msg> &r ) {
00575 my_mutex_type::scoped_lock l(my_mutex, true);
00576 for ( my_successors_type::iterator i = my_successors.begin();
00577 i != my_successors.end(); ++i ) {
00578 if ( *i == & r ) {
00579 if ( my_owner )
00580 r.remove_predecessor( *my_owner );
00581 my_successors.erase(i);
00582 break;
00583 }
00584 }
00585 }
00586
00587 bool empty() {
00588 my_mutex_type::scoped_lock l(my_mutex, false);
00589 return my_successors.empty();
00590 }
00591
00592 virtual bool try_put( continue_msg t ) = 0;
00593
00594 };
00595
00597 template<typename T, typename M=spin_rw_mutex>
00598 class broadcast_cache : public successor_cache<T, M> {
00599 typedef M my_mutex_type;
00600 typedef std::list< receiver<T> * > my_successors_type;
00601
00602 public:
00603
00604 broadcast_cache( ) {}
00605
00606 bool try_put( T t ) {
00607 bool msg = false;
00608 bool upgraded = false;
00609 typename my_mutex_type::scoped_lock l(this->my_mutex, false);
00610 typename my_successors_type::iterator i = this->my_successors.begin();
00611 while ( i != this->my_successors.end() ) {
00612 if ( (*i)->try_put( t ) == true ) {
00613 ++i;
00614 msg = true;
00615 } else {
00616 if ( (*i)->register_predecessor(*this->my_owner) ) {
00617 if (!upgraded) {
00618 l.upgrade_to_writer();
00619 upgraded = true;
00620 }
00621 i = this->my_successors.erase(i);
00622 }
00623 else {
00624 ++i;
00625 }
00626 }
00627 }
00628 return msg;
00629 }
00630 };
00631
00633 template<typename T, typename M=spin_rw_mutex >
00634 class round_robin_cache : public successor_cache<T, M> {
00635 typedef size_t size_type;
00636 typedef M my_mutex_type;
00637 typedef std::list< receiver<T> * > my_successors_type;
00638
00639 public:
00640
00641 round_robin_cache( ) {}
00642
00643 size_type size() {
00644 typename my_mutex_type::scoped_lock l(this->my_mutex, false);
00645 return this->my_successors.size();
00646 }
00647
00648 bool try_put( T t ) {
00649 bool upgraded = false;
00650 typename my_mutex_type::scoped_lock l(this->my_mutex, false);
00651 typename my_successors_type::iterator i = this->my_successors.begin();
00652 while ( i != this->my_successors.end() ) {
00653 if ( (*i)->try_put( t ) ) {
00654 return true;
00655 } else {
00656 if ( (*i)->register_predecessor(*this->my_owner) ) {
00657 if (!upgraded) {
00658 l.upgrade_to_writer();
00659 upgraded = true;
00660 }
00661 i = this->my_successors.erase(i);
00662 }
00663 else {
00664 ++i;
00665 }
00666 }
00667 }
00668 return false;
00669 }
00670 };
00671
00672 template<typename T>
00673 class decrementer : public continue_receiver, internal::no_copy {
00674
00675 T *my_node;
00676
00677 void execute() {
00678 my_node->decrement_counter();
00679 }
00680
00681 public:
00682
00683 typedef continue_msg input_type;
00684 typedef continue_msg output_type;
00685 decrementer( int number_of_predecessors = 0 ) : continue_receiver( number_of_predecessors ) { }
00686 void set_owner( T *node ) { my_node = node; }
00687 };
00688
00689 }
00691
00692
00694
00695 class graph : internal::no_copy {
00696
00697 template< typename Body >
00698 class run_task : public task {
00699 public:
00700 run_task( Body& body ) : my_body(body) {}
00701 task *execute() {
00702 my_body();
00703 return NULL;
00704 }
00705 private:
00706 Body my_body;
00707 };
00708
00709 template< typename Receiver, typename Body >
00710 class run_and_put_task : public task {
00711 public:
00712 run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_body(body) {}
00713 task *execute() {
00714 my_receiver.try_put( my_body() );
00715 return NULL;
00716 }
00717 private:
00718 Receiver &my_receiver;
00719 Body my_body;
00720 };
00721
00722 public:
00723
00725 enum concurrency { unlimited = 0, serial = 1 };
00726
00728 graph() : my_root_task( new ( task::allocate_root( ) ) empty_task ) {
00729 my_root_task->set_ref_count(1);
00730 }
00731
00733
00735 ~graph() {
00736 wait_for_all();
00737 my_root_task->set_ref_count(0);
00738 task::destroy( *my_root_task );
00739 }
00740
00741
00743
00745 void increment_wait_count() {
00746 if (my_root_task)
00747 my_root_task->increment_ref_count();
00748 }
00749
00751
00753 void decrement_wait_count() {
00754 if (my_root_task)
00755 my_root_task->decrement_ref_count();
00756 }
00757
00759
00761 template< typename Receiver, typename Body >
00762 void run( Receiver &r, Body body ) {
00763 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
00764 run_and_put_task< Receiver, Body >( r, body ) );
00765 }
00766
00768
00770 template< typename Body >
00771 void run( Body body ) {
00772 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
00773 run_task< Body >( body ) );
00774 }
00775
00777
00778 void wait_for_all() {
00779 if (my_root_task)
00780 my_root_task->wait_for_all();
00781 my_root_task->set_ref_count(1);
00782 }
00783
00785 task * root_task() {
00786 return my_root_task;
00787 }
00788
00789 private:
00790
00791 task *my_root_task;
00792
00793 };
00794
00795
00797 namespace internal {
00798
00800 template< typename Input, typename Output >
00801 class function_input : public receiver<Input>, no_assign {
00802 typedef sender<Input> predecessor_type;
00803 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
00804 enum op_type {reg_pred, rem_pred, app_body, tryput, try_fwd};
00805
00806 public:
00808 typedef Input input_type;
00810 typedef Output output_type;
00811
00813 template< typename Body >
00814 function_input( graph &g, size_t max_concurrency, Body& body )
00815 : my_root_task(g.root_task()), my_max_concurrency(max_concurrency), my_concurrency(internal::node_state_idle),
00816 my_body( new internal::function_body_leaf< input_type, output_type, Body>(body) ),
00817 forwarder_busy(false) {
00818 my_predecessors.set_owner(this);
00819 my_aggregator.initialize_handler(my_functor_t(this));
00820 }
00821
00823 virtual ~function_input() { delete my_body; }
00824
00826 virtual bool try_put( input_type t ) {
00827 if ( my_max_concurrency == 0 ) {
00828 spawn_body_task( t );
00829 return true;
00830 } else {
00831 my_operation op_data(t, tryput);
00832 my_aggregator.execute(&op_data);
00833 return op_data.status == SUCCEEDED;
00834 }
00835 }
00836
00838 bool register_predecessor( predecessor_type &src ) {
00839 my_operation op_data(reg_pred);
00840 op_data.r = &src;
00841 my_aggregator.execute(&op_data);
00842 return true;
00843 }
00844
00846 bool remove_predecessor( predecessor_type &src ) {
00847 my_operation op_data(rem_pred);
00848 op_data.r = &src;
00849 my_aggregator.execute(&op_data);
00850 return true;
00851 }
00852
00853 protected:
00854 task *my_root_task;
00855 const size_t my_max_concurrency;
00856 size_t my_concurrency;
00857 function_body<input_type, output_type> *my_body;
00858 predecessor_cache<input_type, null_mutex > my_predecessors;
00859
00860 virtual broadcast_cache<output_type > &successors() = 0;
00861
00862 private:
00863 friend class apply_body_task< function_input< input_type, output_type >, input_type >;
00864 friend class forward_task< function_input< input_type, output_type > >;
00865
00866 class my_operation : public aggregated_operation< my_operation > {
00867 public:
00868 char type;
00869 union {
00870 input_type *elem;
00871 predecessor_type *r;
00872 };
00873 my_operation(const input_type& e, op_type t) :
00874 type(char(t)), elem(const_cast<input_type*>(&e)) {}
00875 my_operation(op_type t) : type(char(t)), r(NULL) {}
00876 };
00877
00878 class my_functor_t {
00879 function_input<input_type, output_type> *fi;
00880 public:
00881 my_functor_t() {}
00882 my_functor_t(function_input<input_type, output_type> *fi_) : fi(fi_) {}
00883 void operator()(my_operation* op_list) {
00884 fi->handle_operations(op_list);
00885 }
00886 };
00887
00888 bool forwarder_busy;
00889 aggregator< my_functor_t, my_operation > my_aggregator;
00890
00891 void handle_operations(my_operation *op_list) {
00892 my_operation *tmp;
00893 while (op_list) {
00894 tmp = op_list;
00895 op_list = op_list->next;
00896 switch (tmp->type) {
00897 case reg_pred:
00898 my_predecessors.add(*(tmp->r));
00899 __TBB_store_with_release(tmp->status, SUCCEEDED);
00900 if (!forwarder_busy) {
00901 forwarder_busy = true;
00902 spawn_forward_task();
00903 }
00904 break;
00905 case rem_pred:
00906 my_predecessors.remove(*(tmp->r));
00907 __TBB_store_with_release(tmp->status, SUCCEEDED);
00908 break;
00909 case app_body:
00910 __TBB_ASSERT(my_max_concurrency != 0, NULL);
00911 --my_concurrency;
00912 __TBB_store_with_release(tmp->status, SUCCEEDED);
00913 if (my_concurrency<my_max_concurrency) {
00914 input_type i;
00915 if (my_predecessors.get_item(i)) {
00916 ++my_concurrency;
00917 spawn_body_task(i);
00918 }
00919 }
00920 break;
00921 case tryput: internal_try_put(tmp); break;
00922 case try_fwd: internal_forward(tmp); break;
00923 }
00924 }
00925 }
00926
00927
00929 void internal_try_put(my_operation *op) {
00930 __TBB_ASSERT(my_max_concurrency != 0, NULL);
00931 if (my_concurrency < my_max_concurrency) {
00932 ++my_concurrency;
00933 spawn_body_task(*(op->elem));
00934 __TBB_store_with_release(op->status, SUCCEEDED);
00935 } else {
00936 __TBB_store_with_release(op->status, FAILED);
00937 }
00938 }
00939
00941 void internal_forward(my_operation *op) {
00942 if (my_concurrency<my_max_concurrency || !my_max_concurrency) {
00943 input_type i;
00944 if (my_predecessors.get_item(i)) {
00945 ++my_concurrency;
00946 __TBB_store_with_release(op->status, SUCCEEDED);
00947 spawn_body_task(i);
00948 return;
00949 }
00950 }
00951 __TBB_store_with_release(op->status, FAILED);
00952 forwarder_busy = false;
00953 }
00954
00956 void apply_body( input_type &i ) {
00957 successors().try_put( (*my_body)(i) );
00958 if ( my_max_concurrency != 0 ) {
00959 my_operation op_data(app_body);
00960 my_aggregator.execute(&op_data);
00961 }
00962 }
00963
00965 inline void spawn_body_task( input_type &input ) {
00966 task::enqueue(*new(task::allocate_additional_child_of(*my_root_task)) apply_body_task<function_input<input_type, output_type>, input_type >(*this, input));
00967 }
00968
00970 void forward() {
00971 my_operation op_data(try_fwd);
00972 do {
00973 op_data.status = WAIT;
00974 my_aggregator.execute(&op_data);
00975 } while (op_data.status == SUCCEEDED);
00976 }
00977
00979 inline void spawn_forward_task() {
00980 task::enqueue(*new(task::allocate_additional_child_of(*my_root_task)) forward_task<function_input<input_type, output_type> >(*this));
00981 }
00982 };
00983
00985 template< typename Output >
00986 class continue_input : public continue_receiver {
00987 public:
00988
00990 typedef continue_msg input_type;
00991
00993 typedef Output output_type;
00994
00995 template< typename Body >
00996 continue_input( graph &g, Body& body )
00997 : my_root_task(g.root_task()),
00998 my_body( new internal::function_body_leaf< input_type, output_type, Body>(body) ) { }
00999
01000 template< typename Body >
01001 continue_input( graph &g, int number_of_predecessors, Body& body )
01002 : continue_receiver( number_of_predecessors ), my_root_task(g.root_task()),
01003 my_body( new internal::function_body_leaf< input_type, output_type, Body>(body) ) { }
01004
01005 protected:
01006
01007 task *my_root_task;
01008 function_body<input_type, output_type> *my_body;
01009
01010 virtual broadcast_cache<output_type > &successors() = 0;
01011
01012 friend class apply_body_task< continue_input< Output >, continue_msg >;
01013
01015 void apply_body( input_type ) {
01016 successors().try_put( (*my_body)( continue_msg() ) );
01017 }
01018
01020 void execute( ) {
01021 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
01022 apply_body_task< continue_input< Output >, continue_msg >( *this, continue_msg() ) );
01023 }
01024 };
01025
01027 template< typename Output >
01028 class function_output : public sender<Output> {
01029 public:
01030
01031 typedef Output output_type;
01032
01033 function_output() { }
01034
01036 bool register_successor( receiver<output_type> &r ) {
01037 successors().register_successor( r );
01038 return true;
01039 }
01040
01042 bool remove_successor( receiver<output_type> &r ) {
01043 successors().remove_successor( r );
01044 return true;
01045 }
01046
01047 protected:
01048
01049 virtual broadcast_cache<output_type > &successors() = 0;
01050
01051 };
01052
01053 }
01055
01057 template < typename Output >
01058 class source_node : public graph_node, public sender< Output > {
01059 public:
01060
01062 typedef Output output_type;
01063
01065 typedef receiver< Output > successor_type;
01066
01068 template< typename Body >
01069 source_node( graph &g, Body body, bool is_active = true )
01070 : my_root_task(g.root_task()), my_state( is_active ? internal::node_state_idle : internal::node_state_inactive ),
01071 my_body( new internal::source_body_leaf< output_type, Body>(body) ),
01072 my_reserved(false), my_has_cached_item(false) {
01073 my_successors.set_owner(this);
01074 }
01075
01077 ~source_node() { delete my_body; }
01078
01080 bool register_successor( receiver<output_type> &r ) {
01081 spin_mutex::scoped_lock lock(my_mutex);
01082 my_successors.register_successor(r);
01083 if ( my_state != internal::node_state_inactive )
01084 spawn_put();
01085 return true;
01086 }
01087
01089 bool remove_successor( receiver<output_type> &r ) {
01090 spin_mutex::scoped_lock lock(my_mutex);
01091 my_successors.remove_successor(r);
01092 return true;
01093 }
01094
01096 bool try_get( output_type &v ) {
01097 spin_mutex::scoped_lock lock(my_mutex);
01098 if ( my_reserved )
01099 return false;
01100
01101 if ( my_has_cached_item ) {
01102 v = my_cached_item;
01103 my_has_cached_item = false;
01104 } else if ( (*my_body)(v) == false ) {
01105 return false;
01106 }
01107 return true;
01108 }
01109
01111 bool try_reserve( output_type &v ) {
01112 spin_mutex::scoped_lock lock(my_mutex);
01113 if ( my_reserved ) {
01114 return false;
01115 }
01116
01117 if ( !my_has_cached_item && (*my_body)(my_cached_item) )
01118 my_has_cached_item = true;
01119
01120 if ( my_has_cached_item ) {
01121 v = my_cached_item;
01122 my_reserved = true;
01123 return true;
01124 } else {
01125 return false;
01126 }
01127 }
01128
01130
01131 bool try_release( ) {
01132 spin_mutex::scoped_lock lock(my_mutex);
01133 __TBB_ASSERT( my_reserved && my_has_cached_item, "releasing non-existent reservation" );
01134 my_reserved = false;
01135 spawn_put();
01136 return true;
01137 }
01138
01140 bool try_consume( ) {
01141 spin_mutex::scoped_lock lock(my_mutex);
01142 __TBB_ASSERT( my_reserved && my_has_cached_item, "consuming non-existent reservation" );
01143 my_reserved = false;
01144 my_has_cached_item = false;
01145 if ( !my_successors.empty() ) {
01146 spawn_put();
01147 }
01148 return true;
01149 }
01150
01152 void activate() {
01153 spin_mutex::scoped_lock lock(my_mutex);
01154 my_state = internal::node_state_idle;
01155 if ( !my_successors.empty() )
01156 spawn_put();
01157 }
01158
01159 private:
01160
01161 task *my_root_task;
01162 spin_mutex my_mutex;
01163 internal::node_state my_state;
01164 internal::source_body<output_type> *my_body;
01165 internal::broadcast_cache< output_type > my_successors;
01166 bool my_reserved;
01167 bool my_has_cached_item;
01168 output_type my_cached_item;
01169
01170 friend class internal::source_task< source_node< output_type > >;
01171
01173 void apply_body( ) {
01174 output_type v;
01175 if ( try_reserve(v) == false )
01176 return;
01177
01178 if ( my_successors.try_put( v ) )
01179 try_consume();
01180 else
01181 try_release();
01182 }
01183
01185 void spawn_put( ) {
01186 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
01187 internal::source_task< source_node< output_type > >( *this ) );
01188 }
01189
01190 };
01191
01193 template <typename Input, typename Output = continue_msg >
01194 class function_node : public graph_node, public internal::function_input<Input,Output>, public internal::function_output<Output> {
01195 public:
01196
01197 typedef Input input_type;
01198 typedef Output output_type;
01199 typedef sender< input_type > predecessor_type;
01200 typedef receiver< output_type > successor_type;
01201
01203 template< typename Body >
01204 function_node( graph &g, size_t concurrency, Body body )
01205 : internal::function_input<input_type,output_type>( g, concurrency, body ) {
01206 my_successors.set_owner(this);
01207 }
01208
01209 protected:
01210
01211 internal::broadcast_cache<output_type> my_successors;
01212 internal::broadcast_cache<output_type> &successors () { return my_successors; }
01213
01214 };
01215
01217 template <typename Output>
01218 class executable_node : public graph_node, public internal::continue_input<Output>, public internal::function_output<Output> {
01219 public:
01220
01221 typedef continue_msg input_type;
01222 typedef Output output_type;
01223 typedef sender< input_type > predecessor_type;
01224 typedef receiver< output_type > successor_type;
01225
01227 template <typename Body >
01228 executable_node( graph &g, Body body )
01229 : internal::continue_input<output_type>( g, body ) {
01230 my_successors.set_owner(this);
01231 }
01232
01234 template <typename Body >
01235 executable_node( graph &g, int number_of_predecessors, Body body )
01236 : internal::continue_input<output_type>( g, number_of_predecessors, body ) {
01237 my_successors.set_owner(this);
01238 }
01239
01240 protected:
01241
01242 internal::broadcast_cache<output_type> my_successors;
01243 internal::broadcast_cache<output_type> &successors () { return my_successors; }
01244
01245 };
01246
01247
01248
01249 template< typename T >
01250 class overwrite_node : public graph_node, public receiver<T>, public sender<T>, internal::no_copy {
01251 public:
01252
01253 typedef T input_type;
01254 typedef T output_type;
01255 typedef sender< input_type > predecessor_type;
01256 typedef receiver< output_type > successor_type;
01257
01258 overwrite_node() : my_buffer_is_valid(false) {
01259 my_successors.set_owner( this );
01260 }
01261
01262 ~overwrite_node() {}
01263
01264 bool register_successor( successor_type &s ) {
01265 spin_mutex::scoped_lock l( my_mutex );
01266 if ( my_buffer_is_valid ) {
01267
01268 if ( s.try_put( my_buffer ) || !s.register_predecessor( *this ) ) {
01269
01270 my_successors.register_successor( s );
01271 return true;
01272 } else {
01273
01274 return false;
01275 }
01276 } else {
01277
01278 my_successors.register_successor( s );
01279 return true;
01280 }
01281 }
01282
01283 bool remove_successor( successor_type &s ) {
01284 spin_mutex::scoped_lock l( my_mutex );
01285 my_successors.remove_successor(s);
01286 return true;
01287 }
01288
01289 bool try_put( T v ) {
01290 spin_mutex::scoped_lock l( my_mutex );
01291 my_buffer = v;
01292 my_buffer_is_valid = true;
01293 my_successors.try_put(v);
01294 return true;
01295 }
01296
01297 bool try_get( T &v ) {
01298 spin_mutex::scoped_lock l( my_mutex );
01299 if ( my_buffer_is_valid ) {
01300 v = my_buffer;
01301 return true;
01302 } else {
01303 return false;
01304 }
01305 }
01306
01307 bool is_valid() {
01308 spin_mutex::scoped_lock l( my_mutex );
01309 return my_buffer_is_valid;
01310 }
01311
01312 void clear() {
01313 spin_mutex::scoped_lock l( my_mutex );
01314 my_buffer_is_valid = false;
01315 }
01316
01317 protected:
01318
01319 spin_mutex my_mutex;
01320 internal::broadcast_cache< T, null_rw_mutex > my_successors;
01321 T my_buffer;
01322 bool my_buffer_is_valid;
01323
01324 };
01325
01326 template< typename T >
01327 class write_once_node : public overwrite_node<T> {
01328 public:
01329
01330 typedef T input_type;
01331 typedef T output_type;
01332 typedef sender< input_type > predecessor_type;
01333 typedef receiver< output_type > successor_type;
01334
01335 bool try_put( T v ) {
01336 spin_mutex::scoped_lock l( this->my_mutex );
01337 if ( this->my_buffer_is_valid ) {
01338 return false;
01339 } else {
01340 this->my_buffer = v;
01341 this->my_buffer_is_valid = true;
01342 this->my_successors.try_put(v);
01343 return true;
01344 }
01345 }
01346 };
01347
01349
01350 class continue_node : public executable_node< continue_msg > {
01351 public:
01352
01353 typedef continue_msg input_type;
01354 typedef continue_msg output_type;
01355 typedef sender< input_type > predecessor_type;
01356 typedef receiver< output_type > successor_type;
01357
01358 continue_node( graph &g ) : executable_node<continue_msg>( g, internal::empty_body< continue_msg, continue_msg>() ) {}
01359 };
01360
01362 template <typename T>
01363 class broadcast_node : public graph_node, public receiver<T>, public sender<T>, internal::no_copy {
01364
01365 internal::broadcast_cache<T> my_successors;
01366
01367 public:
01368
01369 typedef T input_type;
01370 typedef T output_type;
01371 typedef sender< input_type > predecessor_type;
01372 typedef receiver< output_type > successor_type;
01373
01374 broadcast_node( ) {
01375 my_successors.set_owner( this );
01376 }
01377
01379 virtual bool register_successor( receiver<T> &r ) {
01380 my_successors.register_successor( r );
01381 return true;
01382 }
01383
01385 virtual bool remove_successor( receiver<T> &r ) {
01386 my_successors.remove_successor( r );
01387 return true;
01388 }
01389
01390 bool try_put( T t ) {
01391 my_successors.try_put(t);
01392 return true;
01393 }
01394
01395 };
01396
01397 #include "_item_buffer.h"
01398
01400 template <typename T>
01401 class buffer_node : public graph_node, public reservable_item_buffer<T>, public receiver<T>, public sender<T>, internal::no_copy {
01402 public:
01403 typedef T input_type;
01404 typedef T output_type;
01405 typedef sender< input_type > predecessor_type;
01406 typedef receiver< output_type > successor_type;
01407 protected:
01408 typedef size_t size_type;
01409 internal::round_robin_cache< T, null_rw_mutex > my_successors;
01410
01411 task *my_parent;
01412
01413 friend class internal::forward_task< buffer_node< T > >;
01414
01415 enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd};
01416 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01417
01418
01419 class buffer_operation : public internal::aggregated_operation< buffer_operation > {
01420 public:
01421 char type;
01422 T *elem;
01423 successor_type *r;
01424 buffer_operation(const T& e, op_type t) :
01425 type(char(t)), elem(const_cast<T*>(&e)), r(NULL) {}
01426 buffer_operation(op_type t) : type(char(t)), r(NULL) {}
01427 };
01428
01429 class my_functor_t {
01430 buffer_node<T> *bfr;
01431 public:
01432 my_functor_t(buffer_node<T> *bfr_) : bfr(bfr_) {}
01433 my_functor_t() {}
01434 void operator()(buffer_operation* op_list) {
01435 bfr->handle_operations(op_list);
01436 }
01437 };
01438
01439 bool forwarder_busy;
01440 internal::aggregator< my_functor_t, buffer_operation> my_aggregator;
01441
01442 virtual void handle_operations(buffer_operation *op_list) {
01443 buffer_operation *tmp;
01444 bool try_forwarding=false;
01445 while (op_list) {
01446 tmp = op_list;
01447 op_list = op_list->next;
01448 switch (tmp->type) {
01449 case reg_succ: internal_reg_succ(tmp); try_forwarding = true; break;
01450 case rem_succ: internal_rem_succ(tmp); break;
01451 case req_item: internal_pop(tmp); break;
01452 case res_item: internal_reserve(tmp); break;
01453 case rel_res: internal_release(tmp); try_forwarding = true; break;
01454 case con_res: internal_consume(tmp); try_forwarding = true; break;
01455 case put_item: internal_push(tmp); try_forwarding = true; break;
01456 case try_fwd: internal_forward(tmp); break;
01457 }
01458 }
01459 if (try_forwarding && !forwarder_busy) {
01460 forwarder_busy = true;
01461 task::enqueue(*new(task::allocate_additional_child_of(*my_parent)) internal::forward_task< buffer_node<input_type> >(*this));
01462 }
01463 }
01464
01466 virtual void forward() {
01467 buffer_operation op_data(try_fwd);
01468 do {
01469 op_data.status = WAIT;
01470 my_aggregator.execute(&op_data);
01471 } while (op_data.status == SUCCEEDED);
01472 }
01473
01475 virtual void internal_reg_succ(buffer_operation *op) {
01476 my_successors.register_successor(*(op->r));
01477 __TBB_store_with_release(op->status, SUCCEEDED);
01478 }
01479
01481 virtual void internal_rem_succ(buffer_operation *op) {
01482 my_successors.remove_successor(*(op->r));
01483 __TBB_store_with_release(op->status, SUCCEEDED);
01484 }
01485
01487 virtual void internal_forward(buffer_operation *op) {
01488 T i_copy;
01489 bool success = false;
01490 size_type counter = my_successors.size();
01491
01492 while (counter>0 && !this->buffer_empty() && this->item_valid(this->my_tail-1)) {
01493 this->fetch_back(i_copy);
01494 if( my_successors.try_put(i_copy) ) {
01495 this->invalidate_back();
01496 --(this->my_tail);
01497 success = true;
01498 }
01499 --counter;
01500 }
01501 if (success && !counter)
01502 __TBB_store_with_release(op->status, SUCCEEDED);
01503 else {
01504 __TBB_store_with_release(op->status, FAILED);
01505 forwarder_busy = false;
01506 }
01507 }
01508
01509 virtual void internal_push(buffer_operation *op) {
01510 this->push_back(*(op->elem));
01511 __TBB_store_with_release(op->status, SUCCEEDED);
01512 }
01513
01514 virtual void internal_pop(buffer_operation *op) {
01515 if(this->pop_back(*(op->elem))) {
01516 __TBB_store_with_release(op->status, SUCCEEDED);
01517 }
01518 else {
01519 __TBB_store_with_release(op->status, FAILED);
01520 }
01521 }
01522
01523 virtual void internal_reserve(buffer_operation *op) {
01524 if(this->reserve_front(*(op->elem))) {
01525 __TBB_store_with_release(op->status, SUCCEEDED);
01526 }
01527 else {
01528 __TBB_store_with_release(op->status, FAILED);
01529 }
01530 }
01531
01532 virtual void internal_consume(buffer_operation *op) {
01533 this->consume_front();
01534 __TBB_store_with_release(op->status, SUCCEEDED);
01535 }
01536
01537 virtual void internal_release(buffer_operation *op) {
01538 this->release_front();
01539 __TBB_store_with_release(op->status, SUCCEEDED);
01540 }
01541
01542 public:
01544 buffer_node( graph &g ) : reservable_item_buffer<T>(),
01545 my_parent( g.root_task() ), forwarder_busy(false) {
01546 my_successors.set_owner(this);
01547 my_aggregator.initialize_handler(my_functor_t(this));
01548 }
01549
01550 virtual ~buffer_node() {}
01551
01552
01553
01554
01555
01557
01558 bool register_successor( receiver<output_type> &r ) {
01559 buffer_operation op_data(reg_succ);
01560 op_data.r = &r;
01561 my_aggregator.execute(&op_data);
01562 return true;
01563 }
01564
01566
01568 bool remove_successor( receiver<output_type> &r ) {
01569 r.remove_predecessor(*this);
01570 buffer_operation op_data(rem_succ);
01571 op_data.r = &r;
01572 my_aggregator.execute(&op_data);
01573 return true;
01574 }
01575
01577
01579 bool try_get( T &v ) {
01580 buffer_operation op_data(req_item);
01581 op_data.elem = &v;
01582 my_aggregator.execute(&op_data);
01583 return (op_data.status==SUCCEEDED);
01584 }
01585
01587
01589 bool try_reserve( T &v ) {
01590 buffer_operation op_data(res_item);
01591 op_data.elem = &v;
01592 my_aggregator.execute(&op_data);
01593 return (op_data.status==SUCCEEDED);
01594 }
01595
01597
01598 bool try_release() {
01599 buffer_operation op_data(rel_res);
01600 my_aggregator.execute(&op_data);
01601 return true;
01602 }
01603
01605
01606 bool try_consume() {
01607 buffer_operation op_data(con_res);
01608 my_aggregator.execute(&op_data);
01609 return true;
01610 }
01611
01613
01614 bool try_put(T t) {
01615 buffer_operation op_data(t, put_item);
01616 my_aggregator.execute(&op_data);
01617 return true;
01618 }
01619 };
01620
01621
01623 template <typename T>
01624 class queue_node : public buffer_node<T> {
01625 protected:
01626 typedef typename buffer_node<T>::size_type size_type;
01627 typedef typename buffer_node<T>::buffer_operation queue_operation;
01628
01629 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01630
01632 void internal_forward(queue_operation *op) {
01633 T i_copy;
01634 bool success = false;
01635 size_type counter = this->my_successors.size();
01636 if (this->my_reserved || !this->item_valid(this->my_head)){
01637 __TBB_store_with_release(op->status, FAILED);
01638 this->forwarder_busy = false;
01639 return;
01640 }
01641
01642 while (counter>0 && this->item_valid(this->my_head)) {
01643 this->fetch_front(i_copy);
01644 if(this->my_successors.try_put(i_copy)) {
01645 this->invalidate_front();
01646 ++(this->my_head);
01647 success = true;
01648 }
01649 --counter;
01650 }
01651 if (success && !counter)
01652 __TBB_store_with_release(op->status, SUCCEEDED);
01653 else {
01654 __TBB_store_with_release(op->status, FAILED);
01655 this->forwarder_busy = false;
01656 }
01657 }
01658
01659 void internal_pop(queue_operation *op) {
01660 if ( this->my_reserved || !this->item_valid(this->my_head)){
01661 __TBB_store_with_release(op->status, FAILED);
01662 }
01663 else {
01664 this->pop_front(*(op->elem));
01665 __TBB_store_with_release(op->status, SUCCEEDED);
01666 }
01667 }
01668 void internal_reserve(queue_operation *op) {
01669 if (this->my_reserved || !this->item_valid(this->my_head)) {
01670 __TBB_store_with_release(op->status, FAILED);
01671 }
01672 else {
01673 this->my_reserved = true;
01674 this->fetch_front(*(op->elem));
01675 this->invalidate_front();
01676 __TBB_store_with_release(op->status, SUCCEEDED);
01677 }
01678 }
01679 void internal_consume(queue_operation *op) {
01680 this->consume_front();
01681 __TBB_store_with_release(op->status, SUCCEEDED);
01682 }
01683
01684 public:
01685
01686 typedef T input_type;
01687 typedef T output_type;
01688 typedef sender< input_type > predecessor_type;
01689 typedef receiver< output_type > successor_type;
01690
01692 queue_node( graph &g ) : buffer_node<T>(g) {}
01693 };
01694
01696 template< typename T >
01697 class sequencer_node : public queue_node<T> {
01698 internal::function_body< T, size_t > *my_sequencer;
01699 public:
01700
01701 typedef T input_type;
01702 typedef T output_type;
01703 typedef sender< input_type > predecessor_type;
01704 typedef receiver< output_type > successor_type;
01705
01707 template< typename Sequencer >
01708 sequencer_node( graph &g, const Sequencer& s ) : queue_node<T>(g),
01709 my_sequencer(new internal::function_body_leaf< T, size_t, Sequencer>(s) ) {}
01710
01712 ~sequencer_node() { delete my_sequencer; }
01713 protected:
01714 typedef typename buffer_node<T>::size_type size_type;
01715 typedef typename buffer_node<T>::buffer_operation sequencer_operation;
01716
01717 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01718
01719 private:
01720 void internal_push(sequencer_operation *op) {
01721 size_type tag = (*my_sequencer)(*(op->elem));
01722
01723 this->my_tail = (tag+1 > this->my_tail) ? tag+1 : this->my_tail;
01724
01725 if(this->size() > this->capacity())
01726 this->grow_my_array(this->size());
01727 this->item(tag) = std::make_pair( *(op->elem), true );
01728 __TBB_store_with_release(op->status, SUCCEEDED);
01729 }
01730 };
01731
01733 template< typename T, typename Compare = std::less<T> >
01734 class priority_queue_node : public buffer_node<T> {
01735 public:
01736 typedef T input_type;
01737 typedef T output_type;
01738 typedef sender< input_type > predecessor_type;
01739 typedef receiver< output_type > successor_type;
01740
01742 priority_queue_node( graph &g ) : buffer_node<T>(g), mark(0) {}
01743
01744 protected:
01745 typedef typename buffer_node<T>::size_type size_type;
01746 typedef typename buffer_node<T>::item_type item_type;
01747 typedef typename buffer_node<T>::buffer_operation prio_operation;
01748
01749 enum op_stat {WAIT=0, SUCCEEDED, FAILED};
01750
01751 void handle_operations(prio_operation *op_list) {
01752 prio_operation *tmp ;
01753 bool try_forwarding=false;
01754 while (op_list) {
01755 tmp = op_list;
01756 op_list = op_list->next;
01757 switch (tmp->type) {
01758 case buffer_node<T>::reg_succ: this->internal_reg_succ(tmp); try_forwarding = true; break;
01759 case buffer_node<T>::rem_succ: this->internal_rem_succ(tmp); break;
01760 case buffer_node<T>::put_item: internal_push(tmp); try_forwarding = true; break;
01761 case buffer_node<T>::try_fwd: internal_forward(tmp); break;
01762 case buffer_node<T>::rel_res: internal_release(tmp); try_forwarding = true; break;
01763 case buffer_node<T>::con_res: internal_consume(tmp); try_forwarding = true; break;
01764 case buffer_node<T>::req_item: internal_pop(tmp); break;
01765 case buffer_node<T>::res_item: internal_reserve(tmp); break;
01766 }
01767 }
01768
01769 if (mark<this->my_tail) heapify();
01770 if (try_forwarding && !this->forwarder_busy) {
01771 this->forwarder_busy = true;
01772 task::enqueue(*new(task::allocate_additional_child_of(*(this->my_parent))) internal::forward_task< buffer_node<input_type> >(*this));
01773 }
01774 }
01775
01777 void internal_forward(prio_operation *op) {
01778 T i_copy;
01779 bool success = false;
01780 size_type counter = this->my_successors.size();
01781
01782 if (this->my_reserved || this->my_tail == 0) {
01783 __TBB_store_with_release(op->status, FAILED);
01784 this->forwarder_busy = false;
01785 return;
01786 }
01787
01788 while (counter>0 && this->my_tail > 0) {
01789 i_copy = this->my_array[0].first;
01790 bool msg = this->my_successors.try_put(i_copy);
01791 if ( msg == true ) {
01792 if (mark == this->my_tail) --mark;
01793 --(this->my_tail);
01794 this->my_array[0].first=this->my_array[this->my_tail].first;
01795 if (this->my_tail > 1)
01796 reheap();
01797 success = true;
01798 }
01799 --counter;
01800 }
01801 if (success && !counter)
01802 __TBB_store_with_release(op->status, SUCCEEDED);
01803 else {
01804 __TBB_store_with_release(op->status, FAILED);
01805 this->forwarder_busy = false;
01806 }
01807 }
01808
01809 void internal_push(prio_operation *op) {
01810 if ( this->my_tail >= this->my_array_size )
01811 this->grow_my_array( this->my_tail + 1 );
01812 this->my_array[this->my_tail] = std::make_pair( *(op->elem), true );
01813 ++(this->my_tail);
01814 __TBB_store_with_release(op->status, SUCCEEDED);
01815 }
01816 void internal_pop(prio_operation *op) {
01817 if ( this->my_reserved == true || this->my_tail == 0 ) {
01818 __TBB_store_with_release(op->status, FAILED);
01819 }
01820 else {
01821 if (mark<this->my_tail &&
01822 compare(this->my_array[0].first,
01823 this->my_array[this->my_tail-1].first)) {
01824
01825
01826 *(op->elem) = this->my_array[this->my_tail-1].first;
01827 --(this->my_tail);
01828 __TBB_store_with_release(op->status, SUCCEEDED);
01829 }
01830 else {
01831 *(op->elem) = this->my_array[0].first;
01832 if (mark == this->my_tail) --mark;
01833 --(this->my_tail);
01834 __TBB_store_with_release(op->status, SUCCEEDED);
01835 this->my_array[0].first=this->my_array[this->my_tail].first;
01836 if (this->my_tail > 1)
01837 reheap();
01838 }
01839 }
01840 }
01841 void internal_reserve(prio_operation *op) {
01842 if (this->my_reserved == true || this->my_tail == 0) {
01843 __TBB_store_with_release(op->status, FAILED);
01844 }
01845 else {
01846 this->my_reserved = true;
01847 *(op->elem) = reserved_item = this->my_array[0].first;
01848 if (mark == this->my_tail) --mark;
01849 --(this->my_tail);
01850 __TBB_store_with_release(op->status, SUCCEEDED);
01851 this->my_array[0].first = this->my_array[this->my_tail].first;
01852 if (this->my_tail > 1)
01853 reheap();
01854 }
01855 }
01856 void internal_consume(prio_operation *op) {
01857 this->my_reserved = false;
01858 __TBB_store_with_release(op->status, SUCCEEDED);
01859 }
01860 void internal_release(prio_operation *op) {
01861 if (this->my_tail >= this->my_array_size)
01862 this->grow_my_array( this->my_tail + 1 );
01863 this->my_array[this->my_tail] = std::make_pair(reserved_item, true);
01864 ++(this->my_tail);
01865 this->my_reserved = false;
01866 __TBB_store_with_release(op->status, SUCCEEDED);
01867 heapify();
01868 }
01869 private:
01870 Compare compare;
01871 size_type mark;
01872 input_type reserved_item;
01873
01874 void heapify() {
01875 if (!mark) mark = 1;
01876 for (; mark<this->my_tail; ++mark) {
01877 size_type cur_pos = mark;
01878 input_type to_place = this->my_array[mark].first;
01879 do {
01880 size_type parent = (cur_pos-1)>>1;
01881 if (!compare(this->my_array[parent].first, to_place))
01882 break;
01883 this->my_array[cur_pos].first = this->my_array[parent].first;
01884 cur_pos = parent;
01885 } while( cur_pos );
01886 this->my_array[cur_pos].first = to_place;
01887 }
01888 }
01889
01890 void reheap() {
01891 size_type cur_pos=0, child=1;
01892 while (child < mark) {
01893 size_type target = child;
01894 if (child+1<mark &&
01895 compare(this->my_array[child].first,
01896 this->my_array[child+1].first))
01897 ++target;
01898
01899 if (compare(this->my_array[target].first,
01900 this->my_array[this->my_tail].first))
01901 break;
01902 this->my_array[cur_pos].first = this->my_array[target].first;
01903 cur_pos = target;
01904 child = (cur_pos<<1)+1;
01905 }
01906 this->my_array[cur_pos].first = this->my_array[this->my_tail].first;
01907 }
01908 };
01909
01911
01914 template< typename T >
01915 class limiter_node : public graph_node, public receiver< T >, public sender< T >, internal::no_copy {
01916 public:
01917
01918 typedef T input_type;
01919 typedef T output_type;
01920 typedef sender< input_type > predecessor_type;
01921 typedef receiver< output_type > successor_type;
01922
01923 private:
01924
01925 task *my_root_task;
01926 size_t my_threshold;
01927 size_t my_count;
01928 internal::predecessor_cache< T > my_predecessors;
01929 spin_mutex my_mutex;
01930 internal::broadcast_cache< T > my_successors;
01931
01932 friend class internal::forward_task< limiter_node<T> >;
01933
01934
01935 friend class internal::decrementer< limiter_node<T> >;
01936
01937 void decrement_counter() {
01938 input_type v;
01939
01940
01941 if ( my_predecessors.get_item( v ) == false
01942 || my_successors.try_put(v) == false ) {
01943 spin_mutex::scoped_lock lock(my_mutex);
01944 --my_count;
01945 if ( !my_predecessors.empty() )
01946 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
01947 internal::forward_task< limiter_node<T> >( *this ) );
01948 }
01949 }
01950
01951 void forward() {
01952 {
01953 spin_mutex::scoped_lock lock(my_mutex);
01954 if ( my_count < my_threshold )
01955 ++my_count;
01956 else
01957 return;
01958 }
01959 decrement_counter();
01960 }
01961
01962 public:
01963
01965 internal::decrementer< limiter_node<T> > decrement;
01966
01968 limiter_node( graph &g, size_t threshold, int number_of_decrement_predecessors = 0 ) :
01969 my_root_task(g.root_task()), my_threshold(threshold), my_count(0), decrement(number_of_decrement_predecessors) {
01970 my_predecessors.set_owner(this);
01971 my_successors.set_owner(this);
01972 decrement.set_owner(this);
01973 }
01974
01976 bool register_successor( receiver<output_type> &r ) {
01977 my_successors.register_successor(r);
01978 return true;
01979 }
01980
01982
01983 bool remove_successor( receiver<output_type> &r ) {
01984 r.remove_predecessor(*this);
01985 my_successors.remove_successor(r);
01986 return true;
01987 }
01988
01990 bool try_put( T t ) {
01991 {
01992 spin_mutex::scoped_lock lock(my_mutex);
01993 if ( my_count >= my_threshold )
01994 return false;
01995 else
01996 ++my_count;
01997 }
01998
01999 bool msg = my_successors.try_put(t);
02000
02001 if ( msg != true ) {
02002 spin_mutex::scoped_lock lock(my_mutex);
02003 --my_count;
02004 if ( !my_predecessors.empty() )
02005 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
02006 internal::forward_task< limiter_node<T> >( *this ) );
02007 }
02008
02009 return msg;
02010 }
02011
02013 bool register_predecessor( predecessor_type &src ) {
02014 spin_mutex::scoped_lock lock(my_mutex);
02015 my_predecessors.add( src );
02016 if ( my_count < my_threshold && !my_successors.empty() )
02017 task::enqueue( * new ( task::allocate_additional_child_of( *my_root_task ) )
02018 internal::forward_task< limiter_node<T> >( *this ) );
02019 return true;
02020 }
02021
02023 bool remove_predecessor( predecessor_type &src ) {
02024 my_predecessors.remove( src );
02025 return true;
02026 }
02027
02028 };
02029
02030 namespace internal {
02031
02032 struct forwarding_base {
02033 forwarding_base(task *rt) : my_root_task(rt) {}
02034 virtual ~forwarding_base() {}
02035 virtual void decrement_port_count() = 0;
02036 virtual void increment_port_count() = 0;
02037
02038 task* my_root_task;
02039 };
02040
02041 template< int N >
02042 struct join_helper {
02043
02044 template< typename TupleType, typename PortType >
02045 static inline void set_join_node_pointer(TupleType &my_input, PortType *port) {
02046 std::get<N-1>( my_input ).set_join_node_pointer(port);
02047 join_helper<N-1>::set_join_node_pointer( my_input, port );
02048 }
02049 template< typename TupleType >
02050 static inline void consume_reservations( TupleType &my_input ) {
02051 std::get<N-1>( my_input ).consume();
02052 join_helper<N-1>::consume_reservations( my_input );
02053 }
02054
02055 template< typename TupleType >
02056 static inline void release_my_reservation( TupleType &my_input ) {
02057 std::get<N-1>( my_input ).release();
02058 }
02059
02060 template <typename TupleType>
02061 static inline void release_reservations( TupleType &my_input) {
02062 join_helper<N-1>::release_reservations(my_input);
02063 release_my_reservation(my_input);
02064 }
02065
02066 template< typename InputTuple, typename OutputTuple >
02067 static inline bool reserve( InputTuple &my_input, OutputTuple &out) {
02068 if ( !std::get<N-1>( my_input ).reserve( std::get<N-1>( out ) ) ) return false;
02069 if ( !join_helper<N-1>::reserve( my_input, out ) ) {
02070 release_my_reservation( my_input );
02071 return false;
02072 }
02073 return true;
02074 }
02075
02076 template<typename InputTuple, typename OutputTuple>
02077 static inline bool get_my_item( InputTuple &my_input, OutputTuple &out) {
02078 bool res = std::get<N-1>(my_input).get_item(std::get<N-1>(out) );
02079 return join_helper<N-1>::get_my_item(my_input, out) && res;
02080 }
02081
02082 template<typename InputTuple, typename OutputTuple>
02083 static inline bool get_items(InputTuple &my_input, OutputTuple &out) {
02084 return get_my_item(my_input, out);
02085 }
02086
02087 template<typename InputTuple>
02088 static inline void reset_my_port(InputTuple &my_input) {
02089 join_helper<N-1>::reset_my_port(my_input);
02090 std::get<N-1>(my_input).reset_port();
02091 }
02092
02093 template<typename InputTuple>
02094 static inline void reset_ports(InputTuple& my_input) {
02095 reset_my_port(my_input);
02096 }
02097 };
02098
02099 template< >
02100 struct join_helper<1> {
02101
02102 template< typename TupleType, typename PortType >
02103 static inline void set_join_node_pointer(TupleType &my_input, PortType *port) {
02104 std::get<0>( my_input ).set_join_node_pointer(port);
02105 }
02106
02107 template< typename TupleType >
02108 static inline void consume_reservations( TupleType &my_input ) {
02109 std::get<0>( my_input ).consume();
02110 }
02111
02112 template< typename TupleType >
02113 static inline void release_my_reservation( TupleType &my_input ) {
02114 std::get<0>( my_input ).release();
02115 }
02116
02117 template<typename TupleType>
02118 static inline void release_reservations( TupleType &my_input) {
02119 release_my_reservation(my_input);
02120 }
02121
02122 template< typename InputTuple, typename OutputTuple >
02123 static inline bool reserve( InputTuple &my_input, OutputTuple &out) {
02124 return std::get<0>( my_input ).reserve( std::get<0>( out ) );
02125 }
02126
02127 template<typename InputTuple, typename OutputTuple>
02128 static inline bool get_my_item( InputTuple &my_input, OutputTuple &out) {
02129 return std::get<0>(my_input).get_item(std::get<0>(out));
02130 }
02131
02132 template<typename InputTuple, typename OutputTuple>
02133 static inline bool get_items(InputTuple &my_input, OutputTuple &out) {
02134 return get_my_item(my_input, out);
02135 }
02136
02137 template<typename InputTuple>
02138 static inline void reset_my_port(InputTuple &my_input) {
02139 std::get<0>(my_input).reset_port();
02140 }
02141
02142 template<typename InputTuple>
02143 static inline void reset_ports(InputTuple& my_input) {
02144 reset_my_port(my_input);
02145 }
02146 };
02147
02148 namespace join_policy_namespace {
02149 enum join_policy { reserving
02150 , queueing
02151 };
02152 }
02153 using namespace join_policy_namespace;
02154
02156 template< typename T >
02157 class reserving_port : public receiver<T> {
02158 public:
02159 typedef T input_type;
02160 typedef sender<T> predecessor_type;
02161
02163 reserving_port() : reserved(false) {
02164 my_join = NULL;
02165 my_predecessors.set_owner( this );
02166 }
02167
02168
02169 reserving_port(const reserving_port& ) : receiver<T>() {
02170 reserved = false;
02171 my_join = NULL;
02172 my_predecessors.set_owner( this );
02173 }
02174
02175 void set_join_node_pointer(forwarding_base *join) {
02176 my_join = join;
02177 }
02178
02179
02180 bool try_put( T ) {
02181 return false;
02182 }
02183
02185 bool register_predecessor( sender<T> &src ) {
02186 spin_mutex::scoped_lock l(my_mutex);
02187 bool no_predecessors = my_predecessors.empty();
02188 my_predecessors.add(src);
02189 if ( no_predecessors ) {
02190 my_join->decrement_port_count( );
02191 }
02192 return true;
02193 }
02194
02196 bool remove_predecessor( sender<T> &src ) {
02197 spin_mutex::scoped_lock l(my_mutex);
02198 my_predecessors.remove( src );
02199 if(my_predecessors.empty()) my_join->increment_port_count();
02200 return true;
02201 }
02202
02204 bool reserve( T &v ) {
02205 spin_mutex::scoped_lock l(my_mutex);
02206 if ( reserved ) {
02207 return false;
02208 }
02209 if ( my_predecessors.try_reserve( v ) ) {
02210 reserved = true;
02211 return true;
02212 } else if ( my_predecessors.empty() ) {
02213 my_join->increment_port_count();
02214 }
02215 return false;
02216 }
02217
02219 void release( ) {
02220 spin_mutex::scoped_lock l(my_mutex);
02221 reserved = false;
02222 my_predecessors.try_release( );
02223 }
02224
02226 void consume( ) {
02227 spin_mutex::scoped_lock l(my_mutex);
02228 reserved = false;
02229 my_predecessors.try_consume( );
02230 }
02231
02232 private:
02233 spin_mutex my_mutex;
02234 forwarding_base *my_join;
02235 reservable_predecessor_cache< T > my_predecessors;
02236 bool reserved;
02237 };
02238
02240 template<typename T>
02241 class queueing_port : public receiver<T>, public item_buffer<T> {
02242 public:
02243 typedef T input_type;
02244 typedef sender<T> predecessor_type;
02245 typedef queueing_port<T> my_node_type;
02246
02248 queueing_port() : item_buffer<T>() {
02249 my_join = NULL;
02250 my_predecessors.set_owner( this );
02251 }
02252
02254 queueing_port(const queueing_port& ) : receiver<T>(), item_buffer<T>() {
02255 my_join = NULL;
02256 my_predecessors.set_owner( this );
02257 }
02258
02260 void set_join_node_pointer(forwarding_base *join) {
02261 my_join = join;
02262 }
02263
02264 bool try_put(T v) {
02265 spin_mutex::scoped_lock l(my_mutex);
02266 bool was_empty = this->buffer_empty();
02267 this->push_back(v);
02268 if (was_empty) my_join->decrement_port_count();
02269 return true;
02270 }
02271
02272
02273
02274
02275
02276 void forward() {
02277 spin_mutex::scoped_lock l(my_mutex);
02278 while(!my_predecessors.empty()) {
02279 T my_item;
02280 bool have_item = my_predecessors.get_item(my_item);
02281 if(have_item) {
02282 bool was_empty = this->buffer_empty();
02283 this->push_back(my_item);
02284 if(was_empty) my_join->decrement_port_count();
02285 }
02286 else {
02287 return;
02288 }
02289 }
02290 }
02291
02293 bool register_predecessor( sender<T> &src ) {
02294 spin_mutex::scoped_lock l(my_mutex);
02295 my_predecessors.add(src);
02296 task::enqueue( * new ( task::allocate_additional_child_of( *(my_join->my_root_task) ) )
02297 forward_task<my_node_type>(*this) );
02298 return true;
02299 }
02300
02302 bool remove_predecessor( sender<T> &src ) {
02303 spin_mutex::scoped_lock l(my_mutex);
02304 my_predecessors.remove( src );
02305 return true;
02306 }
02307
02308 bool get_item( T &v ) {
02309 spin_mutex::scoped_lock l(my_mutex);
02310 if(!this->buffer_empty()) {
02311 this->fetch_front(v);
02312 return true;
02313 }
02314 if(my_predecessors.get_item( v ) ) {
02315 this->push_back(v);
02316
02317 my_join->decrement_port_count();
02318 return true;
02319 }
02320 return false;
02321 }
02322
02323
02324
02325
02326 void reset_port() {
02327 spin_mutex::scoped_lock l(my_mutex);
02328 __TBB_ASSERT(this->item_valid(this->my_head), "No item to reset");
02329 this->invalidate_front(); ++(this->my_head);
02330 if(this->item_valid(this->my_head)) {
02331 my_join->decrement_port_count();
02332 }
02333 }
02334
02335 private:
02336 spin_mutex my_mutex;
02337 forwarding_base *my_join;
02338 predecessor_cache<T> my_predecessors;
02339 };
02340
02341 template<join_policy JP, typename InputTuple, typename OutputTuple>
02342 class join_node_base;
02343
02345 template<join_policy JP, typename InputTuple, typename OutputTuple>
02346 class join_node_FE;
02347
02348 template<typename InputTuple, typename OutputTuple>
02349 class join_node_FE<reserving, InputTuple, OutputTuple> : public forwarding_base {
02350 public:
02351 static const int N = std::tuple_size<OutputTuple>::value;
02352 typedef OutputTuple output_type;
02353 typedef InputTuple input_type;
02354 typedef join_node_base<reserving, InputTuple, OutputTuple> my_node_type;
02355
02356 join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NULL) {
02357 ports_with_no_inputs = N;
02358 join_helper<N>::set_join_node_pointer(my_inputs, this);
02359 }
02360
02361 void set_my_node(my_node_type *new_my_node) { my_node = new_my_node; }
02362
02363 void increment_port_count() {
02364 ++ports_with_no_inputs;
02365 }
02366
02367
02368 void decrement_port_count() {
02369 if(ports_with_no_inputs.fetch_and_decrement() == 1) {
02370 task::enqueue( * new ( task::allocate_additional_child_of( *(this->my_root_task) ) )
02371 forward_task<my_node_type>(*my_node) );
02372 }
02373 }
02374
02375 input_type &inputs() { return my_inputs; }
02376 protected:
02377
02378
02379 bool tuple_build_may_succeed() {
02380 return !ports_with_no_inputs;
02381 }
02382
02383 bool try_to_make_tuple(output_type &out) {
02384 if(ports_with_no_inputs) return false;
02385 return join_helper<N>::reserve(my_inputs, out);
02386 }
02387
02388 void tuple_accepted() {
02389 join_helper<N>::consume_reservations(my_inputs);
02390 }
02391 void tuple_rejected() {
02392 join_helper<N>::release_reservations(my_inputs);
02393 }
02394
02395 input_type my_inputs;
02396 my_node_type *my_node;
02397 atomic<size_t> ports_with_no_inputs;
02398 };
02399
02400 template<typename InputTuple, typename OutputTuple>
02401 class join_node_FE<queueing, InputTuple, OutputTuple> : public forwarding_base {
02402 public:
02403 static const int N = std::tuple_size<OutputTuple>::value;
02404 typedef OutputTuple output_type;
02405 typedef InputTuple input_type;
02406 typedef join_node_base<queueing, InputTuple, OutputTuple> my_node_type;
02407
02408 join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NULL) {
02409 ports_with_no_items = N;
02410 join_helper<N>::set_join_node_pointer(my_inputs, this);
02411 }
02412
02413
02414 void set_my_node(my_node_type *new_my_node) { my_node = new_my_node; }
02415
02416 void reset_port_count() {
02417 ports_with_no_items = N;
02418 }
02419
02420
02421 void decrement_port_count() {
02422 if(ports_with_no_items.fetch_and_decrement() == 1) {
02423 task::enqueue( * new ( task::allocate_additional_child_of( *(this->my_root_task) ) )
02424 forward_task<my_node_type>(*my_node) );
02425 }
02426 }
02427
02428 void increment_port_count() { __TBB_ASSERT(false, NULL); }
02429
02430 input_type &inputs() { return my_inputs; }
02431 protected:
02432
02433
02434 bool tuple_build_may_succeed() {
02435 return !ports_with_no_items;
02436 }
02437
02438 bool try_to_make_tuple(output_type &out) {
02439 if(ports_with_no_items) return false;
02440 return join_helper<N>::get_items(my_inputs, out);
02441 }
02442
02443 void tuple_accepted() {
02444 reset_port_count();
02445 join_helper<N>::reset_ports(my_inputs);
02446 }
02447 void tuple_rejected() {
02448
02449 }
02450
02451 input_type my_inputs;
02452 my_node_type *my_node;
02453 atomic<size_t> ports_with_no_items;
02454 };
02455
02457 template<join_policy JP, typename InputTuple, typename OutputTuple>
02458 class join_node_base : public graph_node, public join_node_FE<JP, InputTuple, OutputTuple>,
02459 public sender<OutputTuple>, no_copy {
02460 public:
02461 typedef OutputTuple output_type;
02462
02463 typedef receiver<output_type> successor_type;
02464 typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type;
02465 using input_ports_type::tuple_build_may_succeed;
02466 using input_ports_type::try_to_make_tuple;
02467 using input_ports_type::tuple_accepted;
02468 using input_ports_type::tuple_rejected;
02469
02470 join_node_base(graph &g) : input_ports_type(g) {
02471 my_successors.set_owner(this);
02472 input_ports_type::set_my_node(this);
02473 }
02474
02475 bool register_successor(successor_type &r) {
02476 spin_mutex::scoped_lock l(my_mutex);
02477 my_successors.register_successor(r);
02478 if(tuple_build_may_succeed()) {
02479 task::enqueue( * new ( task::allocate_additional_child_of( *(this->my_root_task)) )
02480 forward_task<join_node_base<JP,InputTuple,OutputTuple> >( *this ) );
02481 }
02482 return true;
02483 }
02484
02485 bool remove_successor( successor_type &r) {
02486 spin_mutex::scoped_lock l(my_mutex);
02487 my_successors.remove_successor(r);
02488 return true;
02489 }
02490
02491 bool try_get( output_type &v) {
02492 spin_mutex::scoped_lock l(my_mutex);
02493 if(tuple_build_may_succeed()) {
02494 if(try_to_make_tuple(v)) {
02495
02496 tuple_accepted();
02497 return true;
02498 }
02499 }
02500 return false;
02501 }
02502
02503 private:
02504 broadcast_cache<output_type, null_rw_mutex> my_successors;
02505 spin_mutex my_mutex;
02506
02507 friend class forward_task< join_node_base<JP, InputTuple, OutputTuple> >;
02508
02509 void forward() {
02510 spin_mutex::scoped_lock l(my_mutex);
02511 output_type out;
02512 if(!tuple_build_may_succeed()) return;
02513 while(try_to_make_tuple(out)) {
02514 if(my_successors.try_put(out)) {
02515 tuple_accepted();
02516 }
02517 else {
02518 tuple_rejected();
02519 return;
02520 }
02521 }
02522 }
02523 };
02524
02526
02527 template<int N, typename OutputTuple, join_policy JP>
02528 class unfolded_join_node;
02529
02530 template<typename OutputTuple>
02531 class unfolded_join_node<2,OutputTuple,reserving> : public internal::join_node_base<reserving,
02532 std::tuple<
02533 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02534 reserving_port<typename std::tuple_element<1,OutputTuple>::type> >,
02535 OutputTuple
02536 >
02537 {
02538 public:
02539 typedef typename std::tuple<
02540 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02541 reserving_port<typename std::tuple_element<1,OutputTuple>::type> > input_ports_tuple_type;
02542 typedef OutputTuple output_type;
02543 private:
02544 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02545 public:
02546 unfolded_join_node(graph &g) : base_type(g) {}
02547 };
02548
02549 template<typename OutputTuple>
02550 class unfolded_join_node<3,OutputTuple,reserving> : public internal::join_node_base<reserving,
02551 std::tuple<
02552 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02553 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02554 reserving_port<typename std::tuple_element<2,OutputTuple>::type> >,
02555 OutputTuple
02556 >
02557 {
02558 public:
02559 typedef typename std::tuple<
02560 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02561 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02562 reserving_port<typename std::tuple_element<2,OutputTuple>::type> > input_ports_tuple_type;
02563 typedef OutputTuple output_type;
02564 private:
02565 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02566 public:
02567 unfolded_join_node(graph &g) : base_type(g) {}
02568 };
02569
02570 template<typename OutputTuple>
02571 class unfolded_join_node<4,OutputTuple,reserving> : public internal::join_node_base<reserving,
02572 std::tuple<
02573 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02574 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02575 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02576 reserving_port<typename std::tuple_element<3,OutputTuple>::type> >,
02577 OutputTuple
02578 > {
02579 public:
02580 typedef typename std::tuple<
02581 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02582 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02583 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02584 reserving_port<typename std::tuple_element<3,OutputTuple>::type> > input_ports_tuple_type;
02585 typedef OutputTuple output_type;
02586 private:
02587 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02588 public:
02589 unfolded_join_node(graph &g) : base_type(g) {}
02590 };
02591
02592 template<typename OutputTuple>
02593 class unfolded_join_node<5,OutputTuple,reserving> : public internal::join_node_base<reserving,
02594 std::tuple<
02595 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02596 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02597 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02598 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02599 reserving_port<typename std::tuple_element<4,OutputTuple>::type> >,
02600 OutputTuple
02601 > {
02602 public:
02603 typedef typename std::tuple<
02604 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02605 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02606 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02607 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02608 reserving_port<typename std::tuple_element<4,OutputTuple>::type> > input_ports_tuple_type;
02609 typedef OutputTuple output_type;
02610 private:
02611 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02612 public:
02613 unfolded_join_node(graph &g) : base_type(g) {}
02614 };
02615
02616 template<typename OutputTuple>
02617 class unfolded_join_node<6,OutputTuple,reserving> : public internal::join_node_base<reserving,
02618 std::tuple<
02619 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02620 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02621 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02622 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02623 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02624 reserving_port<typename std::tuple_element<5,OutputTuple>::type> >,
02625 OutputTuple
02626 > {
02627 public:
02628 typedef typename std::tuple<
02629 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02630 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02631 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02632 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02633 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02634 reserving_port<typename std::tuple_element<5,OutputTuple>::type> > input_ports_tuple_type;
02635 typedef OutputTuple output_type;
02636 private:
02637 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02638 public:
02639 unfolded_join_node(graph &g) : base_type(g) {}
02640 };
02641
02642 template<typename OutputTuple>
02643 class unfolded_join_node<7,OutputTuple,reserving> : public internal::join_node_base<reserving,
02644 std::tuple<
02645 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02646 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02647 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02648 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02649 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02650 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02651 reserving_port<typename std::tuple_element<6,OutputTuple>::type> >,
02652 OutputTuple
02653 > {
02654 public:
02655 typedef typename std::tuple<
02656 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02657 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02658 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02659 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02660 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02661 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02662 reserving_port<typename std::tuple_element<6,OutputTuple>::type> > input_ports_tuple_type;
02663 typedef OutputTuple output_type;
02664 private:
02665 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02666 public:
02667 unfolded_join_node(graph &g) : base_type(g) {}
02668 };
02669
02670 template<typename OutputTuple>
02671 class unfolded_join_node<8,OutputTuple,reserving> : public internal::join_node_base<reserving,
02672 std::tuple<
02673 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02674 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02675 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02676 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02677 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02678 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02679 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02680 reserving_port<typename std::tuple_element<7,OutputTuple>::type> >,
02681 OutputTuple
02682 > {
02683 public:
02684 typedef typename std::tuple<
02685 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02686 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02687 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02688 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02689 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02690 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02691 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02692 reserving_port<typename std::tuple_element<7,OutputTuple>::type> > input_ports_tuple_type;
02693 typedef OutputTuple output_type;
02694 private:
02695 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02696 public:
02697 unfolded_join_node(graph &g) : base_type(g) {}
02698 };
02699
02700 template<typename OutputTuple>
02701 class unfolded_join_node<9,OutputTuple,reserving> : public internal::join_node_base<reserving,
02702 std::tuple<
02703 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02704 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02705 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02706 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02707 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02708 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02709 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02710 reserving_port<typename std::tuple_element<7,OutputTuple>::type>,
02711 reserving_port<typename std::tuple_element<8,OutputTuple>::type> >,
02712 OutputTuple
02713 > {
02714 public:
02715 typedef typename std::tuple<
02716 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02717 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02718 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02719 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02720 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02721 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02722 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02723 reserving_port<typename std::tuple_element<7,OutputTuple>::type>,
02724 reserving_port<typename std::tuple_element<8,OutputTuple>::type> > input_ports_tuple_type;
02725 typedef OutputTuple output_type;
02726 private:
02727 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02728 public:
02729 unfolded_join_node(graph &g) : base_type(g) {}
02730 };
02731
02732 template<typename OutputTuple>
02733 class unfolded_join_node<10,OutputTuple,reserving> : public internal::join_node_base<reserving,
02734 std::tuple<
02735 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02736 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02737 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02738 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02739 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02740 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02741 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02742 reserving_port<typename std::tuple_element<7,OutputTuple>::type>,
02743 reserving_port<typename std::tuple_element<8,OutputTuple>::type>,
02744 reserving_port<typename std::tuple_element<9,OutputTuple>::type> >,
02745 OutputTuple
02746 > {
02747 public:
02748 typedef typename std::tuple<
02749 reserving_port<typename std::tuple_element<0,OutputTuple>::type>,
02750 reserving_port<typename std::tuple_element<1,OutputTuple>::type>,
02751 reserving_port<typename std::tuple_element<2,OutputTuple>::type>,
02752 reserving_port<typename std::tuple_element<3,OutputTuple>::type>,
02753 reserving_port<typename std::tuple_element<4,OutputTuple>::type>,
02754 reserving_port<typename std::tuple_element<5,OutputTuple>::type>,
02755 reserving_port<typename std::tuple_element<6,OutputTuple>::type>,
02756 reserving_port<typename std::tuple_element<7,OutputTuple>::type>,
02757 reserving_port<typename std::tuple_element<8,OutputTuple>::type>,
02758 reserving_port<typename std::tuple_element<9,OutputTuple>::type> > input_ports_tuple_type;
02759 typedef OutputTuple output_type;
02760 private:
02761 typedef join_node_base<reserving, input_ports_tuple_type, output_type > base_type;
02762 public:
02763 unfolded_join_node(graph &g) : base_type(g) {}
02764 };
02765
02766 template<typename OutputTuple>
02767 class unfolded_join_node<2,OutputTuple,queueing> : public internal::join_node_base<queueing,
02768 std::tuple<
02769 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02770 queueing_port<typename std::tuple_element<1,OutputTuple>::type> >,
02771 OutputTuple
02772 >
02773 {
02774 public:
02775 typedef typename std::tuple<
02776 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02777 queueing_port<typename std::tuple_element<1,OutputTuple>::type> > input_ports_tuple_type;
02778 typedef OutputTuple output_type;
02779 private:
02780 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02781 public:
02782 unfolded_join_node(graph &g) : base_type(g) {}
02783 };
02784
02785 template<typename OutputTuple>
02786 class unfolded_join_node<3,OutputTuple,queueing> : public internal::join_node_base<queueing,
02787 std::tuple<
02788 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02789 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02790 queueing_port<typename std::tuple_element<2,OutputTuple>::type> >,
02791 OutputTuple
02792 >
02793 {
02794 public:
02795 typedef typename std::tuple<
02796 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02797 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02798 queueing_port<typename std::tuple_element<2,OutputTuple>::type> > input_ports_tuple_type;
02799 typedef OutputTuple output_type;
02800 private:
02801 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02802 public:
02803 unfolded_join_node(graph &g) : base_type(g) {}
02804 };
02805
02806 template<typename OutputTuple>
02807 class unfolded_join_node<4,OutputTuple,queueing> : public internal::join_node_base<queueing,
02808 std::tuple<
02809 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02810 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02811 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02812 queueing_port<typename std::tuple_element<3,OutputTuple>::type> >,
02813 OutputTuple
02814 > {
02815 public:
02816 typedef typename std::tuple<
02817 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02818 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02819 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02820 queueing_port<typename std::tuple_element<3,OutputTuple>::type> > input_ports_tuple_type;
02821 typedef OutputTuple output_type;
02822 private:
02823 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02824 public:
02825 unfolded_join_node(graph &g) : base_type(g) {}
02826 };
02827
02828 template<typename OutputTuple>
02829 class unfolded_join_node<5,OutputTuple,queueing> : public internal::join_node_base<queueing,
02830 std::tuple<
02831 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02832 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02833 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02834 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02835 queueing_port<typename std::tuple_element<4,OutputTuple>::type> >,
02836 OutputTuple
02837 > {
02838 public:
02839 typedef typename std::tuple<
02840 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02841 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02842 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02843 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02844 queueing_port<typename std::tuple_element<4,OutputTuple>::type> > input_ports_tuple_type;
02845 typedef OutputTuple output_type;
02846 private:
02847 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02848 public:
02849 unfolded_join_node(graph &g) : base_type(g) {}
02850 };
02851
02852 template<typename OutputTuple>
02853 class unfolded_join_node<6,OutputTuple,queueing> : public internal::join_node_base<queueing,
02854 std::tuple<
02855 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02856 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02857 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02858 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02859 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02860 queueing_port<typename std::tuple_element<5,OutputTuple>::type> >,
02861 OutputTuple
02862 > {
02863 public:
02864 typedef typename std::tuple<
02865 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02866 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02867 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02868 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02869 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02870 queueing_port<typename std::tuple_element<5,OutputTuple>::type> > input_ports_tuple_type;
02871 typedef OutputTuple output_type;
02872 private:
02873 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02874 public:
02875 unfolded_join_node(graph &g) : base_type(g) {}
02876 };
02877
02878 template<typename OutputTuple>
02879 class unfolded_join_node<7,OutputTuple,queueing> : public internal::join_node_base<queueing,
02880 std::tuple<
02881 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02882 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02883 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02884 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02885 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02886 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02887 queueing_port<typename std::tuple_element<6,OutputTuple>::type> >,
02888 OutputTuple
02889 > {
02890 public:
02891 typedef typename std::tuple<
02892 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02893 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02894 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02895 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02896 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02897 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02898 queueing_port<typename std::tuple_element<6,OutputTuple>::type> > input_ports_tuple_type;
02899 typedef OutputTuple output_type;
02900 private:
02901 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02902 public:
02903 unfolded_join_node(graph &g) : base_type(g) {}
02904 };
02905
02906 template<typename OutputTuple>
02907 class unfolded_join_node<8,OutputTuple,queueing> : public internal::join_node_base<queueing,
02908 std::tuple<
02909 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02910 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02911 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02912 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02913 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02914 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02915 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02916 queueing_port<typename std::tuple_element<7,OutputTuple>::type> >,
02917 OutputTuple
02918 > {
02919 public:
02920 typedef typename std::tuple<
02921 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02922 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02923 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02924 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02925 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02926 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02927 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02928 queueing_port<typename std::tuple_element<7,OutputTuple>::type> > input_ports_tuple_type;
02929 typedef OutputTuple output_type;
02930 private:
02931 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02932 public:
02933 unfolded_join_node(graph &g) : base_type(g) {}
02934 };
02935
02936 template<typename OutputTuple>
02937 class unfolded_join_node<9,OutputTuple,queueing> : public internal::join_node_base<queueing,
02938 std::tuple<
02939 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02940 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02941 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02942 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02943 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02944 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02945 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02946 queueing_port<typename std::tuple_element<7,OutputTuple>::type>,
02947 queueing_port<typename std::tuple_element<8,OutputTuple>::type> >,
02948 OutputTuple
02949 > {
02950 public:
02951 typedef typename std::tuple<
02952 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02953 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02954 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02955 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02956 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02957 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02958 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02959 queueing_port<typename std::tuple_element<7,OutputTuple>::type>,
02960 queueing_port<typename std::tuple_element<8,OutputTuple>::type> > input_ports_tuple_type;
02961 typedef OutputTuple output_type;
02962 private:
02963 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02964 public:
02965 unfolded_join_node(graph &g) : base_type(g) {}
02966 };
02967
02968 template<typename OutputTuple>
02969 class unfolded_join_node<10,OutputTuple,queueing> : public internal::join_node_base<queueing,
02970 std::tuple<
02971 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02972 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02973 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02974 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02975 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02976 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02977 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02978 queueing_port<typename std::tuple_element<7,OutputTuple>::type>,
02979 queueing_port<typename std::tuple_element<8,OutputTuple>::type>,
02980 queueing_port<typename std::tuple_element<9,OutputTuple>::type> >,
02981 OutputTuple
02982 > {
02983 public:
02984 typedef typename std::tuple<
02985 queueing_port<typename std::tuple_element<0,OutputTuple>::type>,
02986 queueing_port<typename std::tuple_element<1,OutputTuple>::type>,
02987 queueing_port<typename std::tuple_element<2,OutputTuple>::type>,
02988 queueing_port<typename std::tuple_element<3,OutputTuple>::type>,
02989 queueing_port<typename std::tuple_element<4,OutputTuple>::type>,
02990 queueing_port<typename std::tuple_element<5,OutputTuple>::type>,
02991 queueing_port<typename std::tuple_element<6,OutputTuple>::type>,
02992 queueing_port<typename std::tuple_element<7,OutputTuple>::type>,
02993 queueing_port<typename std::tuple_element<8,OutputTuple>::type>,
02994 queueing_port<typename std::tuple_element<9,OutputTuple>::type> > input_ports_tuple_type;
02995 typedef OutputTuple output_type;
02996 private:
02997 typedef join_node_base<queueing, input_ports_tuple_type, output_type > base_type;
02998 public:
02999 unfolded_join_node(graph &g) : base_type(g) {}
03000 };
03001
03003 template<size_t N, typename JNT>
03004 typename std::tuple_element<N, typename JNT::input_ports_tuple_type>::type &input_port(JNT &jn) {
03005 return std::get<N>(jn.inputs());
03006 }
03007
03008 }
03009
03010 using namespace internal::join_policy_namespace;
03011 using internal::input_port;
03012
03013 template<typename OutputTuple, join_policy JP=reserving>
03014 class join_node: public internal::unfolded_join_node<std::tuple_size<OutputTuple>::value, OutputTuple, JP> {
03015 private:
03016 static const int N = std::tuple_size<OutputTuple>::value;
03017 typedef typename internal::unfolded_join_node<N, OutputTuple, JP> unfolded_type;
03018 public:
03019 typedef OutputTuple output_type;
03020 typedef typename unfolded_type::input_ports_tuple_type input_ports_tuple_type;
03021 join_node(graph &g) : unfolded_type(g) { }
03022 };
03023
03024
03025
03026
03027
03029 template< typename T >
03030 inline void make_edge( sender<T> &p, receiver<T> &s ) {
03031 p.register_successor( s );
03032 }
03033
03035 template< typename T, typename SIterator >
03036 inline void make_edges( sender<T> &p, SIterator s_begin, SIterator s_end ) {
03037 for ( SIterator i = s_begin; i != s_end; ++i ) {
03038 make_edge( p, **i );
03039 }
03040 }
03041
03043 template< typename T, typename PIterator >
03044 inline void make_edges( PIterator p_begin, PIterator p_end, receiver<T> &s ) {
03045 for ( PIterator i = p_begin; i != p_end; ++i ) {
03046 make_edge( **i, s );
03047 }
03048 }
03049
03050 }
03051
03052 #endif
03053