graph.h

Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
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 // use the VC10 or gcc version of tuple if it is available.
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         /* override */ bool register_predecessor( predecessor_type & ) {
00155             spin_mutex::scoped_lock l(my_mutex);
00156             ++my_predecessor_count;
00157             return true;
00158         }
00159 
00161 
00164         /* override */ bool remove_predecessor( predecessor_type & ) {
00165             spin_mutex::scoped_lock l(my_mutex);
00166             --my_predecessor_count;
00167             return true;
00168         }
00169 
00171 
00173         /* override */ 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             /*override */ 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             // Assumes lock is held
00372             inline bool internal_empty( )  {
00373                 return my_q.empty();
00374             }
00375 
00376             // Assumes lock is held
00377             inline size_type internal_size( )  {
00378                 return my_q.size(); 
00379             }
00380 
00381             // Assumes lock is held
00382             inline void internal_push( T &n )  {
00383                 my_q.push(&n);
00384             }
00385 
00386             // Assumes lock is held
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                     // Try to get from this sender
00423                     msg = src->try_get( v );
00424 
00425                     if (msg == false) {
00426                         // Relinquish ownership of the edge
00427                         if ( my_owner) 
00428                             src->register_successor( *my_owner );
00429                     } else {
00430                         // Retain ownership of the edge
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                     // Try to get from this sender
00466                     msg = reserved_src->try_reserve( v );
00467 
00468                     if (msg == false) {
00469                         typename my_mutex_type::scoped_lock lock(this->my_mutex);
00470                         // Relinquish ownership of the edge
00471                         reserved_src->register_successor( *this->my_owner );
00472                         reserved_src = NULL;
00473                     } else {
00474                         // Retain ownership of the edge
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             /* override */ 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             /* override */ 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             /* override */ void apply_body( input_type ) {
01016                 successors().try_put( (*my_body)( continue_msg() ) );
01017             }
01018 
01020             /* override */ 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             /* override */ bool register_successor( receiver<output_type> &r ) {
01037                 successors().register_successor( r );
01038                 return true;
01039             }
01040 
01042             /* override */ 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         /* override */ 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         /* override */ 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         /*override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ bool register_successor( successor_type &s ) {
01265             spin_mutex::scoped_lock l( my_mutex );
01266             if ( my_buffer_is_valid ) {
01267                 // We have a valid value that must be forwarded immediately.
01268                 if ( s.try_put( my_buffer ) || !s.register_predecessor( *this  ) ) {
01269                     // We add the successor: it accepted our put or it rejected it but won't let use become a predecessor
01270                     my_successors.register_successor( s );
01271                     return true;
01272                 } else {
01273                     // We don't add the successor: it rejected our put and we became its predecessor instead
01274                     return false;
01275                 }
01276             } else {
01277                 // No valid value yet, just add as successor
01278                 my_successors.register_successor( s );
01279                 return true;
01280             }
01281         }
01282 
01283         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         // implements the aggregator_operation concept
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; // flagged when a successor accepts
01490             size_type counter = my_successors.size();
01491             // Try forwarding, giving each successor a chance
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; // found an accepting successor
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         // message sender implementation
01554         //
01555 
01557 
01558         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ bool try_release() {
01599             buffer_operation op_data(rel_res);
01600             my_aggregator.execute(&op_data);
01601             return true;
01602         }
01603 
01605 
01606         /* override */ bool try_consume() {
01607             buffer_operation op_data(con_res);
01608             my_aggregator.execute(&op_data);
01609             return true;
01610         }
01611 
01613 
01614         /* override */ 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         /* override */ void internal_forward(queue_operation *op) {
01633             T i_copy;
01634             bool success = false; // flagged when a successor accepts
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             // Keep trying to send items while there is at least one accepting successor
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; // found an accepting successor
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         /* override */ 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         /* override */ 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         /* override */ 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         /* override */ 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());  // tail already has 1 added to it
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         /* override */ void handle_operations(prio_operation *op_list) {
01752             prio_operation *tmp /*, *pop_list*/ ;
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             // process pops!  for now, no special pop processing
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         /* override */ void internal_forward(prio_operation *op) {
01778             T i_copy;
01779             bool success = false; // flagged when a successor accepts
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             // Keep trying to send while there exists an accepting successor
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) // don't reheap for heap of size 1
01796                         reheap();
01797                     success = true; // found an accepting successor
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         /* override */ 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         /* override */ 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                     // there are newly pushed elems; last one higher than top
01825                     // copy the data
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 { // extract and push the last element down heap
01831                     *(op->elem) = this->my_array[0].first; // copy the data
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) // don't reheap for heap of size 1
01837                         reheap();
01838                 }
01839             }
01840         }
01841         /* override */ 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) // don't reheap for heap of size 1
01853                     reheap();
01854             }
01855         }
01856         /* override */ void internal_consume(prio_operation *op) {
01857             this->my_reserved = false;
01858             __TBB_store_with_release(op->status, SUCCEEDED);
01859         }
01860         /* override */ 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) { // for each unheaped element
01877                 size_type cur_pos = mark;
01878                 input_type to_place = this->my_array[mark].first;
01879                 do { // push to_place up the heap
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                 // target now has the higher priority child
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         // Let decrementer call decrement_counter()
01935         friend class internal::decrementer< limiter_node<T> >;
01936 
01937         void decrement_counter() {
01938             input_type v;
01939             
01940             // If we can't get / put an item immediately then drop the count
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         /* override */ bool register_successor( receiver<output_type> &r ) {
01977             my_successors.register_successor(r);
01978             return true;
01979         }
01980 
01982 
01983         /* override */ bool remove_successor( receiver<output_type> &r ) {
01984             r.remove_predecessor(*this);
01985             my_successors.remove_successor(r);
01986             return true;
01987         }
01988 
01990         /* override */ 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         /* override */ 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         /* override */ 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         // moved here so input ports can queue tasks
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) ); // may fail
02079             return join_helper<N-1>::get_my_item(my_input, out) && res;       // do get on other inputs before returning
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         // copy constructor
02169         reserving_port(const reserving_port& /* other */) : 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         // always rejects, so arc is reversed (and reserves can be done.)
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( ); // may try to forward
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& /* other */) : 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         /*override*/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         // this is spawned when we have a predecessor attached and
02273         // if the buffer is empty.  This way the thread running the
02274         // predecessor may return.  But it really is a "backward"
02275         // method, not forward...
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;     // failed to get anymore items
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 ) ) {  // calls into predecessor
02315                 this->push_back(v);
02316                 // buffer was empty
02317                 my_join->decrement_port_count();
02318                 return true;
02319             }
02320             return false;
02321         }
02322 
02323         // try to get from predecessors
02324         // reset called when item is accepted by successor, but
02325         // is initiated by join_node.
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; // for forwarding
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         // if all input_ports have predecessors, spawn forward to try and consume tuples
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         // all methods on input ports should be called under spin lock from join_node_base.
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; // for forwarding
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         // needed for forwarding
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         // if all input_ports have items, spawn forward to try and consume tuples
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); }  // should never be called
02429 
02430         input_type &inputs() { return my_inputs; }
02431     protected:
02432         // all methods on input ports should be called under spin lock from join_node_base.
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             // nothing to do.
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                     // successor requested, so acceptance guaranteed
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     //  using tuple_element.
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     } // namespace internal
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     // Making edges
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 

Copyright © 2005-2011 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.