graph.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# 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.