| _flow_graph_join_impl.h | | _flow_graph_join_impl.h | |
| | | | |
| skipping to change at line 46 | | skipping to change at line 46 | |
| #include "tbb/internal/_flow_graph_types_impl.h" | | #include "tbb/internal/_flow_graph_types_impl.h" | |
| | | | |
| namespace internal { | | namespace internal { | |
| | | | |
| typedef size_t tag_value; | | typedef size_t tag_value; | |
| static const tag_value NO_TAG = tag_value(-1); | | static const tag_value NO_TAG = tag_value(-1); | |
| | | | |
| struct forwarding_base { | | struct forwarding_base { | |
| forwarding_base(task *rt) : my_root_task(rt), current_tag(NO_TAG) {
} | | forwarding_base(task *rt) : my_root_task(rt), current_tag(NO_TAG) {
} | |
| virtual ~forwarding_base() {} | | virtual ~forwarding_base() {} | |
|
| virtual void decrement_port_count() = 0; | | // decrement_port_count may create a forwarding task. If we cannot | |
| | | handle the task | |
| | | // ourselves, ask decrement_port_count to deal with it. | |
| | | virtual task * decrement_port_count(bool handle_task) = 0; | |
| virtual void increment_port_count() = 0; | | virtual void increment_port_count() = 0; | |
|
| virtual void increment_tag_count(tag_value /*t*/) {} | | virtual task * increment_tag_count(tag_value /*t*/, bool /*handle_t
ask*/) {return NULL;} | |
| // moved here so input ports can queue tasks | | // moved here so input ports can queue tasks | |
| task* my_root_task; | | task* my_root_task; | |
| tag_value current_tag; // so ports can refer to FE's desired items | | tag_value current_tag; // so ports can refer to FE's desired items | |
| }; | | }; | |
| | | | |
| template< int N > | | template< int N > | |
| struct join_helper { | | struct join_helper { | |
| | | | |
| template< typename TupleType, typename PortType > | | template< typename TupleType, typename PortType > | |
| static inline void set_join_node_pointer(TupleType &my_input, PortT
ype *port) { | | static inline void set_join_node_pointer(TupleType &my_input, PortT
ype *port) { | |
|
| std::get<N-1>( my_input ).set_join_node_pointer(port); | | tbb::flow::get<N-1>( my_input ).set_join_node_pointer(port); | |
| join_helper<N-1>::set_join_node_pointer( my_input, port ); | | join_helper<N-1>::set_join_node_pointer( my_input, port ); | |
| } | | } | |
| template< typename TupleType > | | template< typename TupleType > | |
| static inline void consume_reservations( TupleType &my_input ) { | | static inline void consume_reservations( TupleType &my_input ) { | |
|
| std::get<N-1>( my_input ).consume(); | | tbb::flow::get<N-1>( my_input ).consume(); | |
| join_helper<N-1>::consume_reservations( my_input ); | | join_helper<N-1>::consume_reservations( my_input ); | |
| } | | } | |
| | | | |
| template< typename TupleType > | | template< typename TupleType > | |
| static inline void release_my_reservation( TupleType &my_input ) { | | static inline void release_my_reservation( TupleType &my_input ) { | |
|
| std::get<N-1>( my_input ).release(); | | tbb::flow::get<N-1>( my_input ).release(); | |
| } | | } | |
| | | | |
| template <typename TupleType> | | template <typename TupleType> | |
| static inline void release_reservations( TupleType &my_input) { | | static inline void release_reservations( TupleType &my_input) { | |
| join_helper<N-1>::release_reservations(my_input); | | join_helper<N-1>::release_reservations(my_input); | |
| release_my_reservation(my_input); | | release_my_reservation(my_input); | |
| } | | } | |
| | | | |
| template< typename InputTuple, typename OutputTuple > | | template< typename InputTuple, typename OutputTuple > | |
| static inline bool reserve( InputTuple &my_input, OutputTuple &out)
{ | | static inline bool reserve( InputTuple &my_input, OutputTuple &out)
{ | |
|
| if ( !std::get<N-1>( my_input ).reserve( std::get<N-1>( out ) )
) return false; | | if ( !tbb::flow::get<N-1>( my_input ).reserve( tbb::flow::get<N
-1>( out ) ) ) return false; | |
| if ( !join_helper<N-1>::reserve( my_input, out ) ) { | | if ( !join_helper<N-1>::reserve( my_input, out ) ) { | |
| release_my_reservation( my_input ); | | release_my_reservation( my_input ); | |
| return false; | | return false; | |
| } | | } | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| static inline bool get_my_item( InputTuple &my_input, OutputTuple &
out) { | | static inline bool get_my_item( InputTuple &my_input, OutputTuple &
out) { | |
|
| bool res = std::get<N-1>(my_input).get_item(std::get<N-1>(out)
); // may fail | | bool res = tbb::flow::get<N-1>(my_input).get_item(tbb::flow::ge
t<N-1>(out) ); // may fail | |
| return join_helper<N-1>::get_my_item(my_input, out) && res;
// do get on other inputs before returning | | return join_helper<N-1>::get_my_item(my_input, out) && res;
// do get on other inputs before returning | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| static inline bool get_items(InputTuple &my_input, OutputTuple &out
) { | | static inline bool get_items(InputTuple &my_input, OutputTuple &out
) { | |
| return get_my_item(my_input, out); | | return get_my_item(my_input, out); | |
| } | | } | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_my_port(InputTuple &my_input) { | | static inline void reset_my_port(InputTuple &my_input) { | |
| join_helper<N-1>::reset_my_port(my_input); | | join_helper<N-1>::reset_my_port(my_input); | |
|
| std::get<N-1>(my_input).reset_port(); | | tbb::flow::get<N-1>(my_input).reset_port(); | |
| } | | } | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_ports(InputTuple& my_input) { | | static inline void reset_ports(InputTuple& my_input) { | |
| reset_my_port(my_input); | | reset_my_port(my_input); | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename TagFuncTuple> | | template<typename InputTuple, typename TagFuncTuple> | |
| static inline void set_tag_func(InputTuple &my_input, TagFuncTuple
&my_tag_funcs) { | | static inline void set_tag_func(InputTuple &my_input, TagFuncTuple
&my_tag_funcs) { | |
|
| std::get<N-1>(my_input).set_my_original_tag_func(std::get<N-1>( | | tbb::flow::get<N-1>(my_input).set_my_original_tag_func(tbb::flo | |
| my_tag_funcs)); | | w::get<N-1>(my_tag_funcs)); | |
| std::get<N-1>(my_input).set_my_tag_func(std::get<N-1>(my_input) | | tbb::flow::get<N-1>(my_input).set_my_tag_func(tbb::flow::get<N- | |
| .my_original_func()->clone()); | | 1>(my_input).my_original_func()->clone()); | |
| std::get<N-1>(my_tag_funcs) = NULL; | | tbb::flow::get<N-1>(my_tag_funcs) = NULL; | |
| join_helper<N-1>::set_tag_func(my_input, my_tag_funcs); | | join_helper<N-1>::set_tag_func(my_input, my_tag_funcs); | |
| } | | } | |
| | | | |
| template< typename TagFuncTuple1, typename TagFuncTuple2> | | template< typename TagFuncTuple1, typename TagFuncTuple2> | |
| static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF
uncTuple2 &other_inputs) { | | static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF
uncTuple2 &other_inputs) { | |
|
| if(std::get<N-1>(other_inputs).my_original_func()) { | | if(tbb::flow::get<N-1>(other_inputs).my_original_func()) { | |
| std::get<N-1>(my_inputs).set_my_tag_func(std::get<N-1>(othe | | tbb::flow::get<N-1>(my_inputs).set_my_tag_func(tbb::flow::g | |
| r_inputs).my_original_func()->clone()); | | et<N-1>(other_inputs).my_original_func()->clone()); | |
| std::get<N-1>(my_inputs).set_my_original_tag_func(std::get< | | tbb::flow::get<N-1>(my_inputs).set_my_original_tag_func(tbb | |
| N-1>(other_inputs).my_original_func()->clone()); | | ::flow::get<N-1>(other_inputs).my_original_func()->clone()); | |
| } | | } | |
| join_helper<N-1>::copy_tag_functors(my_inputs, other_inputs); | | join_helper<N-1>::copy_tag_functors(my_inputs, other_inputs); | |
| } | | } | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_inputs(InputTuple &my_input) { | | static inline void reset_inputs(InputTuple &my_input) { | |
| join_helper<N-1>::reset_inputs(my_input); | | join_helper<N-1>::reset_inputs(my_input); | |
|
| std::get<N-1>(my_input).reinitialize_port(); | | tbb::flow::get<N-1>(my_input).reinitialize_port(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template< > | | template< > | |
| struct join_helper<1> { | | struct join_helper<1> { | |
| | | | |
| template< typename TupleType, typename PortType > | | template< typename TupleType, typename PortType > | |
| static inline void set_join_node_pointer(TupleType &my_input, PortT
ype *port) { | | static inline void set_join_node_pointer(TupleType &my_input, PortT
ype *port) { | |
|
| std::get<0>( my_input ).set_join_node_pointer(port); | | tbb::flow::get<0>( my_input ).set_join_node_pointer(port); | |
| } | | } | |
| | | | |
| template< typename TupleType > | | template< typename TupleType > | |
| static inline void consume_reservations( TupleType &my_input ) { | | static inline void consume_reservations( TupleType &my_input ) { | |
|
| std::get<0>( my_input ).consume(); | | tbb::flow::get<0>( my_input ).consume(); | |
| } | | } | |
| | | | |
| template< typename TupleType > | | template< typename TupleType > | |
| static inline void release_my_reservation( TupleType &my_input ) { | | static inline void release_my_reservation( TupleType &my_input ) { | |
|
| std::get<0>( my_input ).release(); | | tbb::flow::get<0>( my_input ).release(); | |
| } | | } | |
| | | | |
| template<typename TupleType> | | template<typename TupleType> | |
| static inline void release_reservations( TupleType &my_input) { | | static inline void release_reservations( TupleType &my_input) { | |
| release_my_reservation(my_input); | | release_my_reservation(my_input); | |
| } | | } | |
| | | | |
| template< typename InputTuple, typename OutputTuple > | | template< typename InputTuple, typename OutputTuple > | |
| static inline bool reserve( InputTuple &my_input, OutputTuple &out)
{ | | static inline bool reserve( InputTuple &my_input, OutputTuple &out)
{ | |
|
| return std::get<0>( my_input ).reserve( std::get<0>( out ) ); | | return tbb::flow::get<0>( my_input ).reserve( tbb::flow::get<0>
( out ) ); | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| static inline bool get_my_item( InputTuple &my_input, OutputTuple &
out) { | | static inline bool get_my_item( InputTuple &my_input, OutputTuple &
out) { | |
|
| return std::get<0>(my_input).get_item(std::get<0>(out)); | | return tbb::flow::get<0>(my_input).get_item(tbb::flow::get<0>(o
ut)); | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| static inline bool get_items(InputTuple &my_input, OutputTuple &out
) { | | static inline bool get_items(InputTuple &my_input, OutputTuple &out
) { | |
| return get_my_item(my_input, out); | | return get_my_item(my_input, out); | |
| } | | } | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_my_port(InputTuple &my_input) { | | static inline void reset_my_port(InputTuple &my_input) { | |
|
| std::get<0>(my_input).reset_port(); | | tbb::flow::get<0>(my_input).reset_port(); | |
| } | | } | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_ports(InputTuple& my_input) { | | static inline void reset_ports(InputTuple& my_input) { | |
| reset_my_port(my_input); | | reset_my_port(my_input); | |
| } | | } | |
| | | | |
| template<typename InputTuple, typename TagFuncTuple> | | template<typename InputTuple, typename TagFuncTuple> | |
| static inline void set_tag_func(InputTuple &my_input, TagFuncTuple
&my_tag_funcs) { | | static inline void set_tag_func(InputTuple &my_input, TagFuncTuple
&my_tag_funcs) { | |
|
| std::get<0>(my_input).set_my_original_tag_func(std::get<0>(my_t | | tbb::flow::get<0>(my_input).set_my_original_tag_func(tbb::flow: | |
| ag_funcs)); | | :get<0>(my_tag_funcs)); | |
| std::get<0>(my_input).set_my_tag_func(std::get<0>(my_input).my_ | | tbb::flow::get<0>(my_input).set_my_tag_func(tbb::flow::get<0>(m | |
| original_func()->clone()); | | y_input).my_original_func()->clone()); | |
| std::get<0>(my_tag_funcs) = NULL; | | tbb::flow::get<0>(my_tag_funcs) = NULL; | |
| } | | } | |
| | | | |
| template< typename TagFuncTuple1, typename TagFuncTuple2> | | template< typename TagFuncTuple1, typename TagFuncTuple2> | |
| static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF
uncTuple2 &other_inputs) { | | static inline void copy_tag_functors(TagFuncTuple1 &my_inputs, TagF
uncTuple2 &other_inputs) { | |
|
| if(std::get<0>(other_inputs).my_original_func()) { | | if(tbb::flow::get<0>(other_inputs).my_original_func()) { | |
| std::get<0>(my_inputs).set_my_tag_func(std::get<0>(other_in | | tbb::flow::get<0>(my_inputs).set_my_tag_func(tbb::flow::get | |
| puts).my_original_func()->clone()); | | <0>(other_inputs).my_original_func()->clone()); | |
| std::get<0>(my_inputs).set_my_original_tag_func(std::get<0> | | tbb::flow::get<0>(my_inputs).set_my_original_tag_func(tbb:: | |
| (other_inputs).my_original_func()->clone()); | | flow::get<0>(other_inputs).my_original_func()->clone()); | |
| } | | } | |
| } | | } | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| static inline void reset_inputs(InputTuple &my_input) { | | static inline void reset_inputs(InputTuple &my_input) { | |
|
| std::get<0>(my_input).reinitialize_port(); | | tbb::flow::get<0>(my_input).reinitialize_port(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! The two-phase join port | | //! The two-phase join port | |
| template< typename T > | | template< typename T > | |
| class reserving_port : public receiver<T> { | | class reserving_port : public receiver<T> { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| private: | | private: | |
| | | | |
| skipping to change at line 244 | | skipping to change at line 246 | |
| reserving_port_operation *current; | | reserving_port_operation *current; | |
| bool no_predecessors; | | bool no_predecessors; | |
| while(op_list) { | | while(op_list) { | |
| current = op_list; | | current = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch(current->type) { | | switch(current->type) { | |
| case reg_pred: | | case reg_pred: | |
| no_predecessors = my_predecessors.empty(); | | no_predecessors = my_predecessors.empty(); | |
| my_predecessors.add(*(current->my_pred)); | | my_predecessors.add(*(current->my_pred)); | |
| if ( no_predecessors ) { | | if ( no_predecessors ) { | |
|
| my_join->decrement_port_count( ); // may try to for
ward | | (void) my_join->decrement_port_count(true); // may
try to forward | |
| } | | } | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case rem_pred: | | case rem_pred: | |
| my_predecessors.remove(*(current->my_pred)); | | my_predecessors.remove(*(current->my_pred)); | |
| if(my_predecessors.empty()) my_join->increment_port_cou
nt(); | | if(my_predecessors.empty()) my_join->increment_port_cou
nt(); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case res_item: | | case res_item: | |
| if ( reserved ) { | | if ( reserved ) { | |
| | | | |
| skipping to change at line 281 | | skipping to change at line 283 | |
| break; | | break; | |
| case con_res: | | case con_res: | |
| reserved = false; | | reserved = false; | |
| my_predecessors.try_consume( ); | | my_predecessors.try_consume( ); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | protected: | |
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_c | |
| | | ache; | |
| | | template<typename X, typename Y> friend class internal::round_robin | |
| | | _cache; | |
| | | task *try_put_task( const T & ) { | |
| | | return NULL; | |
| | | } | |
| | | | |
| public: | | public: | |
| | | | |
| //! Constructor | | //! Constructor | |
| reserving_port() : reserved(false) { | | reserving_port() : reserved(false) { | |
| my_join = NULL; | | my_join = NULL; | |
| my_predecessors.set_owner( this ); | | my_predecessors.set_owner( this ); | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| // copy constructor | | // copy constructor | |
| | | | |
| skipping to change at line 302 | | skipping to change at line 312 | |
| reserved = false; | | reserved = false; | |
| my_join = NULL; | | my_join = NULL; | |
| my_predecessors.set_owner( this ); | | my_predecessors.set_owner( this ); | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| void set_join_node_pointer(forwarding_base *join) { | | void set_join_node_pointer(forwarding_base *join) { | |
| my_join = join; | | my_join = join; | |
| } | | } | |
| | | | |
|
| // always rejects, so arc is reversed (and reserves can be done.) | | | |
| bool try_put( const T & ) { | | | |
| return false; | | | |
| } | | | |
| | | | |
| //! Add a predecessor | | //! Add a predecessor | |
| bool register_predecessor( sender<T> &src ) { | | bool register_predecessor( sender<T> &src ) { | |
| reserving_port_operation op_data(src, reg_pred); | | reserving_port_operation op_data(src, reg_pred); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.status == SUCCEEDED; | | return op_data.status == SUCCEEDED; | |
| } | | } | |
| | | | |
| //! Remove a predecessor | | //! Remove a predecessor | |
| bool remove_predecessor( sender<T> &src ) { | | bool remove_predecessor( sender<T> &src ) { | |
| reserving_port_operation op_data(src, rem_pred); | | reserving_port_operation op_data(src, rem_pred); | |
| | | | |
| skipping to change at line 367 | | skipping to change at line 372 | |
| //! queueing join_port | | //! queueing join_port | |
| template<typename T> | | template<typename T> | |
| class queueing_port : public receiver<T>, public item_buffer<T> { | | class queueing_port : public receiver<T>, public item_buffer<T> { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| typedef queueing_port<T> my_node_type; | | typedef queueing_port<T> my_node_type; | |
| | | | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| private: | | private: | |
|
| enum op_type { try__put, get__item, res_port }; | | enum op_type { get__item, res_port, try__put_task }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef queueing_port<T> my_class; | | typedef queueing_port<T> my_class; | |
| | | | |
| class queueing_port_operation : public aggregated_operation<queuein
g_port_operation> { | | class queueing_port_operation : public aggregated_operation<queuein
g_port_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| T my_val; | | T my_val; | |
| T *my_arg; | | T *my_arg; | |
|
| | | task * bypass_t; | |
| // constructor for value parameter | | // constructor for value parameter | |
| queueing_port_operation(const T& e, op_type t) : | | queueing_port_operation(const T& e, op_type t) : | |
|
| // type(char(t)), my_val(const_cast<T>(e)) {} | | type(char(t)), my_val(e) | |
| type(char(t)), my_val(e) {} | | , bypass_t(NULL) | |
| | | {} | |
| // constructor for pointer parameter | | // constructor for pointer parameter | |
| queueing_port_operation(const T* p, op_type t) : | | queueing_port_operation(const T* p, op_type t) : | |
|
| type(char(t)), my_arg(const_cast<T*>(p)) {} | | type(char(t)), my_arg(const_cast<T*>(p)) | |
| | | , bypass_t(NULL) | |
| | | {} | |
| // constructor with no parameter | | // constructor with no parameter | |
|
| queueing_port_operation(op_type t) : type(char(t)) {} | | queueing_port_operation(op_type t) : type(char(t)) | |
| | | , bypass_t(NULL) | |
| | | {} | |
| }; | | }; | |
| | | | |
| typedef internal::aggregating_functor<my_class, queueing_port_opera
tion> my_handler; | | typedef internal::aggregating_functor<my_class, queueing_port_opera
tion> my_handler; | |
| friend class internal::aggregating_functor<my_class, queueing_port_
operation>; | | friend class internal::aggregating_functor<my_class, queueing_port_
operation>; | |
| aggregator<my_handler, queueing_port_operation> my_aggregator; | | aggregator<my_handler, queueing_port_operation> my_aggregator; | |
| | | | |
| void handle_operations(queueing_port_operation* op_list) { | | void handle_operations(queueing_port_operation* op_list) { | |
| queueing_port_operation *current; | | queueing_port_operation *current; | |
| bool was_empty; | | bool was_empty; | |
| while(op_list) { | | while(op_list) { | |
| current = op_list; | | current = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch(current->type) { | | switch(current->type) { | |
|
| case try__put: | | case try__put_task: { | |
| was_empty = this->buffer_empty(); | | task *rtask = NULL; | |
| this->push_back(current->my_val); | | was_empty = this->buffer_empty(); | |
| if (was_empty) my_join->decrement_port_count(); | | this->push_back(current->my_val); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | if (was_empty) rtask = my_join->decrement_port_coun | |
| | | t(false); | |
| | | else | |
| | | rtask = SUCCESSFULLY_ENQUEUED; | |
| | | current->bypass_t = rtask; | |
| | | __TBB_store_with_release(current->status, SUCCEEDED | |
| | | ); | |
| | | } | |
| break; | | break; | |
| case get__item: | | case get__item: | |
| if(!this->buffer_empty()) { | | if(!this->buffer_empty()) { | |
| this->fetch_front(*(current->my_arg)); | | this->fetch_front(*(current->my_arg)); | |
| __TBB_store_with_release(current->status, SUCCEEDED
); | | __TBB_store_with_release(current->status, SUCCEEDED
); | |
| } | | } | |
| else { | | else { | |
| __TBB_store_with_release(current->status, FAILED); | | __TBB_store_with_release(current->status, FAILED); | |
| } | | } | |
| break; | | break; | |
| case res_port: | | case res_port: | |
| __TBB_ASSERT(this->item_valid(this->my_head), "No item
to reset"); | | __TBB_ASSERT(this->item_valid(this->my_head), "No item
to reset"); | |
| this->invalidate_front(); ++(this->my_head); | | this->invalidate_front(); ++(this->my_head); | |
| if(this->item_valid(this->my_head)) { | | if(this->item_valid(this->my_head)) { | |
|
| my_join->decrement_port_count(); | | (void)my_join->decrement_port_count(true); | |
| } | | } | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ------------ End Aggregator --------------- | | // ------------ End Aggregator --------------- | |
|
| | | | |
| | | protected: | |
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_c | |
| | | ache; | |
| | | template<typename X, typename Y> friend class internal::round_robin | |
| | | _cache; | |
| | | /*override*/task *try_put_task(const T &v) { | |
| | | queueing_port_operation op_data(v, try__put_task); | |
| | | my_aggregator.execute(&op_data); | |
| | | __TBB_ASSERT(op_data.status == SUCCEEDED || !op_data.bypass_t, | |
| | | "inconsistent return from aggregator"); | |
| | | if(!op_data.bypass_t) return SUCCESSFULLY_ENQUEUED; | |
| | | return op_data.bypass_t; | |
| | | } | |
| | | | |
| public: | | public: | |
| | | | |
| //! Constructor | | //! Constructor | |
| queueing_port() : item_buffer<T>() { | | queueing_port() : item_buffer<T>() { | |
| my_join = NULL; | | my_join = NULL; | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| //! copy constructor | | //! copy constructor | |
| queueing_port(const queueing_port& /* other */) : receiver<T>(), it
em_buffer<T>() { | | queueing_port(const queueing_port& /* other */) : receiver<T>(), it
em_buffer<T>() { | |
| my_join = NULL; | | my_join = NULL; | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| //! record parent for tallying available items | | //! record parent for tallying available items | |
| void set_join_node_pointer(forwarding_base *join) { | | void set_join_node_pointer(forwarding_base *join) { | |
| my_join = join; | | my_join = join; | |
| } | | } | |
| | | | |
|
| /*override*/bool try_put(const T &v) { | | | |
| queueing_port_operation op_data(v, try__put); | | | |
| my_aggregator.execute(&op_data); | | | |
| return op_data.status == SUCCEEDED; | | | |
| } | | | |
| | | | |
| bool get_item( T &v ) { | | bool get_item( T &v ) { | |
| queueing_port_operation op_data(&v, get__item); | | queueing_port_operation op_data(&v, get__item); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.status == SUCCEEDED; | | return op_data.status == SUCCEEDED; | |
| } | | } | |
| | | | |
| // reset_port is called when item is accepted by successor, but | | // reset_port is called when item is accepted by successor, but | |
| // is initiated by join_node. | | // is initiated by join_node. | |
| void reset_port() { | | void reset_port() { | |
| queueing_port_operation op_data(res_port); | | queueing_port_operation op_data(res_port); | |
| | | | |
| skipping to change at line 503 | | skipping to change at line 526 | |
| typedef tag_matching_port<T> my_class; | | typedef tag_matching_port<T> my_class; | |
| | | | |
| class tag_matching_port_operation : public aggregated_operation<tag
_matching_port_operation> { | | class tag_matching_port_operation : public aggregated_operation<tag
_matching_port_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| T my_val; | | T my_val; | |
| T *my_arg; | | T *my_arg; | |
| tag_value my_tag_value; | | tag_value my_tag_value; | |
| // constructor for value parameter | | // constructor for value parameter | |
| tag_matching_port_operation(const T& e, op_type t) : | | tag_matching_port_operation(const T& e, op_type t) : | |
|
| // type(char(t)), my_val(const_cast<T>(e)) {} | | | |
| type(char(t)), my_val(e) {} | | type(char(t)), my_val(e) {} | |
| // constructor for pointer parameter | | // constructor for pointer parameter | |
| tag_matching_port_operation(const T* p, op_type t) : | | tag_matching_port_operation(const T* p, op_type t) : | |
| type(char(t)), my_arg(const_cast<T*>(p)) {} | | type(char(t)), my_arg(const_cast<T*>(p)) {} | |
| // constructor with no parameter | | // constructor with no parameter | |
| tag_matching_port_operation(op_type t) : type(char(t)) {} | | tag_matching_port_operation(op_type t) : type(char(t)) {} | |
| }; | | }; | |
| | | | |
| typedef internal::aggregating_functor<my_class, tag_matching_port_o
peration> my_handler; | | typedef internal::aggregating_functor<my_class, tag_matching_port_o
peration> my_handler; | |
| friend class internal::aggregating_functor<my_class, tag_matching_p
ort_operation>; | | friend class internal::aggregating_functor<my_class, tag_matching_p
ort_operation>; | |
| | | | |
| skipping to change at line 544 | | skipping to change at line 566 | |
| break; | | break; | |
| case res_port: | | case res_port: | |
| // use current_tag from FE for item | | // use current_tag from FE for item | |
| this->tagged_delete(my_join->current_tag); | | this->tagged_delete(my_join->current_tag); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ------------ End Aggregator --------------- | | // ------------ End Aggregator --------------- | |
|
| | | protected: | |
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_c | |
| | | ache; | |
| | | template<typename X, typename Y> friend class internal::round_robin | |
| | | _cache; | |
| | | /*override*/task *try_put_task(const T& v) { | |
| | | tag_matching_port_operation op_data(v, try__put); | |
| | | op_data.my_tag_value = (*my_tag_func)(v); | |
| | | task *rtask = NULL; | |
| | | my_aggregator.execute(&op_data); | |
| | | if(op_data.status == SUCCEEDED) { | |
| | | rtask = my_join->increment_tag_count(op_data.my_tag_value, | |
| | | false); // may spawn | |
| | | // rtask has to reflect the return status of the try_put | |
| | | if(!rtask) rtask = SUCCESSFULLY_ENQUEUED; | |
| | | } | |
| | | return rtask; | |
| | | } | |
| | | | |
| public: | | public: | |
| | | | |
| tag_matching_port() : receiver<T>(), tagged_buffer<tag_value, T, NO
_TAG>() { | | tag_matching_port() : receiver<T>(), tagged_buffer<tag_value, T, NO
_TAG>() { | |
| my_join = NULL; | | my_join = NULL; | |
| my_tag_func = NULL; | | my_tag_func = NULL; | |
| my_original_tag_func = NULL; | | my_original_tag_func = NULL; | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| // copy constructor | | // copy constructor | |
| | | | |
| skipping to change at line 579 | | skipping to change at line 618 | |
| } | | } | |
| | | | |
| void set_my_original_tag_func(my_tag_func_type *f) { | | void set_my_original_tag_func(my_tag_func_type *f) { | |
| my_original_tag_func = f; | | my_original_tag_func = f; | |
| } | | } | |
| | | | |
| void set_my_tag_func(my_tag_func_type *f) { | | void set_my_tag_func(my_tag_func_type *f) { | |
| my_tag_func = f; | | my_tag_func = f; | |
| } | | } | |
| | | | |
|
| /*override*/bool try_put(const T& v) { | | | |
| tag_matching_port_operation op_data(v, try__put); | | | |
| op_data.my_tag_value = (*my_tag_func)(v); | | | |
| my_aggregator.execute(&op_data); | | | |
| if(op_data.status == SUCCEEDED) { | | | |
| // the assertion in the aggregator above will ensure we do | | | |
| not call with the same | | | |
| // tag twice. We have to exit the aggregator to keep lock- | | | |
| ups from happening; | | | |
| // the increment of the tag hash table in the FE is under a | | | |
| separate aggregator, | | | |
| // so that is serialized. | | | |
| // is a race possible? I do not believe so; the increment | | | |
| may cause a build of | | | |
| // an output tuple, but its component is already in the has | | | |
| h table for the port. | | | |
| my_join->increment_tag_count(op_data.my_tag_value); // may | | | |
| spawn | | | |
| | | | |
| } | | | |
| return op_data.status == SUCCEEDED; | | | |
| } | | | |
| | | | |
| bool get_item( T &v ) { | | bool get_item( T &v ) { | |
| tag_matching_port_operation op_data(&v, get__item); | | tag_matching_port_operation op_data(&v, get__item); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.status == SUCCEEDED; | | return op_data.status == SUCCEEDED; | |
| } | | } | |
| | | | |
| // reset_port is called when item is accepted by successor, but | | // reset_port is called when item is accepted by successor, but | |
| // is initiated by join_node. | | // is initiated by join_node. | |
| void reset_port() { | | void reset_port() { | |
| tag_matching_port_operation op_data(res_port); | | tag_matching_port_operation op_data(res_port); | |
| | | | |
| skipping to change at line 642 | | skipping to change at line 664 | |
| template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | |
| class join_node_base; | | class join_node_base; | |
| | | | |
| //! join_node_FE : implements input port policy | | //! join_node_FE : implements input port policy | |
| template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | |
| class join_node_FE; | | class join_node_FE; | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| class join_node_FE<reserving, InputTuple, OutputTuple> : public forward
ing_base { | | class join_node_FE<reserving, InputTuple, OutputTuple> : public forward
ing_base { | |
| public: | | public: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef InputTuple input_type; | | typedef InputTuple input_type; | |
| typedef join_node_base<reserving, InputTuple, OutputTuple> my_node_
type; // for forwarding | | typedef join_node_base<reserving, InputTuple, OutputTuple> my_node_
type; // for forwarding | |
| | | | |
| join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU
LL) { | | join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU
LL) { | |
| ports_with_no_inputs = N; | | ports_with_no_inputs = N; | |
| join_helper<N>::set_join_node_pointer(my_inputs, this); | | join_helper<N>::set_join_node_pointer(my_inputs, this); | |
| } | | } | |
| | | | |
| join_node_FE(const join_node_FE& other) : forwarding_base(other.my_
root_task), my_node(NULL) { | | join_node_FE(const join_node_FE& other) : forwarding_base(other.my_
root_task), my_node(NULL) { | |
| | | | |
| skipping to change at line 664 | | skipping to change at line 686 | |
| join_helper<N>::set_join_node_pointer(my_inputs, this); | | join_helper<N>::set_join_node_pointer(my_inputs, this); | |
| } | | } | |
| | | | |
| void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | |
| | | | |
| void increment_port_count() { | | void increment_port_count() { | |
| ++ports_with_no_inputs; | | ++ports_with_no_inputs; | |
| } | | } | |
| | | | |
| // if all input_ports have predecessors, spawn forward to try and c
onsume tuples | | // if all input_ports have predecessors, spawn forward to try and c
onsume tuples | |
|
| void decrement_port_count() { | | task * decrement_port_count(bool handle_task) { | |
| if(ports_with_no_inputs.fetch_and_decrement() == 1) { | | if(ports_with_no_inputs.fetch_and_decrement() == 1) { | |
|
| task::enqueue( * new ( task::allocate_additional_child_of( | | task *rtask = new ( task::allocate_additional_child_of( *(t | |
| *(this->my_root_task) ) ) | | his->my_root_task) ) ) | |
| forward_task<my_node_type>(*my_node) ); | | forward_task_bypass | |
| | | <my_node_type>(*my_node); | |
| | | if(!handle_task) return rtask; | |
| | | task::enqueue(*rtask); | |
| } | | } | |
|
| | | return NULL; | |
| } | | } | |
| | | | |
| input_type &input_ports() { return my_inputs; } | | input_type &input_ports() { return my_inputs; } | |
| | | | |
| protected: | | protected: | |
| | | | |
| void reset() { | | void reset() { | |
| // called outside of parallel contexts | | // called outside of parallel contexts | |
| ports_with_no_inputs = N; | | ports_with_no_inputs = N; | |
| join_helper<N>::reset_inputs(my_inputs); | | join_helper<N>::reset_inputs(my_inputs); | |
| | | | |
| skipping to change at line 707 | | skipping to change at line 733 | |
| } | | } | |
| | | | |
| input_type my_inputs; | | input_type my_inputs; | |
| my_node_type *my_node; | | my_node_type *my_node; | |
| atomic<size_t> ports_with_no_inputs; | | atomic<size_t> ports_with_no_inputs; | |
| }; | | }; | |
| | | | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| class join_node_FE<queueing, InputTuple, OutputTuple> : public forwardi
ng_base { | | class join_node_FE<queueing, InputTuple, OutputTuple> : public forwardi
ng_base { | |
| public: | | public: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef InputTuple input_type; | | typedef InputTuple input_type; | |
| typedef join_node_base<queueing, InputTuple, OutputTuple> my_node_t
ype; // for forwarding | | typedef join_node_base<queueing, InputTuple, OutputTuple> my_node_t
ype; // for forwarding | |
| | | | |
| join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU
LL) { | | join_node_FE(graph &g) : forwarding_base(g.root_task()), my_node(NU
LL) { | |
| ports_with_no_items = N; | | ports_with_no_items = N; | |
| join_helper<N>::set_join_node_pointer(my_inputs, this); | | join_helper<N>::set_join_node_pointer(my_inputs, this); | |
| } | | } | |
| | | | |
| join_node_FE(const join_node_FE& other) : forwarding_base(other.my_
root_task), my_node(NULL) { | | join_node_FE(const join_node_FE& other) : forwarding_base(other.my_
root_task), my_node(NULL) { | |
| | | | |
| skipping to change at line 730 | | skipping to change at line 756 | |
| } | | } | |
| | | | |
| // needed for forwarding | | // needed for forwarding | |
| void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | |
| | | | |
| void reset_port_count() { | | void reset_port_count() { | |
| ports_with_no_items = N; | | ports_with_no_items = N; | |
| } | | } | |
| | | | |
| // if all input_ports have items, spawn forward to try and consume
tuples | | // if all input_ports have items, spawn forward to try and consume
tuples | |
|
| void decrement_port_count() { | | task * decrement_port_count(bool handle_task) | |
| | | { | |
| if(ports_with_no_items.fetch_and_decrement() == 1) { | | if(ports_with_no_items.fetch_and_decrement() == 1) { | |
|
| task::enqueue( * new ( task::allocate_additional_child_of( | | task *rtask = new ( task::allocate_additional_child_of( *(t | |
| *(this->my_root_task) ) ) | | his->my_root_task) ) ) | |
| forward_task<my_node_type>(*my_node) ); | | forward_task_bypass | |
| | | <my_node_type>(*my_node); | |
| | | if(!handle_task) return rtask; | |
| | | task::enqueue( *rtask); | |
| } | | } | |
|
| | | return NULL; | |
| } | | } | |
| | | | |
| void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou
ld never be called | | void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou
ld never be called | |
| | | | |
| input_type &input_ports() { return my_inputs; } | | input_type &input_ports() { return my_inputs; } | |
| | | | |
| protected: | | protected: | |
| | | | |
| void reset() { | | void reset() { | |
| reset_port_count(); | | reset_port_count(); | |
| | | | |
| skipping to change at line 775 | | skipping to change at line 806 | |
| } | | } | |
| | | | |
| input_type my_inputs; | | input_type my_inputs; | |
| my_node_type *my_node; | | my_node_type *my_node; | |
| atomic<size_t> ports_with_no_items; | | atomic<size_t> ports_with_no_items; | |
| }; | | }; | |
| | | | |
| // tag_matching join input port. | | // tag_matching join input port. | |
| template<typename InputTuple, typename OutputTuple> | | template<typename InputTuple, typename OutputTuple> | |
| class join_node_FE<tag_matching, InputTuple, OutputTuple> : public forw
arding_base, | | class join_node_FE<tag_matching, InputTuple, OutputTuple> : public forw
arding_base, | |
|
| | | // buffer of tag value counts buffer
of output items | |
| public tagged_buffer<tag_value, size_t, NO_TAG>, public item_b
uffer<OutputTuple> { | | public tagged_buffer<tag_value, size_t, NO_TAG>, public item_b
uffer<OutputTuple> { | |
| public: | | public: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef InputTuple input_type; | | typedef InputTuple input_type; | |
| typedef tagged_buffer<tag_value, size_t, NO_TAG> my_tag_buffer; | | typedef tagged_buffer<tag_value, size_t, NO_TAG> my_tag_buffer; | |
| typedef item_buffer<output_type> output_buffer_type; | | typedef item_buffer<output_type> output_buffer_type; | |
| typedef join_node_base<tag_matching, InputTuple, OutputTuple> my_no
de_type; // for forwarding | | typedef join_node_base<tag_matching, InputTuple, OutputTuple> my_no
de_type; // for forwarding | |
| | | | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| // the aggregator is only needed to serialize the access to the has
h table. | | // the aggregator is only needed to serialize the access to the has
h table. | |
| // and the output_buffer_type base class | | // and the output_buffer_type base class | |
| private: | | private: | |
| | | | |
| skipping to change at line 799 | | skipping to change at line 831 | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef join_node_FE<tag_matching, InputTuple, OutputTuple> my_clas
s; | | typedef join_node_FE<tag_matching, InputTuple, OutputTuple> my_clas
s; | |
| | | | |
| class tag_matching_FE_operation : public aggregated_operation<tag_m
atching_FE_operation> { | | class tag_matching_FE_operation : public aggregated_operation<tag_m
atching_FE_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| union { | | union { | |
| tag_value my_val; | | tag_value my_val; | |
| output_type* my_output; | | output_type* my_output; | |
| }; | | }; | |
|
| | | task *bypass_t; | |
| | | bool enqueue_task; | |
| // constructor for value parameter | | // constructor for value parameter | |
|
| tag_matching_FE_operation(const tag_value& e, op_type t) : | | tag_matching_FE_operation(const tag_value& e , bool q_task , op | |
| // type(char(t)), my_val(const_cast<T>(e)) {} | | _type t) : type(char(t)), my_val(e), | |
| type(char(t)), my_val(e) {} | | bypass_t(NULL), enqueue_task(q_task) {} | |
| tag_matching_FE_operation(output_type *p, op_type t) : | | tag_matching_FE_operation(output_type *p, op_type t) : type(cha | |
| type(char(t)), my_output(p) {} | | r(t)), my_output(p), bypass_t(NULL), | |
| | | enqueue_task(true) {} | |
| // constructor with no parameter | | // constructor with no parameter | |
|
| tag_matching_FE_operation(op_type t) : type(char(t)) {} | | tag_matching_FE_operation(op_type t) : type(char(t)), bypass_t(
NULL), enqueue_task(true) {} | |
| }; | | }; | |
| | | | |
| typedef internal::aggregating_functor<my_class, tag_matching_FE_ope
ration> my_handler; | | typedef internal::aggregating_functor<my_class, tag_matching_FE_ope
ration> my_handler; | |
| friend class internal::aggregating_functor<my_class, tag_matching_F
E_operation>; | | friend class internal::aggregating_functor<my_class, tag_matching_F
E_operation>; | |
| aggregator<my_handler, tag_matching_FE_operation> my_aggregator; | | aggregator<my_handler, tag_matching_FE_operation> my_aggregator; | |
| | | | |
| // called from aggregator, so serialized | | // called from aggregator, so serialized | |
|
| void fill_output_buffer(bool should_enqueue) { | | // construct as many output objects as possible. | |
| | | // returns a task pointer if the a task would have been enqueued bu | |
| | | t we asked that | |
| | | // it be returned. Otherwise returns NULL. | |
| | | task * fill_output_buffer(bool should_enqueue, bool handle_task) { | |
| output_type l_out; | | output_type l_out; | |
|
| | | task *rtask = NULL; | |
| bool do_fwd = should_enqueue && this->buffer_empty(); | | bool do_fwd = should_enqueue && this->buffer_empty(); | |
|
| while(find_value_tag(this->current_tag,N)) { | | while(find_value_tag(this->current_tag,N)) { // while there ar | |
| this->tagged_delete(this->current_tag); | | e completed items | |
| | | this->tagged_delete(this->current_tag); // remove the tag | |
| if(join_helper<N>::get_items(my_inputs, l_out)) { // <==
call back | | if(join_helper<N>::get_items(my_inputs, l_out)) { // <==
call back | |
| this->push_back(l_out); | | this->push_back(l_out); | |
|
| if(do_fwd) { | | if(do_fwd) { // we enqueue if receiving an item from p | |
| task::enqueue( * new ( task::allocate_additional_ch | | redecessor, not if successor asks for item | |
| ild_of( *(this->my_root_task) ) ) | | rtask = new ( task::allocate_additional_child_of( * | |
| forward_task<my_node_type>(*my_node) ); | | (this->my_root_task) ) ) | |
| | | forward_task_bypass<my_node_type>(*my_node); | |
| | | if(handle_task) { | |
| | | task::enqueue(*rtask); | |
| | | rtask = NULL; | |
| | | } | |
| do_fwd = false; | | do_fwd = false; | |
| } | | } | |
| // retire the input values | | // retire the input values | |
| join_helper<N>::reset_ports(my_inputs); // <== call b
ack | | join_helper<N>::reset_ports(my_inputs); // <== call b
ack | |
| this->current_tag = NO_TAG; | | this->current_tag = NO_TAG; | |
| } | | } | |
| else { | | else { | |
| __TBB_ASSERT(false, "should have had something to push"
); | | __TBB_ASSERT(false, "should have had something to push"
); | |
| } | | } | |
| } | | } | |
|
| | | return rtask; | |
| } | | } | |
| | | | |
| void handle_operations(tag_matching_FE_operation* op_list) { | | void handle_operations(tag_matching_FE_operation* op_list) { | |
| tag_matching_FE_operation *current; | | tag_matching_FE_operation *current; | |
| while(op_list) { | | while(op_list) { | |
| current = op_list; | | current = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch(current->type) { | | switch(current->type) { | |
| case res_count: // called from BE | | case res_count: // called from BE | |
| { | | { | |
| output_type l_out; | | output_type l_out; | |
| this->pop_front(l_out); // don't care about return
ed value. | | this->pop_front(l_out); // don't care about return
ed value. | |
| // buffer as many tuples as we can make | | // buffer as many tuples as we can make | |
|
| fill_output_buffer(true); | | (void)fill_output_buffer(true, true); | |
| __TBB_store_with_release(current->status, SUCCEEDED
); | | __TBB_store_with_release(current->status, SUCCEEDED
); | |
| } | | } | |
| break; | | break; | |
| case inc_count: { // called from input ports | | case inc_count: { // called from input ports | |
| size_t *p = 0; | | size_t *p = 0; | |
| tag_value t = current->my_val; | | tag_value t = current->my_val; | |
|
| | | bool do_enqueue = current->enqueue_task; | |
| if(!(this->tagged_find_ref(t,p))) { | | if(!(this->tagged_find_ref(t,p))) { | |
| this->tagged_insert(t, 0); | | this->tagged_insert(t, 0); | |
| if(!(this->tagged_find_ref(t,p))) { | | if(!(this->tagged_find_ref(t,p))) { | |
|
| __TBB_ASSERT(false, NULL); | | __TBB_ASSERT(false, "should find tag after
inserting it"); | |
| } | | } | |
| } | | } | |
| if(++(*p) == size_t(N)) { | | if(++(*p) == size_t(N)) { | |
|
| task::enqueue( * new ( task::allocate_additiona | | task *rtask = fill_output_buffer(true, do_enque | |
| l_child_of( *(this->my_root_task) ) ) | | ue); | |
| forward_task<my_node_type>(*my_node) ); | | __TBB_ASSERT(!rtask || !do_enqueue, "task shoul | |
| | | d not be returned"); | |
| | | current->bypass_t = rtask; | |
| } | | } | |
| } | | } | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case may_succeed: // called from BE | | case may_succeed: // called from BE | |
|
| fill_output_buffer(false); | | (void)fill_output_buffer(false, /*handle_task*/true);
// handle_task not used | |
| __TBB_store_with_release(current->status, this->buffer_
empty() ? FAILED : SUCCEEDED); | | __TBB_store_with_release(current->status, this->buffer_
empty() ? FAILED : SUCCEEDED); | |
| break; | | break; | |
| case try_make: // called from BE | | case try_make: // called from BE | |
| if(this->buffer_empty()) { | | if(this->buffer_empty()) { | |
| __TBB_store_with_release(current->status, FAILED); | | __TBB_store_with_release(current->status, FAILED); | |
| } | | } | |
| else { | | else { | |
| this->fetch_front(*(current->my_output)); | | this->fetch_front(*(current->my_output)); | |
| __TBB_store_with_release(current->status, SUCCEEDED
); | | __TBB_store_with_release(current->status, SUCCEEDED
); | |
| } | | } | |
| | | | |
| skipping to change at line 911 | | skipping to change at line 955 | |
| // needed for forwarding | | // needed for forwarding | |
| void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | | void set_my_node(my_node_type *new_my_node) { my_node = new_my_node
; } | |
| | | | |
| void reset_port_count() { // called from BE | | void reset_port_count() { // called from BE | |
| tag_matching_FE_operation op_data(res_count); | | tag_matching_FE_operation op_data(res_count); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return; | | return; | |
| } | | } | |
| | | | |
| // if all input_ports have items, spawn forward to try and consume
tuples | | // if all input_ports have items, spawn forward to try and consume
tuples | |
|
| void increment_tag_count(tag_value t) { // called from input_ports | | // return a task if we are asked and did create one. | |
| tag_matching_FE_operation op_data(t, inc_count); | | task *increment_tag_count(tag_value t, bool handle_task) { // call | |
| | | ed from input_ports | |
| | | tag_matching_FE_operation op_data(t, handle_task, inc_count); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| return; | | return op_data.bypass_t; | |
| } | | } | |
| | | | |
|
| void decrement_port_count() { __TBB_ASSERT(false, NULL); } | | /*override*/ task *decrement_port_count(bool /*handle_task*/) { __T
BB_ASSERT(false, NULL); return NULL; } | |
| | | | |
| void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou
ld never be called | | void increment_port_count() { __TBB_ASSERT(false, NULL); } // shou
ld never be called | |
| | | | |
| input_type &input_ports() { return my_inputs; } | | input_type &input_ports() { return my_inputs; } | |
| | | | |
| protected: | | protected: | |
| | | | |
| void reset() { | | void reset() { | |
| // called outside of parallel contexts | | // called outside of parallel contexts | |
| join_helper<N>::reset_inputs(my_inputs); | | join_helper<N>::reset_inputs(my_inputs); | |
| | | | |
| skipping to change at line 966 | | skipping to change at line 1011 | |
| } | | } | |
| | | | |
| input_type my_inputs; // input ports | | input_type my_inputs; // input ports | |
| my_node_type *my_node; | | my_node_type *my_node; | |
| }; // join_node_FE<tag_matching, InputTuple, OutputTuple> | | }; // join_node_FE<tag_matching, InputTuple, OutputTuple> | |
| | | | |
| //! join_node_base | | //! join_node_base | |
| template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | | template<graph_buffer_policy JP, typename InputTuple, typename OutputTu
ple> | |
| class join_node_base : public graph_node, public join_node_FE<JP, Input
Tuple, OutputTuple>, | | class join_node_base : public graph_node, public join_node_FE<JP, Input
Tuple, OutputTuple>, | |
| public sender<OutputTuple> { | | public sender<OutputTuple> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| | | | |
| typedef receiver<output_type> successor_type; | | typedef receiver<output_type> successor_type; | |
| typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | | typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | |
| using input_ports_type::tuple_build_may_succeed; | | using input_ports_type::tuple_build_may_succeed; | |
| using input_ports_type::try_to_make_tuple; | | using input_ports_type::try_to_make_tuple; | |
| using input_ports_type::tuple_accepted; | | using input_ports_type::tuple_accepted; | |
| using input_ports_type::tuple_rejected; | | using input_ports_type::tuple_rejected; | |
| | | | |
| private: | | private: | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
|
| enum op_type { reg_succ, rem_succ, try__get, do_fwrd }; | | enum op_type { reg_succ, rem_succ, try__get, do_fwrd, do_fwrd_bypas
s }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | | typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | |
| | | | |
| class join_node_base_operation : public aggregated_operation<join_n
ode_base_operation> { | | class join_node_base_operation : public aggregated_operation<join_n
ode_base_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| union { | | union { | |
| output_type *my_arg; | | output_type *my_arg; | |
| successor_type *my_succ; | | successor_type *my_succ; | |
| }; | | }; | |
|
| join_node_base_operation(const output_type& e, op_type t) : | | task *bypass_t; | |
| type(char(t)), my_arg(const_cast<output_type*>(&e)) {} | | join_node_base_operation(const output_type& e, op_type t) : typ | |
| | | e(char(t)), | |
| | | my_arg(const_cast<output_type*>(&e)), bypass_t(NULL) {} | |
| join_node_base_operation(const successor_type &s, op_type t) :
type(char(t)), | | join_node_base_operation(const successor_type &s, op_type t) :
type(char(t)), | |
|
| my_succ(const_cast<successor_type *>(&s)) {} | | my_succ(const_cast<successor_type *>(&s)), bypass_t(NULL) { | |
| join_node_base_operation(op_type t) : type(char(t)) {} | | } | |
| | | join_node_base_operation(op_type t) : type(char(t)), bypass_t(N | |
| | | ULL) {} | |
| }; | | }; | |
| | | | |
| typedef internal::aggregating_functor<my_class, join_node_base_oper
ation> my_handler; | | typedef internal::aggregating_functor<my_class, join_node_base_oper
ation> my_handler; | |
| friend class internal::aggregating_functor<my_class, join_node_base
_operation>; | | friend class internal::aggregating_functor<my_class, join_node_base
_operation>; | |
| bool forwarder_busy; | | bool forwarder_busy; | |
| aggregator<my_handler, join_node_base_operation> my_aggregator; | | aggregator<my_handler, join_node_base_operation> my_aggregator; | |
| | | | |
| void handle_operations(join_node_base_operation* op_list) { | | void handle_operations(join_node_base_operation* op_list) { | |
| join_node_base_operation *current; | | join_node_base_operation *current; | |
| while(op_list) { | | while(op_list) { | |
| current = op_list; | | current = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch(current->type) { | | switch(current->type) { | |
| case reg_succ: | | case reg_succ: | |
| my_successors.register_successor(*(current->my_succ)); | | my_successors.register_successor(*(current->my_succ)); | |
| if(tuple_build_may_succeed() && !forwarder_busy) { | | if(tuple_build_may_succeed() && !forwarder_busy) { | |
|
| task::enqueue( * new ( task::allocate_additional_ch | | task *rtask = new ( task::allocate_additional_child | |
| ild_of(*(this->my_root_task)) ) | | _of(*(this->my_root_task)) ) | |
| forward_task<join_node_base<JP,InputTuple,O | | forward_task_bypass | |
| utputTuple> >(*this)); | | <join_node_base<JP,InputTuple,OutputTuple> | |
| | | >(*this); | |
| | | task::enqueue(*rtask); | |
| forwarder_busy = true; | | forwarder_busy = true; | |
| } | | } | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case rem_succ: | | case rem_succ: | |
| my_successors.remove_successor(*(current->my_succ)); | | my_successors.remove_successor(*(current->my_succ)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case try__get: | | case try__get: | |
| if(tuple_build_may_succeed()) { | | if(tuple_build_may_succeed()) { | |
| if(try_to_make_tuple(*(current->my_arg))) { | | if(try_to_make_tuple(*(current->my_arg))) { | |
| tuple_accepted(); | | tuple_accepted(); | |
| __TBB_store_with_release(current->status, SUCCE
EDED); | | __TBB_store_with_release(current->status, SUCCE
EDED); | |
| } | | } | |
| else __TBB_store_with_release(current->status, FAIL
ED); | | else __TBB_store_with_release(current->status, FAIL
ED); | |
| } | | } | |
| else __TBB_store_with_release(current->status, FAILED); | | else __TBB_store_with_release(current->status, FAILED); | |
| break; | | break; | |
|
| case do_fwrd: { | | case do_fwrd_bypass: { | |
| bool build_succeeded; | | bool build_succeeded; | |
|
| | | task *last_task = NULL; | |
| output_type out; | | output_type out; | |
| if(tuple_build_may_succeed()) { | | if(tuple_build_may_succeed()) { | |
| do { | | do { | |
| build_succeeded = try_to_make_tuple(out); | | build_succeeded = try_to_make_tuple(out); | |
| if(build_succeeded) { | | if(build_succeeded) { | |
|
| if(my_successors.try_put(out)) { | | task *new_task = my_successors.try_put_ | |
| | | task(out); | |
| | | last_task = combine_tasks(last_task, ne | |
| | | w_task); | |
| | | if(new_task) { | |
| tuple_accepted(); | | tuple_accepted(); | |
| } | | } | |
| else { | | else { | |
| tuple_rejected(); | | tuple_rejected(); | |
| build_succeeded = false; | | build_succeeded = false; | |
| } | | } | |
| } | | } | |
| } while(build_succeeded); | | } while(build_succeeded); | |
| } | | } | |
|
| | | current->bypass_t = last_task; | |
| __TBB_store_with_release(current->status, SUCCEEDED
); | | __TBB_store_with_release(current->status, SUCCEEDED
); | |
| forwarder_busy = false; | | forwarder_busy = false; | |
| } | | } | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ---------- end aggregator ----------- | | // ---------- end aggregator ----------- | |
| public: | | public: | |
| join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw
arder_busy(false) { | | join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw
arder_busy(false) { | |
| | | | |
| skipping to change at line 1105 | | skipping to change at line 1158 | |
| | | | |
| protected: | | protected: | |
| | | | |
| /*override*/void reset() { | | /*override*/void reset() { | |
| input_ports_type::reset(); | | input_ports_type::reset(); | |
| } | | } | |
| | | | |
| private: | | private: | |
| broadcast_cache<output_type, null_rw_mutex> my_successors; | | broadcast_cache<output_type, null_rw_mutex> my_successors; | |
| | | | |
|
| friend class forward_task< join_node_base<JP, InputTuple, OutputTup | | friend class forward_task_bypass< join_node_base<JP, InputTuple, Ou | |
| le> >; | | tputTuple> >; | |
| | | task *forward_task() { | |
| void forward() { | | join_node_base_operation op_data(do_fwrd_bypass); | |
| join_node_base_operation op_data(do_fwrd); | | | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | return op_data.bypass_t; | |
| } | | } | |
|
| | | | |
| }; | | }; | |
| | | | |
| // join base class type generator | | // join base class type generator | |
| template<int N, template<class> class PT, typename OutputTuple, graph_b
uffer_policy JP> | | template<int N, template<class> class PT, typename OutputTuple, graph_b
uffer_policy JP> | |
| struct join_base { | | struct join_base { | |
| typedef typename internal::join_node_base<JP, typename wrap_tuple_e
lements<N,PT,OutputTuple>::type, OutputTuple> type; | | typedef typename internal::join_node_base<JP, typename wrap_tuple_e
lements<N,PT,OutputTuple>::type, OutputTuple> type; | |
| }; | | }; | |
| | | | |
| //! unfolded_join_node : passes input_ports_type to join_node_base. We
build the input port type | | //! unfolded_join_node : passes input_ports_type to join_node_base. We
build the input port type | |
| // using tuple_element. The class PT is the port type (reserving_port
, queueing_port, tag_matching_port) | | // using tuple_element. The class PT is the port type (reserving_port
, queueing_port, tag_matching_port) | |
| | | | |
| skipping to change at line 1141 | | skipping to change at line 1195 | |
| unfolded_join_node(graph &g) : base_type(g) {} | | unfolded_join_node(graph &g) : base_type(g) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| | | | |
| // tag_matching unfolded_join_node. This must be a separate specializa
tion because the constructors | | // tag_matching unfolded_join_node. This must be a separate specializa
tion because the constructors | |
| // differ. | | // differ. | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<2,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<2,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<2,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<2,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<2,tag_matching_port,OutputTupl
e>::type input_ports_type; | | typedef typename wrap_tuple_elements<2,tag_matching_port,OutputTupl
e>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
|
| typedef typename std::tuple< f0_p, f1_p > func_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p > func_initializer_ty
pe; | |
| public: | | public: | |
| template<typename B0, typename B1> | | template<typename B0, typename B1> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1) | | new internal::function_body_leaf<T1, tag_value, B1>(b1) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<3,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<3,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<3,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<3,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<3, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<3, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p > func_initializer_ty
pe; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p > func_initiali
zer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2> | | template<typename B0, typename B1, typename B2> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2) | | new internal::function_body_leaf<T2, tag_value, B2>(b2) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<4,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<4,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<4,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<4,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<4, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<4, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p > func_initiali
zer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p > func_in
itializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3> | | template<typename B0, typename B1, typename B2, typename B3> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : base_typ
e(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : base_typ
e(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3) | | new internal::function_body_leaf<T3, tag_value, B3>(b3) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<5,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<5,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<5,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<5,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<5, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<5, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p > func_in
itializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p > f
unc_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) : b
ase_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) : b
ase_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4) | | new internal::function_body_leaf<T4, tag_value, B4>(b4) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| | | | |
| #if __TBB_VARIADIC_MAX >= 6 | | #if __TBB_VARIADIC_MAX >= 6 | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<6,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<6,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<6,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<6,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| typedef typename std::tuple_element<5, OutputTuple>::type T5; | | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<6, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<6, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
| typedef typename internal::function_body<T5, tag_value> *f5_p; | | typedef typename internal::function_body<T5, tag_value> *f5_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p > f
unc_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5
_p > func_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | | new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | |
| new internal::function_body_leaf<T5, tag_value, B5>(b5) | | new internal::function_body_leaf<T5, tag_value, B5>(b5) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
| #if __TBB_VARIADIC_MAX >= 7 | | #if __TBB_VARIADIC_MAX >= 7 | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<7,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<7,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<7,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<7,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| typedef typename std::tuple_element<5, OutputTuple>::type T5; | | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |
| typedef typename std::tuple_element<6, OutputTuple>::type T6; | | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<7, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<7, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
| typedef typename internal::function_body<T5, tag_value> *f5_p; | | typedef typename internal::function_body<T5, tag_value> *f5_p; | |
| typedef typename internal::function_body<T6, tag_value> *f6_p; | | typedef typename internal::function_body<T6, tag_value> *f6_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6
_p > func_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5
_p, f6_p > func_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | | new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | |
| new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | | new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | |
| new internal::function_body_leaf<T6, tag_value, B6>(b6) | | new internal::function_body_leaf<T6, tag_value, B6>(b6) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
| #if __TBB_VARIADIC_MAX >= 8 | | #if __TBB_VARIADIC_MAX >= 8 | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<8,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<8,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<8,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<8,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| typedef typename std::tuple_element<5, OutputTuple>::type T5; | | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |
| typedef typename std::tuple_element<6, OutputTuple>::type T6; | | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |
| typedef typename std::tuple_element<7, OutputTuple>::type T7; | | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<8, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<8, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
| typedef typename internal::function_body<T5, tag_value> *f5_p; | | typedef typename internal::function_body<T5, tag_value> *f5_p; | |
| typedef typename internal::function_body<T6, tag_value> *f6_p; | | typedef typename internal::function_body<T6, tag_value> *f6_p; | |
| typedef typename internal::function_body<T7, tag_value> *f7_p; | | typedef typename internal::function_body<T7, tag_value> *f7_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6
_p, f7_p > func_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5
_p, f6_p, f7_p > func_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | | new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | |
| new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | | new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | |
| | | | |
| skipping to change at line 1372 | | skipping to change at line 1426 | |
| new internal::function_body_leaf<T7, tag_value, B7>(b7) | | new internal::function_body_leaf<T7, tag_value, B7>(b7) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
| #if __TBB_VARIADIC_MAX >= 9 | | #if __TBB_VARIADIC_MAX >= 9 | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<9,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<9,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<9,tag_matching_port,OutputTuple,tag_matching>::type { | | join_base<9,tag_matching_port,OutputTuple,tag_matching>::type { | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| typedef typename std::tuple_element<5, OutputTuple>::type T5; | | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |
| typedef typename std::tuple_element<6, OutputTuple>::type T6; | | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |
| typedef typename std::tuple_element<7, OutputTuple>::type T7; | | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |
| typedef typename std::tuple_element<8, OutputTuple>::type T8; | | typedef typename tbb::flow::tuple_element<8, OutputTuple>::type T8; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<9, tag_matching_port, OutputTu
ple>::type input_ports_type; | | typedef typename wrap_tuple_elements<9, tag_matching_port, OutputTu
ple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
| typedef typename internal::function_body<T5, tag_value> *f5_p; | | typedef typename internal::function_body<T5, tag_value> *f5_p; | |
| typedef typename internal::function_body<T6, tag_value> *f6_p; | | typedef typename internal::function_body<T6, tag_value> *f6_p; | |
| typedef typename internal::function_body<T7, tag_value> *f7_p; | | typedef typename internal::function_body<T7, tag_value> *f7_p; | |
| typedef typename internal::function_body<T8, tag_value> *f8_p; | | typedef typename internal::function_body<T8, tag_value> *f8_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6
_p, f7_p, f8_p > func_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5
_p, f6_p, f7_p, f8_p > func_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7, typename B8> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7, typename B8> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7, B8 b8) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7, B8 b8) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | | new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | |
| new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | | new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | |
| | | | |
| skipping to change at line 1418 | | skipping to change at line 1472 | |
| new internal::function_body_leaf<T8, tag_value, B8>(b8) | | new internal::function_body_leaf<T8, tag_value, B8>(b8) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
| #if __TBB_VARIADIC_MAX >= 10 | | #if __TBB_VARIADIC_MAX >= 10 | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
| class unfolded_join_node<10,tag_matching_port,OutputTuple,tag_matching>
: public | | class unfolded_join_node<10,tag_matching_port,OutputTuple,tag_matching>
: public | |
| join_base<10,tag_matching_port,OutputTuple,tag_matching>::type
{ | | join_base<10,tag_matching_port,OutputTuple,tag_matching>::type
{ | |
|
| typedef typename std::tuple_element<0, OutputTuple>::type T0; | | typedef typename tbb::flow::tuple_element<0, OutputTuple>::type T0; | |
| typedef typename std::tuple_element<1, OutputTuple>::type T1; | | typedef typename tbb::flow::tuple_element<1, OutputTuple>::type T1; | |
| typedef typename std::tuple_element<2, OutputTuple>::type T2; | | typedef typename tbb::flow::tuple_element<2, OutputTuple>::type T2; | |
| typedef typename std::tuple_element<3, OutputTuple>::type T3; | | typedef typename tbb::flow::tuple_element<3, OutputTuple>::type T3; | |
| typedef typename std::tuple_element<4, OutputTuple>::type T4; | | typedef typename tbb::flow::tuple_element<4, OutputTuple>::type T4; | |
| typedef typename std::tuple_element<5, OutputTuple>::type T5; | | typedef typename tbb::flow::tuple_element<5, OutputTuple>::type T5; | |
| typedef typename std::tuple_element<6, OutputTuple>::type T6; | | typedef typename tbb::flow::tuple_element<6, OutputTuple>::type T6; | |
| typedef typename std::tuple_element<7, OutputTuple>::type T7; | | typedef typename tbb::flow::tuple_element<7, OutputTuple>::type T7; | |
| typedef typename std::tuple_element<8, OutputTuple>::type T8; | | typedef typename tbb::flow::tuple_element<8, OutputTuple>::type T8; | |
| typedef typename std::tuple_element<9, OutputTuple>::type T9; | | typedef typename tbb::flow::tuple_element<9, OutputTuple>::type T9; | |
| public: | | public: | |
| typedef typename wrap_tuple_elements<10, tag_matching_port, OutputT
uple>::type input_ports_type; | | typedef typename wrap_tuple_elements<10, tag_matching_port, OutputT
uple>::type input_ports_type; | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| private: | | private: | |
| typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | | typedef join_node_base<tag_matching, input_ports_type, output_type
> base_type; | |
| typedef typename internal::function_body<T0, tag_value> *f0_p; | | typedef typename internal::function_body<T0, tag_value> *f0_p; | |
| typedef typename internal::function_body<T1, tag_value> *f1_p; | | typedef typename internal::function_body<T1, tag_value> *f1_p; | |
| typedef typename internal::function_body<T2, tag_value> *f2_p; | | typedef typename internal::function_body<T2, tag_value> *f2_p; | |
| typedef typename internal::function_body<T3, tag_value> *f3_p; | | typedef typename internal::function_body<T3, tag_value> *f3_p; | |
| typedef typename internal::function_body<T4, tag_value> *f4_p; | | typedef typename internal::function_body<T4, tag_value> *f4_p; | |
| typedef typename internal::function_body<T5, tag_value> *f5_p; | | typedef typename internal::function_body<T5, tag_value> *f5_p; | |
| typedef typename internal::function_body<T6, tag_value> *f6_p; | | typedef typename internal::function_body<T6, tag_value> *f6_p; | |
| typedef typename internal::function_body<T7, tag_value> *f7_p; | | typedef typename internal::function_body<T7, tag_value> *f7_p; | |
| typedef typename internal::function_body<T8, tag_value> *f8_p; | | typedef typename internal::function_body<T8, tag_value> *f8_p; | |
| typedef typename internal::function_body<T9, tag_value> *f9_p; | | typedef typename internal::function_body<T9, tag_value> *f9_p; | |
|
| typedef typename std::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5_p, f6
_p, f7_p, f8_p, f9_p > func_initializer_type; | | typedef typename tbb::flow::tuple< f0_p, f1_p, f2_p, f3_p, f4_p, f5
_p, f6_p, f7_p, f8_p, f9_p > func_initializer_type; | |
| public: | | public: | |
| template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7, typename B8, typename B9> | | template<typename B0, typename B1, typename B2, typename B3, typena
me B4, typename B5, typename B6, typename B7, typename B8, typename B9> | |
| unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7, B8 b8, B9 b9) : base_type(g, | | unfolded_join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4, B5
b5, B6 b6, B7 b7, B8 b8, B9 b9) : base_type(g, | |
| func_initializer_type( | | func_initializer_type( | |
| new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | | new internal::function_body_leaf<T0, tag_value, B0>(b0)
, | |
| new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | | new internal::function_body_leaf<T1, tag_value, B1>(b1)
, | |
| new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | | new internal::function_body_leaf<T2, tag_value, B2>(b2)
, | |
| new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | | new internal::function_body_leaf<T3, tag_value, B3>(b3)
, | |
| new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | | new internal::function_body_leaf<T4, tag_value, B4>(b4)
, | |
| new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | | new internal::function_body_leaf<T5, tag_value, B5>(b5)
, | |
| | | | |
| skipping to change at line 1465 | | skipping to change at line 1519 | |
| new internal::function_body_leaf<T7, tag_value, B7>(b7)
, | | new internal::function_body_leaf<T7, tag_value, B7>(b7)
, | |
| new internal::function_body_leaf<T8, tag_value, B8>(b8)
, | | new internal::function_body_leaf<T8, tag_value, B8>(b8)
, | |
| new internal::function_body_leaf<T9, tag_value, B9>(b9) | | new internal::function_body_leaf<T9, tag_value, B9>(b9) | |
| ) ) {} | | ) ) {} | |
| unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | | unfolded_join_node(const unfolded_join_node &other) : base_type(oth
er) {} | |
| }; | | }; | |
| #endif | | #endif | |
| | | | |
| //! templated function to refer to input ports of the join node | | //! templated function to refer to input ports of the join node | |
| template<size_t N, typename JNT> | | template<size_t N, typename JNT> | |
|
| typename std::tuple_element<N, typename JNT::input_ports_type>::type &i | | typename tbb::flow::tuple_element<N, typename JNT::input_ports_type>::t | |
| nput_port(JNT &jn) { | | ype &input_port(JNT &jn) { | |
| return std::get<N>(jn.input_ports()); | | return tbb::flow::get<N>(jn.input_ports()); | |
| } | | } | |
| | | | |
| } | | } | |
| #endif // __TBB__flow_graph_join_impl_H | | #endif // __TBB__flow_graph_join_impl_H | |
| | | | |
End of changes. 92 change blocks. |
| 199 lines changed or deleted | | 270 lines changed or added | |
|
| _flow_graph_node_impl.h | | _flow_graph_node_impl.h | |
| | | | |
| skipping to change at line 64 | | skipping to change at line 64 | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Input and scheduling for a function node that takes a type Input as
input | | //! Input and scheduling for a function node that takes a type Input as
input | |
| // The only up-ref is apply_body_impl, which should implement the func
tion | | // The only up-ref is apply_body_impl, which should implement the func
tion | |
| // call and any handling of the result. | | // call and any handling of the result. | |
| template< typename Input, typename A, typename ImplType > | | template< typename Input, typename A, typename ImplType > | |
| class function_input_base : public receiver<Input>, tbb::internal::no_a
ssign { | | class function_input_base : public receiver<Input>, tbb::internal::no_a
ssign { | |
| typedef sender<Input> predecessor_type; | | typedef sender<Input> predecessor_type; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
|
| enum op_type {reg_pred, rem_pred, app_body, tryput, try_fwd}; | | enum op_type {reg_pred, rem_pred, app_body, try_fwd, tryput_bypass,
app_body_bypass }; | |
| typedef function_input_base<Input, A, ImplType> my_class; | | typedef function_input_base<Input, A, ImplType> my_class; | |
| | | | |
| public: | | public: | |
| | | | |
| //! The input type of this receiver | | //! The input type of this receiver | |
| typedef Input input_type; | | typedef Input input_type; | |
| | | | |
| //! Constructor for function_input_base | | //! Constructor for function_input_base | |
| function_input_base( graph &g, size_t max_concurrency, function_inp
ut_queue<input_type,A> *q = NULL ) | | function_input_base( graph &g, size_t max_concurrency, function_inp
ut_queue<input_type,A> *q = NULL ) | |
| : my_root_task(g.root_task()), my_max_concurrency(max_concurren
cy), my_concurrency(0), | | : my_root_task(g.root_task()), my_max_concurrency(max_concurren
cy), my_concurrency(0), | |
| | | | |
| skipping to change at line 95 | | skipping to change at line 95 | |
| { | | { | |
| my_predecessors.set_owner(this); | | my_predecessors.set_owner(this); | |
| my_aggregator.initialize_handler(my_handler(this)); | | my_aggregator.initialize_handler(my_handler(this)); | |
| } | | } | |
| | | | |
| //! Destructor | | //! Destructor | |
| virtual ~function_input_base() { | | virtual ~function_input_base() { | |
| if ( my_queue ) delete my_queue; | | if ( my_queue ) delete my_queue; | |
| } | | } | |
| | | | |
|
| //! Put to the node | | //! Put to the node, returning a task if available | |
| virtual bool try_put( const input_type &t ) { | | virtual task * try_put_task( const input_type &t ) { | |
| if ( my_max_concurrency == 0 ) { | | if ( my_max_concurrency == 0 ) { | |
|
| spawn_body_task( t ); | | return create_body_task( t ); | |
| return true; | | | |
| } else { | | } else { | |
|
| my_operation op_data(t, tryput); | | my_operation op_data(t, tryput_bypass); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| return op_data.status == SUCCEEDED; | | if(op_data.status == SUCCEEDED ) { | |
| | | return op_data.bypass_t; | |
| | | } | |
| | | return NULL; | |
| } | | } | |
| } | | } | |
| | | | |
| //! Adds src to the list of cached predecessors. | | //! Adds src to the list of cached predecessors. | |
| /* override */ bool register_predecessor( predecessor_type &src ) { | | /* override */ bool register_predecessor( predecessor_type &src ) { | |
| my_operation op_data(reg_pred); | | my_operation op_data(reg_pred); | |
| op_data.r = &src; | | op_data.r = &src; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| skipping to change at line 145 | | skipping to change at line 147 | |
| size_t my_concurrency; | | size_t my_concurrency; | |
| function_input_queue<input_type, A> *my_queue; | | function_input_queue<input_type, A> *my_queue; | |
| predecessor_cache<input_type, null_mutex > my_predecessors; | | predecessor_cache<input_type, null_mutex > my_predecessors; | |
| | | | |
| /*override*/void reset_receiver() { | | /*override*/void reset_receiver() { | |
| my_predecessors.reset(); | | my_predecessors.reset(); | |
| } | | } | |
| | | | |
| private: | | private: | |
| | | | |
|
| friend class apply_body_task< my_class, input_type >; | | friend class apply_body_task_bypass< my_class, input_type >; | |
| friend class forward_task< my_class >; | | friend class forward_task_bypass< my_class >; | |
| | | | |
| class my_operation : public aggregated_operation< my_operation > { | | class my_operation : public aggregated_operation< my_operation > { | |
| public: | | public: | |
| char type; | | char type; | |
| union { | | union { | |
| input_type *elem; | | input_type *elem; | |
| predecessor_type *r; | | predecessor_type *r; | |
| }; | | }; | |
|
| | | tbb::task *bypass_t; | |
| my_operation(const input_type& e, op_type t) : | | my_operation(const input_type& e, op_type t) : | |
| type(char(t)), elem(const_cast<input_type*>(&e)) {} | | type(char(t)), elem(const_cast<input_type*>(&e)) {} | |
| my_operation(op_type t) : type(char(t)), r(NULL) {} | | my_operation(op_type t) : type(char(t)), r(NULL) {} | |
| }; | | }; | |
| | | | |
| bool forwarder_busy; | | bool forwarder_busy; | |
| typedef internal::aggregating_functor<my_class, my_operation> my_ha
ndler; | | typedef internal::aggregating_functor<my_class, my_operation> my_ha
ndler; | |
| friend class internal::aggregating_functor<my_class, my_operation>; | | friend class internal::aggregating_functor<my_class, my_operation>; | |
| aggregator< my_handler, my_operation > my_aggregator; | | aggregator< my_handler, my_operation > my_aggregator; | |
| | | | |
| | | | |
| skipping to change at line 200 | | skipping to change at line 203 | |
| if ( my_queue ) | | if ( my_queue ) | |
| item_was_retrieved = my_queue->pop(i); | | item_was_retrieved = my_queue->pop(i); | |
| else | | else | |
| item_was_retrieved = my_predecessors.get_item(i
); | | item_was_retrieved = my_predecessors.get_item(i
); | |
| if (item_was_retrieved) { | | if (item_was_retrieved) { | |
| ++my_concurrency; | | ++my_concurrency; | |
| spawn_body_task(i); | | spawn_body_task(i); | |
| } | | } | |
| } | | } | |
| break; | | break; | |
|
| case tryput: internal_try_put(tmp); break; | | case app_body_bypass: { | |
| | | task * new_task = NULL; | |
| | | __TBB_ASSERT(my_max_concurrency != 0, NULL); | |
| | | --my_concurrency; | |
| | | if (my_concurrency<my_max_concurrency) { | |
| | | input_type i; | |
| | | bool item_was_retrieved = false; | |
| | | if ( my_queue ) | |
| | | item_was_retrieved = my_queue->pop(i); | |
| | | else | |
| | | item_was_retrieved = my_predecessors.get_it | |
| | | em(i); | |
| | | if (item_was_retrieved) { | |
| | | ++my_concurrency; | |
| | | new_task = create_body_task(i); | |
| | | } | |
| | | } | |
| | | tmp->bypass_t = new_task; | |
| | | __TBB_store_with_release(tmp->status, SUCCEEDED); | |
| | | } | |
| | | break; | |
| | | case tryput_bypass: internal_try_put_task(tmp); break; | |
| case try_fwd: internal_forward(tmp); break; | | case try_fwd: internal_forward(tmp); break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| //! Put to the node | | //! Put to the node, but return the task instead of enqueueing it | |
| void internal_try_put(my_operation *op) { | | void internal_try_put_task(my_operation *op) { | |
| __TBB_ASSERT(my_max_concurrency != 0, NULL); | | __TBB_ASSERT(my_max_concurrency != 0, NULL); | |
| if (my_concurrency < my_max_concurrency) { | | if (my_concurrency < my_max_concurrency) { | |
| ++my_concurrency; | | ++my_concurrency; | |
|
| spawn_body_task(*(op->elem)); | | task * new_task = create_body_task(*(op->elem)); | |
| | | op->bypass_t = new_task; | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } else if ( my_queue && my_queue->push(*(op->elem)) ) { | | } else if ( my_queue && my_queue->push(*(op->elem)) ) { | |
|
| | | op->bypass_t = SUCCESSFULLY_ENQUEUED; | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } else { | | } else { | |
|
| | | op->bypass_t = NULL; | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| } | | } | |
| } | | } | |
| | | | |
| //! Tries to spawn bodies if available and if concurrency allows | | //! Tries to spawn bodies if available and if concurrency allows | |
| void internal_forward(my_operation *op) { | | void internal_forward(my_operation *op) { | |
|
| | | op->bypass_t = NULL; | |
| if (my_concurrency<my_max_concurrency || !my_max_concurrency) { | | if (my_concurrency<my_max_concurrency || !my_max_concurrency) { | |
| input_type i; | | input_type i; | |
| bool item_was_retrieved = false; | | bool item_was_retrieved = false; | |
| if ( my_queue ) | | if ( my_queue ) | |
| item_was_retrieved = my_queue->pop(i); | | item_was_retrieved = my_queue->pop(i); | |
| else | | else | |
| item_was_retrieved = my_predecessors.get_item(i); | | item_was_retrieved = my_predecessors.get_item(i); | |
| if (item_was_retrieved) { | | if (item_was_retrieved) { | |
| ++my_concurrency; | | ++my_concurrency; | |
|
| | | op->bypass_t = create_body_task(i); | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
|
| spawn_body_task(i); | | | |
| return; | | return; | |
| } | | } | |
| } | | } | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| forwarder_busy = false; | | forwarder_busy = false; | |
| } | | } | |
| | | | |
| //! Applies the body to the provided input | | //! Applies the body to the provided input | |
|
| | | // then decides if more work is available | |
| void apply_body( input_type &i ) { | | void apply_body( input_type &i ) { | |
|
| static_cast<ImplType *>(this)->apply_body_impl(i); | | task *new_task = apply_body_bypass(i); | |
| | | if(!new_task) return; | |
| | | if(new_task == SUCCESSFULLY_ENQUEUED) return; | |
| | | task::enqueue(*new_task); | |
| | | return; | |
| | | } | |
| | | | |
| | | //! Applies the body to the provided input | |
| | | // then decides if more work is available | |
| | | // we should still be able to use app_body, because the task retur | |
| | | ned should be the successor node | |
| | | // and not us, so we are reducing my_concurrency. (might be a pro | |
| | | blem if we are our own successor?) | |
| | | task * apply_body_bypass( input_type &i ) { | |
| | | task * new_task = static_cast<ImplType *>(this)->apply_body_imp | |
| | | l_bypass(i); | |
| if ( my_max_concurrency != 0 ) { | | if ( my_max_concurrency != 0 ) { | |
|
| my_operation op_data(app_body); | | my_operation op_data(app_body_bypass); // tries to pop an
item or get_item, enqueues another apply_body | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | tbb::task *ttask = op_data.bypass_t; | |
| | | new_task = combine_tasks(new_task, ttask); | |
| } | | } | |
|
| | | return new_task; | |
| } | | } | |
| | | | |
|
| | | //! allocates a task to call apply_body( input ) | |
| | | inline task * create_body_task( const input_type &input ) { | |
| | | return new(task::allocate_additional_child_of(*my_root_task)) | |
| | | apply_body_task_bypass < my_class, input_type >(*this, input | |
| | | ); | |
| | | } | |
| | | | |
| //! Spawns a task that calls apply_body( input ) | | //! Spawns a task that calls apply_body( input ) | |
| inline void spawn_body_task( const input_type &input ) { | | inline void spawn_body_task( const input_type &input ) { | |
|
| task::enqueue(*new(task::allocate_additional_child_of(*my_root_t
ask)) apply_body_task< my_class, input_type >(*this, input)); | | task::enqueue(*create_body_task(input)); | |
| } | | } | |
| | | | |
| //! This is executed by an enqueued task, the "forwarder" | | //! This is executed by an enqueued task, the "forwarder" | |
|
| void forward() { | | task *forward_task() { | |
| my_operation op_data(try_fwd); | | my_operation op_data(try_fwd); | |
|
| | | task *rval = NULL; | |
| do { | | do { | |
| op_data.status = WAIT; | | op_data.status = WAIT; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | if(op_data.status == SUCCEEDED) { | |
| | | tbb::task *ttask = op_data.bypass_t; | |
| | | rval = combine_tasks(rval, ttask); | |
| | | } | |
| } while (op_data.status == SUCCEEDED); | | } while (op_data.status == SUCCEEDED); | |
|
| | | return rval; | |
| | | } | |
| | | | |
| | | inline task *create_forward_task() { | |
| | | task *rval = new(task::allocate_additional_child_of(*my_root_tas | |
| | | k)) forward_task_bypass< my_class >(*this); | |
| | | return rval; | |
| } | | } | |
| | | | |
| //! Spawns a task that calls forward() | | //! Spawns a task that calls forward() | |
| inline void spawn_forward_task() { | | inline void spawn_forward_task() { | |
|
| task::enqueue(*new(task::allocate_additional_child_of(*my_root_t
ask)) forward_task< my_class >(*this)); | | task::enqueue(*create_forward_task()); | |
| } | | } | |
| }; // function_input_base | | }; // function_input_base | |
| | | | |
| //! Implements methods for a function node that takes a type Input as i
nput and sends | | //! Implements methods for a function node that takes a type Input as i
nput and sends | |
| // a type Output to its successors. | | // a type Output to its successors. | |
| template< typename Input, typename Output, typename A> | | template< typename Input, typename Output, typename A> | |
| class function_input : public function_input_base<Input, A, function_in
put<Input,Output,A> > { | | class function_input : public function_input_base<Input, A, function_in
put<Input,Output,A> > { | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| | | | |
| skipping to change at line 303 | | skipping to change at line 363 | |
| ~function_input() { | | ~function_input() { | |
| delete my_body; | | delete my_body; | |
| } | | } | |
| | | | |
| template< typename Body > | | template< typename Body > | |
| Body copy_function_object() { | | Body copy_function_object() { | |
| internal::function_body<input_type, output_type> &body_ref = *t
his->my_body; | | internal::function_body<input_type, output_type> &body_ref = *t
his->my_body; | |
| return dynamic_cast< internal::function_body_leaf<input_type, o
utput_type, Body> & >(body_ref).get_body(); | | return dynamic_cast< internal::function_body_leaf<input_type, o
utput_type, Body> & >(body_ref).get_body(); | |
| } | | } | |
| | | | |
|
| void apply_body_impl( const input_type &i) { | | task * apply_body_impl_bypass( const input_type &i) { | |
| successors().try_put( (*my_body)(i) ); | | task * new_task = successors().try_put_task( (*my_body)(i) ); | |
| | | return new_task; | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| | | | |
| void reset_function_input() { | | void reset_function_input() { | |
| base_type::reset_function_input_base(); | | base_type::reset_function_input_base(); | |
| } | | } | |
| | | | |
| function_body<input_type, output_type> *my_body; | | function_body<input_type, output_type> *my_body; | |
| virtual broadcast_cache<output_type > &successors() = 0; | | virtual broadcast_cache<output_type > &successors() = 0; | |
| | | | |
| skipping to change at line 356 | | skipping to change at line 417 | |
| ~multifunction_input() { | | ~multifunction_input() { | |
| delete my_body; | | delete my_body; | |
| } | | } | |
| | | | |
| template< typename Body > | | template< typename Body > | |
| Body copy_function_object() { | | Body copy_function_object() { | |
| internal::multifunction_body<input_type, output_ports_type> &bo
dy_ref = *this->my_body; | | internal::multifunction_body<input_type, output_ports_type> &bo
dy_ref = *this->my_body; | |
| return dynamic_cast< internal::multifunction_body_leaf<input_ty
pe, output_ports_type, Body> & >(body_ref).get_body(); | | return dynamic_cast< internal::multifunction_body_leaf<input_ty
pe, output_ports_type, Body> & >(body_ref).get_body(); | |
| } | | } | |
| | | | |
|
| void apply_body_impl( const input_type &i) { | | // for multifunction nodes we do not have a single successor as suc | |
| | | h. So we just tell | |
| | | // the task we were successful. | |
| | | task * apply_body_impl_bypass( const input_type &i) { | |
| (*my_body)(i, my_output_ports); | | (*my_body)(i, my_output_ports); | |
|
| | | task * new_task = SUCCESSFULLY_ENQUEUED; | |
| | | return new_task; | |
| } | | } | |
| | | | |
| output_ports_type &output_ports(){ return my_output_ports; } | | output_ports_type &output_ports(){ return my_output_ports; } | |
| | | | |
| protected: | | protected: | |
| | | | |
| void reset() { | | void reset() { | |
| base_type::reset_function_input_base(); | | base_type::reset_function_input_base(); | |
| } | | } | |
| | | | |
| multifunction_body<input_type, output_ports_type> *my_body; | | multifunction_body<input_type, output_ports_type> *my_body; | |
| output_ports_type my_output_ports; | | output_ports_type my_output_ports; | |
| | | | |
| }; | | }; | |
| | | | |
| // template to refer to an output port of a multifunction_node | | // template to refer to an output port of a multifunction_node | |
| template<size_t N, typename MOP> | | template<size_t N, typename MOP> | |
|
| typename std::tuple_element<N, typename MOP::output_ports_type>::type & | | typename tbb::flow::tuple_element<N, typename MOP::output_ports_type>:: | |
| output_port(MOP &op) { | | type &output_port(MOP &op) { | |
| return std::get<N>(op.output_ports()); | | return tbb::flow::get<N>(op.output_ports()); | |
| } | | } | |
| | | | |
| // helper structs for split_node | | // helper structs for split_node | |
| template<int N> | | template<int N> | |
| struct emit_element { | | struct emit_element { | |
| template<typename T, typename P> | | template<typename T, typename P> | |
| static void emit_this(const T &t, P &p) { | | static void emit_this(const T &t, P &p) { | |
|
| (void)std::get<N-1>(p).try_put(std::get<N-1>(t)); | | (void)tbb::flow::get<N-1>(p).try_put(tbb::flow::get<N-1>(t)); | |
| emit_element<N-1>::emit_this(t,p); | | emit_element<N-1>::emit_this(t,p); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template<> | | template<> | |
| struct emit_element<1> { | | struct emit_element<1> { | |
| template<typename T, typename P> | | template<typename T, typename P> | |
| static void emit_this(const T &t, P &p) { | | static void emit_this(const T &t, P &p) { | |
|
| (void)std::get<0>(p).try_put(std::get<0>(t)); | | (void)tbb::flow::get<0>(p).try_put(tbb::flow::get<0>(t)); | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Implements methods for an executable node that takes continue_msg a
s input | | //! Implements methods for an executable node that takes continue_msg a
s input | |
| template< typename Output > | | template< typename Output > | |
| class continue_input : public continue_receiver { | | class continue_input : public continue_receiver { | |
| public: | | public: | |
| | | | |
| //! The input type of this receiver | | //! The input type of this receiver | |
| typedef continue_msg input_type; | | typedef continue_msg input_type; | |
| | | | |
| skipping to change at line 434 | | skipping to change at line 499 | |
| return dynamic_cast< internal::function_body_leaf<input_type, o
utput_type, Body> & >(body_ref).get_body(); | | return dynamic_cast< internal::function_body_leaf<input_type, o
utput_type, Body> & >(body_ref).get_body(); | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| | | | |
| task *my_root_task; | | task *my_root_task; | |
| function_body<input_type, output_type> *my_body; | | function_body<input_type, output_type> *my_body; | |
| | | | |
| virtual broadcast_cache<output_type > &successors() = 0; | | virtual broadcast_cache<output_type > &successors() = 0; | |
| | | | |
|
| friend class apply_body_task< continue_input< Output >, continue_ms
g >; | | friend class apply_body_task_bypass< continue_input< Output >, cont
inue_msg >; | |
| | | | |
| //! Applies the body to the provided input | | //! Applies the body to the provided input | |
|
| /* override */ void apply_body( input_type ) { | | /* override */ task *apply_body_bypass( input_type ) { | |
| successors().try_put( (*my_body)( continue_msg() ) ); | | return successors().try_put_task( (*my_body)( continue_msg() ) | |
| | | ); | |
| } | | } | |
| | | | |
| //! Spawns a task that applies the body | | //! Spawns a task that applies the body | |
|
| /* override */ void execute( ) { | | /* override */ task *execute( ) { | |
| task::enqueue( * new ( task::allocate_additional_child_of( *my_ | | task *res = new ( task::allocate_additional_child_of( *my_root_ | |
| root_task ) ) | | task ) ) | |
| apply_body_task< continue_input< Output >, continue_msg >( * | | apply_body_task_bypass< continue_input< Output >, continue_ | |
| this, continue_msg() ) ); | | msg >( *this, continue_msg() ); | |
| | | return res; | |
| } | | } | |
| | | | |
| }; | | }; | |
| | | | |
| //! Implements methods for both executable and function nodes that puts
Output to its successors | | //! Implements methods for both executable and function nodes that puts
Output to its successors | |
| template< typename Output > | | template< typename Output > | |
| class function_output : public sender<Output> { | | class function_output : public sender<Output> { | |
| public: | | public: | |
| | | | |
| typedef Output output_type; | | typedef Output output_type; | |
| | | | |
| skipping to change at line 480 | | skipping to change at line 546 | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| // for multifunction_node. The function_body that implements | | // for multifunction_node. The function_body that implements | |
| // the node will have an input and an output tuple of ports. To pu
t | | // the node will have an input and an output tuple of ports. To pu
t | |
| // an item to a successor, the body should | | // an item to a successor, the body should | |
| // | | // | |
| // get<I>(output_ports).try_put(output_value); | | // get<I>(output_ports).try_put(output_value); | |
| // | | // | |
| // return value will be bool returned from successors.try_put. | | // return value will be bool returned from successors.try_put. | |
|
| bool try_put(const output_type &i) { return my_successors.try_put(i
); } | | task *try_put_task(const output_type &i) { return my_successors.try
_put_task(i); } | |
| | | | |
| protected: | | protected: | |
| broadcast_cache<output_type> my_successors; | | broadcast_cache<output_type> my_successors; | |
| broadcast_cache<output_type > &successors() { return my_successors;
} | | broadcast_cache<output_type > &successors() { return my_successors;
} | |
| | | | |
| }; | | }; | |
| | | | |
|
| | | template< typename Output > | |
| | | class multifunction_output : public function_output<Output> { | |
| | | public: | |
| | | typedef Output output_type; | |
| | | typedef function_output<output_type> base_type; | |
| | | using base_type::my_successors; | |
| | | | |
| | | multifunction_output() : base_type() {my_successors.set_owner(this) | |
| | | ;} | |
| | | multifunction_output( const multifunction_output &/*other*/) : base | |
| | | _type() { my_successors.set_owner(this); } | |
| | | | |
| | | bool try_put(const output_type &i) { | |
| | | task *res = my_successors.try_put_task(i); | |
| | | if(!res) return false; | |
| | | if(res != SUCCESSFULLY_ENQUEUED) task::enqueue(*res); | |
| | | return true; | |
| | | } | |
| | | }; | |
| | | | |
| } // internal | | } // internal | |
| | | | |
| #endif // __TBB__flow_graph_node_impl_H | | #endif // __TBB__flow_graph_node_impl_H | |
| | | | |
End of changes. 38 change blocks. |
| 36 lines changed or deleted | | 130 lines changed or added | |
|
| flow_graph.h | | flow_graph.h | |
| | | | |
| skipping to change at line 45 | | skipping to change at line 45 | |
| #include "null_mutex.h" | | #include "null_mutex.h" | |
| #include "spin_rw_mutex.h" | | #include "spin_rw_mutex.h" | |
| #include "null_rw_mutex.h" | | #include "null_rw_mutex.h" | |
| #include "task.h" | | #include "task.h" | |
| #include "concurrent_vector.h" | | #include "concurrent_vector.h" | |
| #include "internal/_aggregator_impl.h" | | #include "internal/_aggregator_impl.h" | |
| | | | |
| // use the VC10 or gcc version of tuple if it is available. | | // use the VC10 or gcc version of tuple if it is available. | |
| #if __TBB_CPP11_TUPLE_PRESENT | | #if __TBB_CPP11_TUPLE_PRESENT | |
| #include <tuple> | | #include <tuple> | |
|
| | | namespace tbb { | |
| | | namespace flow { | |
| | | using std::tuple; | |
| | | using std::tuple_size; | |
| | | using std::tuple_element; | |
| | | using std::get; | |
| | | } | |
| | | } | |
| #else | | #else | |
| #include "compat/tuple" | | #include "compat/tuple" | |
| #endif | | #endif | |
| | | | |
| #include<list> | | #include<list> | |
| #include<queue> | | #include<queue> | |
| | | | |
| /** @file | | /** @file | |
| \brief The graph related classes and functions | | \brief The graph related classes and functions | |
| | | | |
| | | | |
| skipping to change at line 71 | | skipping to change at line 79 | |
| | | | |
| namespace tbb { | | namespace tbb { | |
| namespace flow { | | namespace flow { | |
| | | | |
| //! An enumeration the provides the two most common concurrency levels: unl
imited and serial | | //! An enumeration the provides the two most common concurrency levels: unl
imited and serial | |
| enum concurrency { unlimited = 0, serial = 1 }; | | enum concurrency { unlimited = 0, serial = 1 }; | |
| | | | |
| namespace interface6 { | | namespace interface6 { | |
| | | | |
| namespace internal { | | namespace internal { | |
|
| template<typename T, typename M> | | template<typename T, typename M> class successor_cache; | |
| class successor_cache; | | template<typename T, typename M> class broadcast_cache; | |
| | | template<typename T, typename M> class round_robin_cache; | |
| } | | } | |
| | | | |
| //! An empty class used for messages that mean "I'm done" | | //! An empty class used for messages that mean "I'm done" | |
| class continue_msg {}; | | class continue_msg {}; | |
| | | | |
| template< typename T > class sender; | | template< typename T > class sender; | |
| template< typename T > class receiver; | | template< typename T > class receiver; | |
| class continue_receiver; | | class continue_receiver; | |
| | | | |
| //! Pure virtual template class that defines a sender of messages of type T | | //! Pure virtual template class that defines a sender of messages of type T | |
| | | | |
| skipping to change at line 114 | | skipping to change at line 123 | |
| virtual bool try_reserve( T & ) { return false; } | | virtual bool try_reserve( T & ) { return false; } | |
| | | | |
| //! Releases the reserved item | | //! Releases the reserved item | |
| virtual bool try_release( ) { return false; } | | virtual bool try_release( ) { return false; } | |
| | | | |
| //! Consumes the reserved item | | //! Consumes the reserved item | |
| virtual bool try_consume( ) { return false; } | | virtual bool try_consume( ) { return false; } | |
| }; | | }; | |
| | | | |
| template< typename T > class limiter_node; // needed for resetting decreme
nter | | template< typename T > class limiter_node; // needed for resetting decreme
nter | |
|
| | | template< typename R, typename B > class run_and_put_task; | |
| | | | |
| | | static tbb::task * const SUCCESSFULLY_ENQUEUED = (task *)-1; | |
| | | | |
| | | // enqueue left task if necessary. Returns the non-enqueued task if there | |
| | | is one. | |
| | | static inline tbb::task *combine_tasks( tbb::task * left, tbb::task * right | |
| | | ) { | |
| | | // if no RHS task, don't change left. | |
| | | if(right == NULL) return left; | |
| | | // right != NULL | |
| | | if(left == NULL) return right; | |
| | | if(left == SUCCESSFULLY_ENQUEUED) return right; | |
| | | // left contains a task | |
| | | if(right != SUCCESSFULLY_ENQUEUED) { | |
| | | // both are valid tasks | |
| | | tbb::task::enqueue(*left); | |
| | | return right; | |
| | | } | |
| | | return left; | |
| | | } | |
| | | | |
| //! Pure virtual template class that defines a receiver of messages of type
T | | //! Pure virtual template class that defines a receiver of messages of type
T | |
| template< typename T > | | template< typename T > | |
| class receiver { | | class receiver { | |
| public: | | public: | |
| //! The input type of this receiver | | //! The input type of this receiver | |
| typedef T input_type; | | typedef T input_type; | |
| | | | |
| //! The predecessor type for this node | | //! The predecessor type for this node | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| | | | |
| //! Destructor | | //! Destructor | |
| virtual ~receiver() {} | | virtual ~receiver() {} | |
| | | | |
| //! Put an item to the receiver | | //! Put an item to the receiver | |
|
| virtual bool try_put( const T& t ) = 0; | | bool try_put( const T& t ) { | |
| | | task *res = try_put_task(t); | |
| | | if(!res) return false; | |
| | | if (res != SUCCESSFULLY_ENQUEUED) task::enqueue(*res); | |
| | | return true; | |
| | | } | |
| | | | |
| | | //! put item to successor; return task to run the successor if possible | |
| | | . | |
| | | protected: | |
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | virtual task *try_put_task(const T& t) = 0; | |
| | | public: | |
| | | | |
| //! Add a predecessor to the node | | //! Add a predecessor to the node | |
| virtual bool register_predecessor( predecessor_type & ) { return false;
} | | virtual bool register_predecessor( predecessor_type & ) { return false;
} | |
| | | | |
| //! Remove a predecessor from the node | | //! Remove a predecessor from the node | |
| virtual bool remove_predecessor( predecessor_type & ) { return false; } | | virtual bool remove_predecessor( predecessor_type & ) { return false; } | |
| | | | |
| protected: | | protected: | |
| //! put receiver back in initial state | | //! put receiver back in initial state | |
| template<typename U> friend class limiter_node; | | template<typename U> friend class limiter_node; | |
| virtual void reset_receiver() = 0; | | virtual void reset_receiver() = 0; | |
|
| | | | |
| template<typename TT, typename M> | | template<typename TT, typename M> | |
|
| friend class internal::successor_cache; | | friend class internal::successor_cache; | |
| virtual bool is_continue_receiver() { return false; } | | virtual bool is_continue_receiver() { return false; } | |
| }; | | }; | |
| | | | |
| //! Base class for receivers of completion messages | | //! Base class for receivers of completion messages | |
| /** These receivers automatically reset, but cannot be explicitly waited on
*/ | | /** These receivers automatically reset, but cannot be explicitly waited on
*/ | |
| class continue_receiver : public receiver< continue_msg > { | | class continue_receiver : public receiver< continue_msg > { | |
| public: | | public: | |
| | | | |
| //! The input type | | //! The input type | |
| typedef continue_msg input_type; | | typedef continue_msg input_type; | |
| | | | |
| skipping to change at line 189 | | skipping to change at line 231 | |
| //! Decrements the trigger threshold | | //! Decrements the trigger threshold | |
| /** Does not check to see if the removal of the predecessor now makes t
he current count | | /** Does not check to see if the removal of the predecessor now makes t
he current count | |
| exceed the new threshold. So removing a predecessor while the grap
h is active can cause | | exceed the new threshold. So removing a predecessor while the grap
h is active can cause | |
| unexpected results. */ | | unexpected results. */ | |
| /* override */ bool remove_predecessor( predecessor_type & ) { | | /* override */ bool remove_predecessor( predecessor_type & ) { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| --my_predecessor_count; | | --my_predecessor_count; | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| //! Puts a continue_msg to the receiver | | protected: | |
| /** If the message causes the message count to reach the predecessor co | | template< typename R, typename B > friend class run_and_put_task; | |
| unt, execute() is called and | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| the message count is reset to 0. Otherwise the message count is in | | ; | |
| cremented. */ | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| /* override */ bool try_put( const input_type & ) { | | he; | |
| | | // execute body is supposed to be too small to create a task for. | |
| | | /* override */ task *try_put_task( const input_type & ) { | |
| { | | { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| if ( ++my_current_count < my_predecessor_count ) | | if ( ++my_current_count < my_predecessor_count ) | |
|
| return true; | | return SUCCESSFULLY_ENQUEUED; | |
| else | | else | |
| my_current_count = 0; | | my_current_count = 0; | |
| } | | } | |
|
| execute(); | | task * res = execute(); | |
| return true; | | return res; | |
| } | | } | |
| | | | |
|
| protected: | | | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| int my_predecessor_count; | | int my_predecessor_count; | |
| int my_current_count; | | int my_current_count; | |
| int my_initial_predecessor_count; | | int my_initial_predecessor_count; | |
| // the friend declaration in the base class did not eliminate the "prot
ected class" | | // the friend declaration in the base class did not eliminate the "prot
ected class" | |
| // error in gcc 4.1.2 | | // error in gcc 4.1.2 | |
| template<typename U> friend class limiter_node; | | template<typename U> friend class limiter_node; | |
| /*override*/void reset_receiver() { | | /*override*/void reset_receiver() { | |
| my_current_count = 0; | | my_current_count = 0; | |
| } | | } | |
| | | | |
| //! Does whatever should happen when the threshold is reached | | //! Does whatever should happen when the threshold is reached | |
| /** This should be very fast or else spawn a task. This is | | /** This should be very fast or else spawn a task. This is | |
| called while the sender is blocked in the try_put(). */ | | called while the sender is blocked in the try_put(). */ | |
|
| virtual void execute() = 0; | | virtual task * execute() = 0; | |
| template<typename TT, typename M> | | template<typename TT, typename M> | |
|
| friend class internal::successor_cache; | | friend class internal::successor_cache; | |
| /*override*/ bool is_continue_receiver() { return true; } | | /*override*/ bool is_continue_receiver() { return true; } | |
| }; | | }; | |
| | | | |
| #include "internal/_flow_graph_impl.h" | | #include "internal/_flow_graph_impl.h" | |
| using namespace internal::graph_policy_namespace; | | using namespace internal::graph_policy_namespace; | |
| | | | |
| class graph; | | class graph; | |
| class graph_node; | | class graph_node; | |
| | | | |
| template <typename GraphContainerType, typename GraphNodeType> | | template <typename GraphContainerType, typename GraphNodeType> | |
| | | | |
| skipping to change at line 320 | | skipping to change at line 363 | |
| } | | } | |
| private: | | private: | |
| Body my_body; | | Body my_body; | |
| }; | | }; | |
| | | | |
| template< typename Receiver, typename Body > | | template< typename Receiver, typename Body > | |
| class run_and_put_task : public task { | | class run_and_put_task : public task { | |
| public: | | public: | |
| run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_bo
dy(body) {} | | run_and_put_task( Receiver &r, Body& body ) : my_receiver(r), my_bo
dy(body) {} | |
| task *execute() { | | task *execute() { | |
|
| my_receiver.try_put( my_body() ); | | task *res = my_receiver.try_put_task( my_body() ); | |
| return NULL; | | if(res == SUCCESSFULLY_ENQUEUED) res = NULL; | |
| | | return res; | |
| } | | } | |
| private: | | private: | |
| Receiver &my_receiver; | | Receiver &my_receiver; | |
| Body my_body; | | Body my_body; | |
| }; | | }; | |
| | | | |
| public: | | public: | |
| //! Constructs a graph with isolated task_group_context | | //! Constructs a graph with isolated task_group_context | |
| explicit graph() : my_nodes(NULL), my_nodes_last(NULL) | | explicit graph() : my_nodes(NULL), my_nodes_last(NULL) | |
| { | | { | |
| | | | |
| skipping to change at line 550 | | skipping to change at line 594 | |
| graph_node *my_p = &(*ii); | | graph_node *my_p = &(*ii); | |
| my_p->reset(); | | my_p->reset(); | |
| } | | } | |
| } | | } | |
| | | | |
| #include "internal/_flow_graph_node_impl.h" | | #include "internal/_flow_graph_node_impl.h" | |
| | | | |
| //! An executable node that acts as a source, i.e. it has no predecessors | | //! An executable node that acts as a source, i.e. it has no predecessors | |
| template < typename Output > | | template < typename Output > | |
| class source_node : public graph_node, public sender< Output > { | | class source_node : public graph_node, public sender< Output > { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| //! The type of the output message, which is complete | | //! The type of the output message, which is complete | |
| typedef Output output_type; | | typedef Output output_type; | |
| | | | |
| //! The type of successors of this node | | //! The type of successors of this node | |
| typedef receiver< Output > successor_type; | | typedef receiver< Output > successor_type; | |
| | | | |
| //! Constructor for a node with a successor | | //! Constructor for a node with a successor | |
| template< typename Body > | | template< typename Body > | |
| | | | |
| skipping to change at line 658 | | skipping to change at line 703 | |
| } | | } | |
| | | | |
| //! Activates a node that was created in the inactive state | | //! Activates a node that was created in the inactive state | |
| void activate() { | | void activate() { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| my_active = true; | | my_active = true; | |
| if ( !my_successors.empty() ) | | if ( !my_successors.empty() ) | |
| spawn_put(); | | spawn_put(); | |
| } | | } | |
| | | | |
|
| template<class Body> | | template<typename Body> | |
| Body copy_function_object() { | | Body copy_function_object() { | |
| internal::source_body<output_type> &body_ref = *this->my_body; | | internal::source_body<output_type> &body_ref = *this->my_body; | |
| return dynamic_cast< internal::source_body_leaf<output_type, Body>
& >(body_ref).get_body(); | | return dynamic_cast< internal::source_body_leaf<output_type, Body>
& >(body_ref).get_body(); | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| | | | |
| //! resets the node to its initial state | | //! resets the node to its initial state | |
| void reset() { | | void reset() { | |
| my_active = init_my_active; | | my_active = init_my_active; | |
| | | | |
| skipping to change at line 686 | | skipping to change at line 731 | |
| task *my_root_task; | | task *my_root_task; | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| bool my_active; | | bool my_active; | |
| bool init_my_active; | | bool init_my_active; | |
| internal::source_body<output_type> *my_body; | | internal::source_body<output_type> *my_body; | |
| internal::broadcast_cache< output_type > my_successors; | | internal::broadcast_cache< output_type > my_successors; | |
| bool my_reserved; | | bool my_reserved; | |
| bool my_has_cached_item; | | bool my_has_cached_item; | |
| output_type my_cached_item; | | output_type my_cached_item; | |
| | | | |
|
| friend class internal::source_task< source_node< output_type > >; | | | |
| | | | |
| // used by apply_body, can invoke body of node. | | // used by apply_body, can invoke body of node. | |
|
| | | | |
| bool try_reserve_apply_body(output_type &v) { | | bool try_reserve_apply_body(output_type &v) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| if ( my_reserved ) { | | if ( my_reserved ) { | |
| return false; | | return false; | |
| } | | } | |
|
| | | | |
| if ( !my_has_cached_item && (*my_body)(my_cached_item) ) | | if ( !my_has_cached_item && (*my_body)(my_cached_item) ) | |
| my_has_cached_item = true; | | my_has_cached_item = true; | |
|
| | | | |
| if ( my_has_cached_item ) { | | if ( my_has_cached_item ) { | |
| v = my_cached_item; | | v = my_cached_item; | |
| my_reserved = true; | | my_reserved = true; | |
| return true; | | return true; | |
| } else { | | } else { | |
| return false; | | return false; | |
| } | | } | |
| } | | } | |
| | | | |
|
| //! Applies the body | | //! Spawns a task that applies the body | |
| /* override */ void apply_body( ) { | | /* override */ void spawn_put( ) { | |
| | | task::enqueue( * new ( task::allocate_additional_child_of( *my_root | |
| | | _task ) ) | |
| | | internal:: source_task_bypass < source_node< output_type > >( *t | |
| | | his ) ); | |
| | | } | |
| | | | |
| | | friend class internal::source_task_bypass< source_node< output_type > > | |
| | | ; | |
| | | //! Applies the body. Returning SUCCESSFULLY_ENQUEUED okay; forward_ta | |
| | | sk_bypass will handle it. | |
| | | /* override */ task * apply_body_bypass( ) { | |
| output_type v; | | output_type v; | |
| if ( !try_reserve_apply_body(v) ) | | if ( !try_reserve_apply_body(v) ) | |
|
| return; | | return NULL; | |
| | | | |
|
| if ( my_successors.try_put( v ) ) | | task *last_task = my_successors.try_put_task(v); | |
| | | if ( last_task ) | |
| try_consume(); | | try_consume(); | |
| else | | else | |
| try_release(); | | try_release(); | |
|
| } | | return last_task; | |
| | | | |
| //! Spawns a task that applies the body | | | |
| /* override */ void spawn_put( ) { | | | |
| task::enqueue( * new ( task::allocate_additional_child_of( *my_root | | | |
| _task ) ) | | | |
| internal::source_task< source_node< output_type > >( *this ) ); | | | |
| } | | } | |
| }; // source_node | | }; // source_node | |
| | | | |
| //! Implements a function node that supports Input -> Output | | //! Implements a function node that supports Input -> Output | |
| template < typename Input, typename Output = continue_msg, graph_buffer_pol
icy = queueing, typename Allocator=cache_aligned_allocator<Input> > | | template < typename Input, typename Output = continue_msg, graph_buffer_pol
icy = queueing, typename Allocator=cache_aligned_allocator<Input> > | |
| class function_node : public graph_node, public internal::function_input<In
put,Output,Allocator>, public internal::function_output<Output> { | | class function_node : public graph_node, public internal::function_input<In
put,Output,Allocator>, public internal::function_output<Output> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | | typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | |
| typedef internal::function_output<output_type> fOutput_type; | | typedef internal::function_output<output_type> fOutput_type; | |
| | | | |
| //! Constructor | | //! Constructor | |
| | | | |
| skipping to change at line 751 | | skipping to change at line 795 | |
| function_node( graph &g, size_t concurrency, Body body ) : | | function_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), internal::function_input<input_type,output_type,Allo
cator>(g, concurrency, body) | | graph_node(g), internal::function_input<input_type,output_type,Allo
cator>(g, concurrency, body) | |
| {} | | {} | |
| | | | |
| //! Copy constructor | | //! Copy constructor | |
| function_node( const function_node& src ) : | | function_node( const function_node& src ) : | |
| graph_node(src.my_graph), internal::function_input<input_type,outpu
t_type,Allocator>( src ), | | graph_node(src.my_graph), internal::function_input<input_type,outpu
t_type,Allocator>( src ), | |
| fOutput_type() | | fOutput_type() | |
| {} | | {} | |
| | | | |
|
| bool try_put(const input_type &i) { return fInput_type::try_put(i); } | | | |
| | | | |
| protected: | | protected: | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | using fInput_type::try_put_task; | |
| | | | |
| // override of graph_node's reset. | | // override of graph_node's reset. | |
| /*override*/void reset() {fInput_type::reset_function_input(); } | | /*override*/void reset() {fInput_type::reset_function_input(); } | |
| | | | |
| /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | | /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | |
| }; | | }; | |
| | | | |
| //! Implements a function node that supports Input -> Output | | //! Implements a function node that supports Input -> Output | |
| template < typename Input, typename Output, typename Allocator > | | template < typename Input, typename Output, typename Allocator > | |
| class function_node<Input,Output,queueing,Allocator> : public graph_node, p
ublic internal::function_input<Input,Output,Allocator>, public internal::fu
nction_output<Output> { | | class function_node<Input,Output,queueing,Allocator> : public graph_node, p
ublic internal::function_input<Input,Output,Allocator>, public internal::fu
nction_output<Output> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | | typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | |
| typedef internal::function_input_queue<input_type, Allocator> queue_typ
e; | | typedef internal::function_input_queue<input_type, Allocator> queue_typ
e; | |
| typedef internal::function_output<output_type> fOutput_type; | | typedef internal::function_output<output_type> fOutput_type; | |
| | | | |
| | | | |
| skipping to change at line 785 | | skipping to change at line 832 | |
| template< typename Body > | | template< typename Body > | |
| function_node( graph &g, size_t concurrency, Body body ) : | | function_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), fInput_type( g, concurrency, body, new queue_type()
) | | graph_node(g), fInput_type( g, concurrency, body, new queue_type()
) | |
| {} | | {} | |
| | | | |
| //! Copy constructor | | //! Copy constructor | |
| function_node( const function_node& src ) : | | function_node( const function_node& src ) : | |
| graph_node(src.my_graph), fInput_type( src, new queue_type() ), fOu
tput_type() | | graph_node(src.my_graph), fInput_type( src, new queue_type() ), fOu
tput_type() | |
| {} | | {} | |
| | | | |
|
| bool try_put(const input_type &i) { return fInput_type::try_put(i); } | | | |
| | | | |
| protected: | | protected: | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | using fInput_type::try_put_task; | |
| | | | |
| /*override*/void reset() { fInput_type::reset_function_input(); } | | /*override*/void reset() { fInput_type::reset_function_input(); } | |
| | | | |
| /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | | /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | |
| }; | | }; | |
| | | | |
| #include "tbb/internal/_flow_graph_types_impl.h" | | #include "tbb/internal/_flow_graph_types_impl.h" | |
| | | | |
| //! implements a function node that supports Input -> (set of outputs) | | //! implements a function node that supports Input -> (set of outputs) | |
| // Output is a tuple of output types. | | // Output is a tuple of output types. | |
| template < typename Input, typename Output, graph_buffer_policy = queueing,
typename Allocator=cache_aligned_allocator<Input> > | | template < typename Input, typename Output, graph_buffer_policy = queueing,
typename Allocator=cache_aligned_allocator<Input> > | |
| class multifunction_node : | | class multifunction_node : | |
| public graph_node, | | public graph_node, | |
| public internal::multifunction_input | | public internal::multifunction_input | |
| < | | < | |
| Input, | | Input, | |
| typename internal::wrap_tuple_elements< | | typename internal::wrap_tuple_elements< | |
|
| std::tuple_size<Output>::value, // #elements in tuple | | tbb::flow::tuple_size<Output>::value, // #elements in tuple | |
| internal::function_output, // wrap this around each element | | internal::multifunction_output, // wrap this around each eleme | |
| | | nt | |
| Output // the tuple providing the types | | Output // the tuple providing the types | |
| >::type, | | >::type, | |
| Allocator | | Allocator | |
| > { | | > { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| private: | | private: | |
|
| static const int N = std::tuple_size<Output>::value; | | static const int N = tbb::flow::tuple_size<Output>::value; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
|
| typedef typename internal::wrap_tuple_elements<N,internal::function_out
put, Output>::type output_ports_type; | | typedef typename internal::wrap_tuple_elements<N,internal::multifunctio
n_output, Output>::type output_ports_type; | |
| private: | | private: | |
| typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | | typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | |
| typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | | typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | |
| public: | | public: | |
| template<typename Body> | | template<typename Body> | |
| multifunction_node( graph &g, size_t concurrency, Body body ) : | | multifunction_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), base_type(g,concurrency, body) | | graph_node(g), base_type(g,concurrency, body) | |
| {} | | {} | |
| multifunction_node( const multifunction_node &other) : | | multifunction_node( const multifunction_node &other) : | |
| graph_node(other.my_graph), base_type(other) | | graph_node(other.my_graph), base_type(other) | |
| {} | | {} | |
| // all the guts are in multifunction_input... | | // all the guts are in multifunction_input... | |
| protected: | | protected: | |
| /*override*/void reset() { base_type::reset(); } | | /*override*/void reset() { base_type::reset(); } | |
| }; // multifunction_node | | }; // multifunction_node | |
| | | | |
| template < typename Input, typename Output, typename Allocator > | | template < typename Input, typename Output, typename Allocator > | |
| class multifunction_node<Input,Output,queueing,Allocator> : public graph_no
de, public internal::multifunction_input<Input, | | class multifunction_node<Input,Output,queueing,Allocator> : public graph_no
de, public internal::multifunction_input<Input, | |
|
| typename internal::wrap_tuple_elements<std::tuple_size<Output>::value, | | typename internal::wrap_tuple_elements<tbb::flow::tuple_size<Output>::v | |
| internal::function_output, Output>::type, Allocator> { | | alue, internal::multifunction_output, Output>::type, Allocator> { | |
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
|
| static const int N = std::tuple_size<Output>::value; | | static const int N = tbb::flow::tuple_size<Output>::value; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
|
| typedef typename internal::wrap_tuple_elements<N, internal::function_ou
tput, Output>::type output_ports_type; | | typedef typename internal::wrap_tuple_elements<N, internal::multifuncti
on_output, Output>::type output_ports_type; | |
| private: | | private: | |
| typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | | typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | |
| typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | | typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | |
| public: | | public: | |
| template<typename Body> | | template<typename Body> | |
| multifunction_node( graph &g, size_t concurrency, Body body) : | | multifunction_node( graph &g, size_t concurrency, Body body) : | |
| graph_node(g), base_type(g,concurrency, body, new queue_type()) | | graph_node(g), base_type(g,concurrency, body, new queue_type()) | |
| {} | | {} | |
| multifunction_node( const multifunction_node &other) : | | multifunction_node( const multifunction_node &other) : | |
| graph_node(other.my_graph), base_type(other, new queue_type()) | | graph_node(other.my_graph), base_type(other, new queue_type()) | |
| | | | |
| skipping to change at line 862 | | skipping to change at line 913 | |
| // all the guts are in multifunction_input... | | // all the guts are in multifunction_input... | |
| protected: | | protected: | |
| /*override*/void reset() { base_type::reset(); } | | /*override*/void reset() { base_type::reset(); } | |
| }; // multifunction_node | | }; // multifunction_node | |
| | | | |
| //! split_node: accepts a tuple as input, forwards each element of the tupl
e to its | | //! split_node: accepts a tuple as input, forwards each element of the tupl
e to its | |
| // successors. The node has unlimited concurrency, so though it is marked
as | | // successors. The node has unlimited concurrency, so though it is marked
as | |
| // "rejecting" it does not reject inputs. | | // "rejecting" it does not reject inputs. | |
| template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup
leType> > | | template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup
leType> > | |
| class split_node : public multifunction_node<TupleType, TupleType, rejectin
g, Allocator> { | | class split_node : public multifunction_node<TupleType, TupleType, rejectin
g, Allocator> { | |
|
| static const int N = std::tuple_size<TupleType>::value; | | static const int N = tbb::flow::tuple_size<TupleType>::value; | |
| typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas
e_type; | | typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas
e_type; | |
| public: | | public: | |
| typedef typename base_type::output_ports_type output_ports_type; | | typedef typename base_type::output_ports_type output_ports_type; | |
| private: | | private: | |
| struct splitting_body { | | struct splitting_body { | |
| void operator()(const TupleType& t, output_ports_type &p) { | | void operator()(const TupleType& t, output_ports_type &p) { | |
| internal::emit_element<N>::emit_this(t, p); | | internal::emit_element<N>::emit_this(t, p); | |
| } | | } | |
| }; | | }; | |
| public: | | public: | |
| typedef TupleType input_type; | | typedef TupleType input_type; | |
| typedef Allocator allocator_type; | | typedef Allocator allocator_type; | |
| split_node(graph &g) : base_type(g, unlimited, splitting_body()) {} | | split_node(graph &g) : base_type(g, unlimited, splitting_body()) {} | |
| split_node( const split_node & other) : base_type(other) {} | | split_node( const split_node & other) : base_type(other) {} | |
| }; | | }; | |
| | | | |
| //! Implements an executable node that supports continue_msg -> Output | | //! Implements an executable node that supports continue_msg -> Output | |
| template <typename Output> | | template <typename Output> | |
| class continue_node : public graph_node, public internal::continue_input<Ou
tput>, public internal::function_output<Output> { | | class continue_node : public graph_node, public internal::continue_input<Ou
tput>, public internal::function_output<Output> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef continue_msg input_type; | | typedef continue_msg input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
|
| | | typedef internal::continue_input<Output> fInput_type; | |
| typedef internal::function_output<output_type> fOutput_type; | | typedef internal::function_output<output_type> fOutput_type; | |
| | | | |
| //! Constructor for executable node with continue_msg -> Output | | //! Constructor for executable node with continue_msg -> Output | |
| template <typename Body > | | template <typename Body > | |
| continue_node( graph &g, Body body ) : | | continue_node( graph &g, Body body ) : | |
| graph_node(g), internal::continue_input<output_type>( g, body ) | | graph_node(g), internal::continue_input<output_type>( g, body ) | |
| {} | | {} | |
| | | | |
| //! Constructor for executable node with continue_msg -> Output | | //! Constructor for executable node with continue_msg -> Output | |
| template <typename Body > | | template <typename Body > | |
| continue_node( graph &g, int number_of_predecessors, Body body ) : | | continue_node( graph &g, int number_of_predecessors, Body body ) : | |
| graph_node(g), internal::continue_input<output_type>( g, number_of_
predecessors, body ) | | graph_node(g), internal::continue_input<output_type>( g, number_of_
predecessors, body ) | |
| {} | | {} | |
| | | | |
| //! Copy constructor | | //! Copy constructor | |
| continue_node( const continue_node& src ) : | | continue_node( const continue_node& src ) : | |
| graph_node(src.my_graph), internal::continue_input<output_type>(src
), | | graph_node(src.my_graph), internal::continue_input<output_type>(src
), | |
| internal::function_output<Output>() | | internal::function_output<Output>() | |
| {} | | {} | |
| | | | |
|
| bool try_put(const input_type &i) { return internal::continue_input<Out | | | |
| put>::try_put(i); } | | | |
| | | | |
| protected: | | protected: | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | using fInput_type::try_put_task; | |
| | | | |
| /*override*/void reset() { internal::continue_input<Output>::reset_rece
iver(); } | | /*override*/void reset() { internal::continue_input<Output>::reset_rece
iver(); } | |
| | | | |
| /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | | /* override */ internal::broadcast_cache<output_type> &successors () {
return fOutput_type::my_successors; } | |
| }; | | }; | |
| | | | |
| template< typename T > | | template< typename T > | |
| class overwrite_node : public graph_node, public receiver<T>, public sender
<T> { | | class overwrite_node : public graph_node, public receiver<T>, public sender
<T> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| | | | |
| overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | | overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | |
| my_successors.set_owner( this ); | | my_successors.set_owner( this ); | |
| } | | } | |
| | | | |
| skipping to change at line 943 | | skipping to change at line 1000 | |
| my_successors.set_owner( this ); | | my_successors.set_owner( this ); | |
| } | | } | |
| | | | |
| ~overwrite_node() {} | | ~overwrite_node() {} | |
| | | | |
| /* override */ bool register_successor( successor_type &s ) { | | /* override */ bool register_successor( successor_type &s ) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| if ( my_buffer_is_valid ) { | | if ( my_buffer_is_valid ) { | |
| // We have a valid value that must be forwarded immediately. | | // We have a valid value that must be forwarded immediately. | |
| if ( s.try_put( my_buffer ) || !s.register_predecessor( *this
) ) { | | if ( s.try_put( my_buffer ) || !s.register_predecessor( *this
) ) { | |
|
| // We add the successor: it accepted our put or it rejected
it but won't let use become a predecessor | | // We add the successor: it accepted our put or it rejected
it but won't let us become a predecessor | |
| my_successors.register_successor( s ); | | my_successors.register_successor( s ); | |
| return true; | | return true; | |
| } else { | | } else { | |
| // We don't add the successor: it rejected our put and we b
ecame its predecessor instead | | // We don't add the successor: it rejected our put and we b
ecame its predecessor instead | |
| return false; | | return false; | |
| } | | } | |
| } else { | | } else { | |
| // No valid value yet, just add as successor | | // No valid value yet, just add as successor | |
| my_successors.register_successor( s ); | | my_successors.register_successor( s ); | |
| return true; | | return true; | |
| } | | } | |
| } | | } | |
| | | | |
| /* override */ bool remove_successor( successor_type &s ) { | | /* override */ bool remove_successor( successor_type &s ) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_successors.remove_successor(s); | | my_successors.remove_successor(s); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| /* override */ bool try_put( const T &v ) { | | | |
| spin_mutex::scoped_lock l( my_mutex ); | | | |
| my_buffer = v; | | | |
| my_buffer_is_valid = true; | | | |
| my_successors.try_put(v); | | | |
| return true; | | | |
| } | | | |
| | | | |
| /* override */ bool try_get( T &v ) { | | /* override */ bool try_get( T &v ) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| if ( my_buffer_is_valid ) { | | if ( my_buffer_is_valid ) { | |
| v = my_buffer; | | v = my_buffer; | |
| return true; | | return true; | |
| } else { | | } else { | |
| return false; | | return false; | |
| } | | } | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 992 | | skipping to change at line 1041 | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| return my_buffer_is_valid; | | return my_buffer_is_valid; | |
| } | | } | |
| | | | |
| void clear() { | | void clear() { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_buffer_is_valid = false; | | my_buffer_is_valid = false; | |
| } | | } | |
| | | | |
| protected: | | protected: | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | /* override */ task * try_put_task( const T &v ) { | |
| | | spin_mutex::scoped_lock l( my_mutex ); | |
| | | my_buffer = v; | |
| | | my_buffer_is_valid = true; | |
| | | task * rtask = my_successors.try_put_task(v); | |
| | | if(!rtask) rtask = SUCCESSFULLY_ENQUEUED; | |
| | | return rtask; | |
| | | } | |
| | | | |
| /*override*/void reset() { my_buffer_is_valid = false; } | | /*override*/void reset() { my_buffer_is_valid = false; } | |
| | | | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| internal::broadcast_cache< T, null_rw_mutex > my_successors; | | internal::broadcast_cache< T, null_rw_mutex > my_successors; | |
| T my_buffer; | | T my_buffer; | |
| bool my_buffer_is_valid; | | bool my_buffer_is_valid; | |
| /*override*/void reset_receiver() {} | | /*override*/void reset_receiver() {} | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 1016 | | skipping to change at line 1076 | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| | | | |
| //! Constructor | | //! Constructor | |
| write_once_node(graph& g) : overwrite_node<T>(g) {} | | write_once_node(graph& g) : overwrite_node<T>(g) {} | |
| | | | |
| //! Copy constructor: call base class copy constructor | | //! Copy constructor: call base class copy constructor | |
| write_once_node( const write_once_node& src ) : overwrite_node<T>(src)
{} | | write_once_node( const write_once_node& src ) : overwrite_node<T>(src)
{} | |
| | | | |
|
| /* override */ bool try_put( const T &v ) { | | protected: | |
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | /* override */ task *try_put_task( const T &v ) { | |
| spin_mutex::scoped_lock l( this->my_mutex ); | | spin_mutex::scoped_lock l( this->my_mutex ); | |
| if ( this->my_buffer_is_valid ) { | | if ( this->my_buffer_is_valid ) { | |
|
| return false; | | return NULL; | |
| } else { | | } else { | |
| this->my_buffer = v; | | this->my_buffer = v; | |
| this->my_buffer_is_valid = true; | | this->my_buffer_is_valid = true; | |
|
| this->my_successors.try_put(v); | | task *res = this->my_successors.try_put_task(v); | |
| return true; | | if(!res) res = SUCCESSFULLY_ENQUEUED; | |
| | | return res; | |
| } | | } | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Forwards messages of type T to all successors | | //! Forwards messages of type T to all successors | |
| template <typename T> | | template <typename T> | |
| class broadcast_node : public graph_node, public receiver<T>, public sender
<T> { | | class broadcast_node : public graph_node, public receiver<T>, public sender
<T> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
|
| | | private: | |
| internal::broadcast_cache<T> my_successors; | | internal::broadcast_cache<T> my_successors; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| | | | |
| broadcast_node(graph& g) : graph_node(g) { | | broadcast_node(graph& g) : graph_node(g) { | |
| my_successors.set_owner( this ); | | my_successors.set_owner( this ); | |
| } | | } | |
| | | | |
| skipping to change at line 1063 | | skipping to change at line 1130 | |
| my_successors.register_successor( r ); | | my_successors.register_successor( r ); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| //! Removes s as a successor | | //! Removes s as a successor | |
| virtual bool remove_successor( receiver<T> &r ) { | | virtual bool remove_successor( receiver<T> &r ) { | |
| my_successors.remove_successor( r ); | | my_successors.remove_successor( r ); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| /* override */ bool try_put( const T &t ) { | | | |
| my_successors.try_put(t); | | | |
| return true; | | | |
| } | | | |
| protected: | | protected: | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | //! build a task to run the successor if possible. Default is old beha | |
| | | vior. | |
| | | /*override*/ task *try_put_task(const T& t) { | |
| | | task *new_task = my_successors.try_put_task(t); | |
| | | if(!new_task) new_task = SUCCESSFULLY_ENQUEUED; | |
| | | return new_task; | |
| | | } | |
| | | | |
| /*override*/void reset() {} | | /*override*/void reset() {} | |
| /*override*/void reset_receiver() {} | | /*override*/void reset_receiver() {} | |
|
| }; | | }; // broadcast_node | |
| | | | |
| #include "internal/_flow_graph_item_buffer_impl.h" | | #include "internal/_flow_graph_item_buffer_impl.h" | |
| | | | |
| //! Forwards messages in arbitrary order | | //! Forwards messages in arbitrary order | |
| template <typename T, typename A=cache_aligned_allocator<T> > | | template <typename T, typename A=cache_aligned_allocator<T> > | |
| class buffer_node : public graph_node, public reservable_item_buffer<T, A>,
public receiver<T>, public sender<T> { | | class buffer_node : public graph_node, public reservable_item_buffer<T, A>,
public receiver<T>, public sender<T> { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef buffer_node<T, A> my_class; | | typedef buffer_node<T, A> my_class; | |
| protected: | | protected: | |
| typedef size_t size_type; | | typedef size_t size_type; | |
| internal::round_robin_cache< T, null_rw_mutex > my_successors; | | internal::round_robin_cache< T, null_rw_mutex > my_successors; | |
| | | | |
| task *my_parent; | | task *my_parent; | |
| | | | |
|
| friend class internal::forward_task< buffer_node< T, A > >; | | friend class internal::forward_task_bypass< buffer_node< T, A > >; | |
| | | | |
|
| enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res,
put_item, try_fwd}; | | enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res,
put_item, try_fwd_task }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| | | | |
| // implements the aggregator_operation concept | | // implements the aggregator_operation concept | |
| class buffer_operation : public internal::aggregated_operation< buffer_
operation > { | | class buffer_operation : public internal::aggregated_operation< buffer_
operation > { | |
| public: | | public: | |
| char type; | | char type; | |
| T *elem; | | T *elem; | |
|
| | | task * ltask; | |
| successor_type *r; | | successor_type *r; | |
|
| buffer_operation(const T& e, op_type t) : | | buffer_operation(const T& e, op_type t) : type(char(t)), elem(const | |
| type(char(t)), elem(const_cast<T*>(&e)), r(NULL) {} | | _cast<T*>(&e)) , ltask(NULL) , r(NULL) {} | |
| buffer_operation(op_type t) : type(char(t)), r(NULL) {} | | buffer_operation(op_type t) : type(char(t)) , ltask(NULL) , r(NULL) | |
| | | {} | |
| }; | | }; | |
| | | | |
| bool forwarder_busy; | | bool forwarder_busy; | |
| typedef internal::aggregating_functor<my_class, buffer_operation> my_ha
ndler; | | typedef internal::aggregating_functor<my_class, buffer_operation> my_ha
ndler; | |
| friend class internal::aggregating_functor<my_class, buffer_operation>; | | friend class internal::aggregating_functor<my_class, buffer_operation>; | |
| internal::aggregator< my_handler, buffer_operation> my_aggregator; | | internal::aggregator< my_handler, buffer_operation> my_aggregator; | |
| | | | |
| virtual void handle_operations(buffer_operation *op_list) { | | virtual void handle_operations(buffer_operation *op_list) { | |
|
| buffer_operation *tmp; | | buffer_operation *tmp = NULL; | |
| bool try_forwarding=false; | | bool try_forwarding=false; | |
| while (op_list) { | | while (op_list) { | |
| tmp = op_list; | | tmp = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch (tmp->type) { | | switch (tmp->type) { | |
| case reg_succ: internal_reg_succ(tmp); try_forwarding = true;
break; | | case reg_succ: internal_reg_succ(tmp); try_forwarding = true;
break; | |
| case rem_succ: internal_rem_succ(tmp); break; | | case rem_succ: internal_rem_succ(tmp); break; | |
| case req_item: internal_pop(tmp); break; | | case req_item: internal_pop(tmp); break; | |
| case res_item: internal_reserve(tmp); break; | | case res_item: internal_reserve(tmp); break; | |
| case rel_res: internal_release(tmp); try_forwarding = true; b
reak; | | case rel_res: internal_release(tmp); try_forwarding = true; b
reak; | |
| case con_res: internal_consume(tmp); try_forwarding = true; b
reak; | | case con_res: internal_consume(tmp); try_forwarding = true; b
reak; | |
| case put_item: internal_push(tmp); try_forwarding = true; brea
k; | | case put_item: internal_push(tmp); try_forwarding = true; brea
k; | |
|
| case try_fwd: internal_forward(tmp); break; | | case try_fwd_task: internal_forward_task(tmp); break; | |
| } | | } | |
| } | | } | |
| if (try_forwarding && !forwarder_busy) { | | if (try_forwarding && !forwarder_busy) { | |
| forwarder_busy = true; | | forwarder_busy = true; | |
|
| task::enqueue(*new(task::allocate_additional_child_of(*my_paren | | task *new_task = new(task::allocate_additional_child_of(*my_par | |
| t)) internal::forward_task< buffer_node<input_type, A> >(*this)); | | ent)) internal:: | |
| | | forward_task_bypass | |
| | | < buffer_node<input_type, A> >(*this); | |
| | | // tmp should point to the last item handled by the aggregator. | |
| | | This is the operation | |
| | | // the handling thread enqueued. So modifying that record will | |
| | | be okay. | |
| | | tbb::task *z = tmp->ltask; | |
| | | tmp->ltask = combine_tasks(z, new_task); // in case the op gen | |
| | | erated a task | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | inline task *grab_forwarding_task( buffer_operation &op_data) { | |
| | | return op_data.ltask; | |
| | | } | |
| | | | |
| | | inline bool enqueue_forwarding_task(buffer_operation &op_data) { | |
| | | task *ft = grab_forwarding_task(op_data); | |
| | | if(ft) { | |
| | | task::enqueue(*ft); | |
| | | return true; | |
| | | } | |
| | | return false; | |
| | | } | |
| | | | |
| //! This is executed by an enqueued task, the "forwarder" | | //! This is executed by an enqueued task, the "forwarder" | |
|
| virtual void forward() { | | virtual task *forward_task() { | |
| buffer_operation op_data(try_fwd); | | buffer_operation op_data(try_fwd_task); | |
| | | task *last_task = NULL; | |
| do { | | do { | |
| op_data.status = WAIT; | | op_data.status = WAIT; | |
|
| | | op_data.ltask = NULL; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | tbb::task *xtask = op_data.ltask; | |
| | | last_task = combine_tasks(last_task, xtask); | |
| } while (op_data.status == SUCCEEDED); | | } while (op_data.status == SUCCEEDED); | |
|
| | | return last_task; | |
| } | | } | |
| | | | |
| //! Register successor | | //! Register successor | |
| virtual void internal_reg_succ(buffer_operation *op) { | | virtual void internal_reg_succ(buffer_operation *op) { | |
| my_successors.register_successor(*(op->r)); | | my_successors.register_successor(*(op->r)); | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } | | } | |
| | | | |
| //! Remove successor | | //! Remove successor | |
| virtual void internal_rem_succ(buffer_operation *op) { | | virtual void internal_rem_succ(buffer_operation *op) { | |
| my_successors.remove_successor(*(op->r)); | | my_successors.remove_successor(*(op->r)); | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } | | } | |
| | | | |
| //! Tries to forward valid items to successors | | //! Tries to forward valid items to successors | |
|
| virtual void internal_forward(buffer_operation *op) { | | virtual void internal_forward_task(buffer_operation *op) { | |
| | | if (this->my_reserved || !this->item_valid(this->my_tail-1)) { | |
| | | __TBB_store_with_release(op->status, FAILED); | |
| | | this->forwarder_busy = false; | |
| | | return; | |
| | | } | |
| T i_copy; | | T i_copy; | |
|
| bool success = false; // flagged when a successor accepts | | task * last_task = NULL; | |
| size_type counter = my_successors.size(); | | size_type counter = my_successors.size(); | |
| // Try forwarding, giving each successor a chance | | // Try forwarding, giving each successor a chance | |
| while (counter>0 && !this->buffer_empty() && this->item_valid(this-
>my_tail-1)) { | | while (counter>0 && !this->buffer_empty() && this->item_valid(this-
>my_tail-1)) { | |
| this->fetch_back(i_copy); | | this->fetch_back(i_copy); | |
|
| if( my_successors.try_put(i_copy) ) { | | task *new_task = my_successors.try_put_task(i_copy); | |
| | | last_task = combine_tasks(last_task, new_task); | |
| | | if(new_task) { | |
| this->invalidate_back(); | | this->invalidate_back(); | |
| --(this->my_tail); | | --(this->my_tail); | |
|
| success = true; // found an accepting successor | | | |
| } | | } | |
| --counter; | | --counter; | |
| } | | } | |
|
| if (success && !counter) | | op->ltask = last_task; // return task | |
| | | if (last_task && !counter) { | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
|
| | | } | |
| else { | | else { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| forwarder_busy = false; | | forwarder_busy = false; | |
| } | | } | |
| } | | } | |
| | | | |
| virtual void internal_push(buffer_operation *op) { | | virtual void internal_push(buffer_operation *op) { | |
| this->push_back(*(op->elem)); | | this->push_back(*(op->elem)); | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } | | } | |
| | | | |
| skipping to change at line 1240 | | skipping to change at line 1346 | |
| // | | // | |
| // message sender implementation | | // message sender implementation | |
| // | | // | |
| | | | |
| //! Adds a new successor. | | //! Adds a new successor. | |
| /** Adds successor r to the list of successors; may forward tasks. */ | | /** Adds successor r to the list of successors; may forward tasks. */ | |
| /* override */ bool register_successor( receiver<output_type> &r ) { | | /* override */ bool register_successor( receiver<output_type> &r ) { | |
| buffer_operation op_data(reg_succ); | | buffer_operation op_data(reg_succ); | |
| op_data.r = &r; | | op_data.r = &r; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | (void)enqueue_forwarding_task(op_data); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| //! Removes a successor. | | //! Removes a successor. | |
| /** Removes successor r from the list of successors. | | /** Removes successor r from the list of successors. | |
| It also calls r.remove_predecessor(*this) to remove this node as a
predecessor. */ | | It also calls r.remove_predecessor(*this) to remove this node as a
predecessor. */ | |
| /* override */ bool remove_successor( receiver<output_type> &r ) { | | /* override */ bool remove_successor( receiver<output_type> &r ) { | |
| r.remove_predecessor(*this); | | r.remove_predecessor(*this); | |
| buffer_operation op_data(rem_succ); | | buffer_operation op_data(rem_succ); | |
| op_data.r = &r; | | op_data.r = &r; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | // even though this operation does not cause a forward, if we are t | |
| | | he handler, and | |
| | | // a forward is scheduled, we may be the first to reach this point | |
| | | after the aggregator, | |
| | | // and so should check for the task. | |
| | | (void)enqueue_forwarding_task(op_data); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| //! Request an item from the buffer_node | | //! Request an item from the buffer_node | |
| /** true = v contains the returned item<BR> | | /** true = v contains the returned item<BR> | |
| false = no item has been returned */ | | false = no item has been returned */ | |
| /* override */ bool try_get( T &v ) { | | /* override */ bool try_get( T &v ) { | |
| buffer_operation op_data(req_item); | | buffer_operation op_data(req_item); | |
| op_data.elem = &v; | | op_data.elem = &v; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | (void)enqueue_forwarding_task(op_data); | |
| return (op_data.status==SUCCEEDED); | | return (op_data.status==SUCCEEDED); | |
| } | | } | |
| | | | |
| //! Reserves an item. | | //! Reserves an item. | |
| /** false = no item can be reserved<BR> | | /** false = no item can be reserved<BR> | |
| true = an item is reserved */ | | true = an item is reserved */ | |
| /* override */ bool try_reserve( T &v ) { | | /* override */ bool try_reserve( T &v ) { | |
| buffer_operation op_data(res_item); | | buffer_operation op_data(res_item); | |
| op_data.elem = &v; | | op_data.elem = &v; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | (void)enqueue_forwarding_task(op_data); | |
| return (op_data.status==SUCCEEDED); | | return (op_data.status==SUCCEEDED); | |
| } | | } | |
| | | | |
| //! Release a reserved item. | | //! Release a reserved item. | |
| /** true = item has been released and so remains in sender */ | | /** true = item has been released and so remains in sender */ | |
| /* override */ bool try_release() { | | /* override */ bool try_release() { | |
| buffer_operation op_data(rel_res); | | buffer_operation op_data(rel_res); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | (void)enqueue_forwarding_task(op_data); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| //! Consumes a reserved item. | | //! Consumes a reserved item. | |
| /** true = item is removed from sender and reservation removed */ | | /** true = item is removed from sender and reservation removed */ | |
| /* override */ bool try_consume() { | | /* override */ bool try_consume() { | |
| buffer_operation op_data(con_res); | | buffer_operation op_data(con_res); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| | | (void)enqueue_forwarding_task(op_data); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| //! Receive an item | | protected: | |
| /** true is always returned */ | | | |
| /* override */ bool try_put(const T &t) { | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | //! receive an item, return a task *if possible | |
| | | /* override */ task *try_put_task(const T &t) { | |
| buffer_operation op_data(t, put_item); | | buffer_operation op_data(t, put_item); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
|
| return true; | | task *ft = grab_forwarding_task(op_data); | |
| | | if(!ft) { | |
| | | ft = SUCCESSFULLY_ENQUEUED; | |
| | | } | |
| | | return ft; | |
| } | | } | |
| | | | |
|
| protected: | | | |
| | | | |
| /*override*/void reset() { | | /*override*/void reset() { | |
| reservable_item_buffer<T, A>::reset(); | | reservable_item_buffer<T, A>::reset(); | |
| forwarder_busy = false; | | forwarder_busy = false; | |
| } | | } | |
| | | | |
| /*override*/void reset_receiver() { | | /*override*/void reset_receiver() { | |
| // nothing to do; no predecesor_cache | | // nothing to do; no predecesor_cache | |
| } | | } | |
| | | | |
|
| }; | | }; // buffer_node | |
| | | | |
| //! Forwards messages in FIFO order | | //! Forwards messages in FIFO order | |
| template <typename T, typename A=cache_aligned_allocator<T> > | | template <typename T, typename A=cache_aligned_allocator<T> > | |
| class queue_node : public buffer_node<T, A> { | | class queue_node : public buffer_node<T, A> { | |
| protected: | | protected: | |
| typedef typename buffer_node<T, A>::size_type size_type; | | typedef typename buffer_node<T, A>::size_type size_type; | |
| typedef typename buffer_node<T, A>::buffer_operation queue_operation; | | typedef typename buffer_node<T, A>::buffer_operation queue_operation; | |
| | | | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| | | | |
|
| //! Tries to forward valid items to successors | | /* override */ void internal_forward_task(queue_operation *op) { | |
| /* override */ void internal_forward(queue_operation *op) { | | | |
| T i_copy; | | | |
| bool success = false; // flagged when a successor accepts | | | |
| size_type counter = this->my_successors.size(); | | | |
| if (this->my_reserved || !this->item_valid(this->my_head)) { | | if (this->my_reserved || !this->item_valid(this->my_head)) { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| this->forwarder_busy = false; | | this->forwarder_busy = false; | |
| return; | | return; | |
| } | | } | |
|
| | | T i_copy; | |
| | | task *last_task = NULL; | |
| | | size_type counter = this->my_successors.size(); | |
| // Keep trying to send items while there is at least one accepting
successor | | // Keep trying to send items while there is at least one accepting
successor | |
| while (counter>0 && this->item_valid(this->my_head)) { | | while (counter>0 && this->item_valid(this->my_head)) { | |
| this->fetch_front(i_copy); | | this->fetch_front(i_copy); | |
|
| if(this->my_successors.try_put(i_copy)) { | | task *new_task = this->my_successors.try_put_task(i_copy); | |
| this->invalidate_front(); | | if(new_task) { | |
| ++(this->my_head); | | this->invalidate_front(); | |
| success = true; // found an accepting successor | | ++(this->my_head); | |
| | | last_task = combine_tasks(last_task, new_task); | |
| } | | } | |
| --counter; | | --counter; | |
| } | | } | |
|
| if (success && !counter) | | op->ltask = last_task; | |
| | | if (last_task && !counter) | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| else { | | else { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| this->forwarder_busy = false; | | this->forwarder_busy = false; | |
| } | | } | |
| } | | } | |
| | | | |
| /* override */ void internal_pop(queue_operation *op) { | | /* override */ void internal_pop(queue_operation *op) { | |
| if ( this->my_reserved || !this->item_valid(this->my_head)){ | | if ( this->my_reserved || !this->item_valid(this->my_head)){ | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| | | | |
| skipping to change at line 1456 | | skipping to change at line 1578 | |
| base_type::reset(); | | base_type::reset(); | |
| } | | } | |
| | | | |
| typedef typename buffer_node<T, A>::size_type size_type; | | typedef typename buffer_node<T, A>::size_type size_type; | |
| typedef typename buffer_node<T, A>::item_type item_type; | | typedef typename buffer_node<T, A>::item_type item_type; | |
| typedef typename buffer_node<T, A>::buffer_operation prio_operation; | | typedef typename buffer_node<T, A>::buffer_operation prio_operation; | |
| | | | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| | | | |
| /* override */ void handle_operations(prio_operation *op_list) { | | /* override */ void handle_operations(prio_operation *op_list) { | |
|
| prio_operation *tmp /*, *pop_list*/ ; | | prio_operation *tmp = op_list /*, *pop_list*/ ; | |
| bool try_forwarding=false; | | bool try_forwarding=false; | |
| while (op_list) { | | while (op_list) { | |
| tmp = op_list; | | tmp = op_list; | |
| op_list = op_list->next; | | op_list = op_list->next; | |
| switch (tmp->type) { | | switch (tmp->type) { | |
| case buffer_node<T, A>::reg_succ: this->internal_reg_succ(tmp);
try_forwarding = true; break; | | case buffer_node<T, A>::reg_succ: this->internal_reg_succ(tmp);
try_forwarding = true; break; | |
| case buffer_node<T, A>::rem_succ: this->internal_rem_succ(tmp);
break; | | case buffer_node<T, A>::rem_succ: this->internal_rem_succ(tmp);
break; | |
| case buffer_node<T, A>::put_item: internal_push(tmp); try_forwa
rding = true; break; | | case buffer_node<T, A>::put_item: internal_push(tmp); try_forwa
rding = true; break; | |
|
| case buffer_node<T, A>::try_fwd: internal_forward(tmp); break; | | case buffer_node<T, A>::try_fwd_task: internal_forward_task(tmp
); break; | |
| case buffer_node<T, A>::rel_res: internal_release(tmp); try_for
warding = true; break; | | case buffer_node<T, A>::rel_res: internal_release(tmp); try_for
warding = true; break; | |
| case buffer_node<T, A>::con_res: internal_consume(tmp); try_for
warding = true; break; | | case buffer_node<T, A>::con_res: internal_consume(tmp); try_for
warding = true; break; | |
| case buffer_node<T, A>::req_item: internal_pop(tmp); break; | | case buffer_node<T, A>::req_item: internal_pop(tmp); break; | |
| case buffer_node<T, A>::res_item: internal_reserve(tmp); break; | | case buffer_node<T, A>::res_item: internal_reserve(tmp); break; | |
| } | | } | |
| } | | } | |
| // process pops! for now, no special pop processing | | // process pops! for now, no special pop processing | |
| if (mark<this->my_tail) heapify(); | | if (mark<this->my_tail) heapify(); | |
| if (try_forwarding && !this->forwarder_busy) { | | if (try_forwarding && !this->forwarder_busy) { | |
| this->forwarder_busy = true; | | this->forwarder_busy = true; | |
|
| task::enqueue(*new(task::allocate_additional_child_of(*(this->m | | task *new_task = new(task::allocate_additional_child_of(*(this- | |
| y_parent))) internal::forward_task< buffer_node<input_type, A> >(*this)); | | >my_parent))) internal:: | |
| | | forward_task_bypass | |
| | | < buffer_node<input_type, A> >(*this); | |
| | | // tmp should point to the last item handled by the aggregator. | |
| | | This is the operation | |
| | | // the handling thread enqueued. So modifying that record will | |
| | | be okay. | |
| | | tbb::task *tmp1 = tmp->ltask; | |
| | | tmp->ltask = combine_tasks(tmp1, new_task); | |
| } | | } | |
| } | | } | |
| | | | |
| //! Tries to forward valid items to successors | | //! Tries to forward valid items to successors | |
|
| /* override */ void internal_forward(prio_operation *op) { | | /* override */ void internal_forward_task(prio_operation *op) { | |
| T i_copy; | | T i_copy; | |
|
| bool success = false; // flagged when a successor accepts | | task * last_task = NULL; // flagged when a successor accepts | |
| size_type counter = this->my_successors.size(); | | size_type counter = this->my_successors.size(); | |
| | | | |
| if (this->my_reserved || this->my_tail == 0) { | | if (this->my_reserved || this->my_tail == 0) { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| this->forwarder_busy = false; | | this->forwarder_busy = false; | |
| return; | | return; | |
| } | | } | |
| // Keep trying to send while there exists an accepting successor | | // Keep trying to send while there exists an accepting successor | |
| while (counter>0 && this->my_tail > 0) { | | while (counter>0 && this->my_tail > 0) { | |
| i_copy = this->my_array[0].first; | | i_copy = this->my_array[0].first; | |
|
| bool msg = this->my_successors.try_put(i_copy); | | task * new_task = this->my_successors.try_put_task(i_copy); | |
| if ( msg == true ) { | | last_task = combine_tasks(last_task, new_task); | |
| | | if ( new_task ) { | |
| if (mark == this->my_tail) --mark; | | if (mark == this->my_tail) --mark; | |
| --(this->my_tail); | | --(this->my_tail); | |
| this->my_array[0].first=this->my_array[this->my_tail].first
; | | this->my_array[0].first=this->my_array[this->my_tail].first
; | |
| if (this->my_tail > 1) // don't reheap for heap of size 1 | | if (this->my_tail > 1) // don't reheap for heap of size 1 | |
| reheap(); | | reheap(); | |
|
| success = true; // found an accepting successor | | | |
| } | | } | |
| --counter; | | --counter; | |
| } | | } | |
|
| if (success && !counter) | | op->ltask = last_task; | |
| | | if (last_task && !counter) | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| else { | | else { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| this->forwarder_busy = false; | | this->forwarder_busy = false; | |
| } | | } | |
| } | | } | |
| | | | |
| /* override */ void internal_push(prio_operation *op) { | | /* override */ void internal_push(prio_operation *op) { | |
| if ( this->my_tail >= this->my_array_size ) | | if ( this->my_tail >= this->my_array_size ) | |
| this->grow_my_array( this->my_tail + 1 ); | | this->grow_my_array( this->my_tail + 1 ); | |
| this->my_array[this->my_tail] = std::make_pair( *(op->elem), true )
; | | this->my_array[this->my_tail] = std::make_pair( *(op->elem), true )
; | |
| ++(this->my_tail); | | ++(this->my_tail); | |
| __TBB_store_with_release(op->status, SUCCEEDED); | | __TBB_store_with_release(op->status, SUCCEEDED); | |
| } | | } | |
|
| | | | |
| /* override */ void internal_pop(prio_operation *op) { | | /* override */ void internal_pop(prio_operation *op) { | |
| if ( this->my_reserved == true || this->my_tail == 0 ) { | | if ( this->my_reserved == true || this->my_tail == 0 ) { | |
| __TBB_store_with_release(op->status, FAILED); | | __TBB_store_with_release(op->status, FAILED); | |
| } | | } | |
| else { | | else { | |
| if (mark<this->my_tail && | | if (mark<this->my_tail && | |
| compare(this->my_array[0].first, | | compare(this->my_array[0].first, | |
| this->my_array[this->my_tail-1].first)) { | | this->my_array[this->my_tail-1].first)) { | |
| // there are newly pushed elems; last one higher than top | | // there are newly pushed elems; last one higher than top | |
| // copy the data | | // copy the data | |
| | | | |
| skipping to change at line 1620 | | skipping to change at line 1750 | |
| this->my_array[cur_pos].first = this->my_array[this->my_tail].first
; | | this->my_array[cur_pos].first = this->my_array[this->my_tail].first
; | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! Forwards messages only if the threshold has not been reached | | //! Forwards messages only if the threshold has not been reached | |
| /** This node forwards items until its threshold is reached. | | /** This node forwards items until its threshold is reached. | |
| It contains no buffering. If the downstream node rejects, the | | It contains no buffering. If the downstream node rejects, the | |
| message is dropped. */ | | message is dropped. */ | |
| template< typename T > | | template< typename T > | |
| class limiter_node : public graph_node, public receiver< T >, public sender
< T > { | | class limiter_node : public graph_node, public receiver< T >, public sender
< T > { | |
|
| | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| | | | |
| private: | | private: | |
| task *my_root_task; | | task *my_root_task; | |
| size_t my_threshold; | | size_t my_threshold; | |
| size_t my_count; | | size_t my_count; | |
| internal::predecessor_cache< T > my_predecessors; | | internal::predecessor_cache< T > my_predecessors; | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| internal::broadcast_cache< T > my_successors; | | internal::broadcast_cache< T > my_successors; | |
| int init_decrement_predecessors; | | int init_decrement_predecessors; | |
| | | | |
|
| friend class internal::forward_task< limiter_node<T> >; | | friend class internal::forward_task_bypass< limiter_node<T> >; | |
| | | | |
| // Let decrementer call decrement_counter() | | // Let decrementer call decrement_counter() | |
| friend class internal::decrementer< limiter_node<T> >; | | friend class internal::decrementer< limiter_node<T> >; | |
| | | | |
|
| void decrement_counter() { | | // only returns a valid task pointer or NULL, never SUCCESSFULLY_ENQUEU | |
| | | ED | |
| | | task * decrement_counter() { | |
| input_type v; | | input_type v; | |
|
| | | task *rval = NULL; | |
| | | | |
| // If we can't get / put an item immediately then drop the count | | // If we can't get / put an item immediately then drop the count | |
| if ( my_predecessors.get_item( v ) == false | | if ( my_predecessors.get_item( v ) == false | |
|
| || my_successors.try_put(v) == false ) { | | || (rval = my_successors.try_put_task(v)) == NULL ) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| --my_count; | | --my_count; | |
|
| if ( !my_predecessors.empty() ) | | if ( !my_predecessors.empty() ) { | |
| task::enqueue( * new ( task::allocate_additional_child_of( | | task *rtask = new ( task::allocate_additional_child_of( *my | |
| *my_root_task ) ) | | _root_task ) ) | |
| internal::forward_task< limiter_node<T> >( *thi | | internal::forward_task_bypass< limiter_node<T> >( *this | |
| s ) ); | | ); | |
| | | __TBB_ASSERT(!rval, "Have two tasks to handle"); | |
| | | return rtask; | |
| | | } | |
| } | | } | |
|
| | | return rval; | |
| } | | } | |
| | | | |
| void forward() { | | void forward() { | |
| { | | { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| if ( my_count < my_threshold ) | | if ( my_count < my_threshold ) | |
| ++my_count; | | ++my_count; | |
| else | | else | |
| return; | | return; | |
| } | | } | |
|
| decrement_counter(); | | task * rtask = decrement_counter(); | |
| | | if(rtask) task::enqueue(*rtask); | |
| | | } | |
| | | | |
| | | task *forward_task() { | |
| | | spin_mutex::scoped_lock lock(my_mutex); | |
| | | if ( my_count >= my_threshold ) | |
| | | return NULL; | |
| | | ++my_count; | |
| | | task * rtask = decrement_counter(); | |
| | | return rtask; | |
| } | | } | |
| | | | |
| public: | | public: | |
| //! The internal receiver< continue_msg > that decrements the count | | //! The internal receiver< continue_msg > that decrements the count | |
| internal::decrementer< limiter_node<T> > decrement; | | internal::decrementer< limiter_node<T> > decrement; | |
| | | | |
| //! Constructor | | //! Constructor | |
| limiter_node(graph &g, size_t threshold, int num_decrement_predecessors
=0) : | | limiter_node(graph &g, size_t threshold, int num_decrement_predecessors
=0) : | |
| graph_node(g), my_root_task(g.root_task()), my_threshold(threshold)
, my_count(0), | | graph_node(g), my_root_task(g.root_task()), my_threshold(threshold)
, my_count(0), | |
| init_decrement_predecessors(num_decrement_predecessors), | | init_decrement_predecessors(num_decrement_predecessors), | |
| | | | |
| skipping to change at line 1707 | | skipping to change at line 1854 | |
| } | | } | |
| | | | |
| //! Removes a successor from this node | | //! Removes a successor from this node | |
| /** r.remove_predecessor(*this) is also called. */ | | /** r.remove_predecessor(*this) is also called. */ | |
| /* override */ bool remove_successor( receiver<output_type> &r ) { | | /* override */ bool remove_successor( receiver<output_type> &r ) { | |
| r.remove_predecessor(*this); | | r.remove_predecessor(*this); | |
| my_successors.remove_successor(r); | | my_successors.remove_successor(r); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
|
| //! Puts an item to this receiver | | | |
| /* override */ bool try_put( const T &t ) { | | | |
| { | | | |
| spin_mutex::scoped_lock lock(my_mutex); | | | |
| if ( my_count >= my_threshold ) | | | |
| return false; | | | |
| else | | | |
| ++my_count; | | | |
| } | | | |
| | | | |
| bool msg = my_successors.try_put(t); | | | |
| | | | |
| if ( msg != true ) { | | | |
| spin_mutex::scoped_lock lock(my_mutex); | | | |
| --my_count; | | | |
| if ( !my_predecessors.empty() ) | | | |
| task::enqueue( * new ( task::allocate_additional_child_of( | | | |
| *my_root_task ) ) | | | |
| internal::forward_task< limiter_node<T> >( *thi | | | |
| s ) ); | | | |
| } | | | |
| | | | |
| return msg; | | | |
| } | | | |
| | | | |
| //! Removes src from the list of cached predecessors. | | //! Removes src from the list of cached predecessors. | |
| /* override */ bool register_predecessor( predecessor_type &src ) { | | /* override */ bool register_predecessor( predecessor_type &src ) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| my_predecessors.add( src ); | | my_predecessors.add( src ); | |
|
| if ( my_count < my_threshold && !my_successors.empty() ) | | if ( my_count < my_threshold && !my_successors.empty() ) { | |
| task::enqueue( * new ( task::allocate_additional_child_of( *my_
root_task ) ) | | task::enqueue( * new ( task::allocate_additional_child_of( *my_
root_task ) ) | |
|
| internal::forward_task< limiter_node<T> >( *this | | internal:: | |
| ) ); | | forward_task_bypass | |
| | | < limiter_node<T> >( *this ) ); | |
| | | } | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| //! Removes src from the list of cached predecessors. | | //! Removes src from the list of cached predecessors. | |
| /* override */ bool remove_predecessor( predecessor_type &src ) { | | /* override */ bool remove_predecessor( predecessor_type &src ) { | |
| my_predecessors.remove( src ); | | my_predecessors.remove( src ); | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| | | | |
|
| | | template< typename R, typename B > friend class run_and_put_task; | |
| | | template<typename X, typename Y> friend class internal::broadcast_cache | |
| | | ; | |
| | | template<typename X, typename Y> friend class internal::round_robin_cac | |
| | | he; | |
| | | //! Puts an item to this receiver | |
| | | /* override */ task *try_put_task( const T &t ) { | |
| | | { | |
| | | spin_mutex::scoped_lock lock(my_mutex); | |
| | | if ( my_count >= my_threshold ) | |
| | | return NULL; | |
| | | else | |
| | | ++my_count; | |
| | | } | |
| | | | |
| | | task * rtask = my_successors.try_put_task(t); | |
| | | | |
| | | if ( !rtask ) { // try_put_task failed. | |
| | | spin_mutex::scoped_lock lock(my_mutex); | |
| | | --my_count; | |
| | | if ( !my_predecessors.empty() ) { | |
| | | rtask = new ( task::allocate_additional_child_of( *my_root_ | |
| | | task ) ) | |
| | | internal::forward_task_bypass< limiter_node<T> >( *this | |
| | | ); | |
| | | } | |
| | | } | |
| | | return rtask; | |
| | | } | |
| | | | |
| /*override*/void reset() { | | /*override*/void reset() { | |
| my_count = 0; | | my_count = 0; | |
| my_predecessors.reset(); | | my_predecessors.reset(); | |
| decrement.reset_receiver(); | | decrement.reset_receiver(); | |
| } | | } | |
| | | | |
| /*override*/void reset_receiver() { my_predecessors.reset(); } | | /*override*/void reset_receiver() { my_predecessors.reset(); } | |
|
| }; | | }; // limiter_node | |
| | | | |
| #include "internal/_flow_graph_join_impl.h" | | #include "internal/_flow_graph_join_impl.h" | |
| | | | |
| using internal::reserving_port; | | using internal::reserving_port; | |
| using internal::queueing_port; | | using internal::queueing_port; | |
| using internal::tag_matching_port; | | using internal::tag_matching_port; | |
| using internal::input_port; | | using internal::input_port; | |
| using internal::tag_value; | | using internal::tag_value; | |
| using internal::NO_TAG; | | using internal::NO_TAG; | |
| | | | |
| template<typename OutputTuple, graph_buffer_policy JP=queueing> class join_
node; | | template<typename OutputTuple, graph_buffer_policy JP=queueing> class join_
node; | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
|
| class join_node<OutputTuple,reserving>: public internal::unfolded_join_node
<std::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, reservin
g> { | | class join_node<OutputTuple,reserving>: public internal::unfolded_join_node
<tbb::flow::tuple_size<OutputTuple>::value, reserving_port, OutputTuple, re
serving> { | |
| private: | | private: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef typename internal::unfolded_join_node<N, reserving_port, Output
Tuple, reserving> unfolded_type; | | typedef typename internal::unfolded_join_node<N, reserving_port, Output
Tuple, reserving> unfolded_type; | |
| public: | | public: | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef typename unfolded_type::input_ports_type input_ports_type; | | typedef typename unfolded_type::input_ports_type input_ports_type; | |
| join_node(graph &g) : unfolded_type(g) { } | | join_node(graph &g) : unfolded_type(g) { } | |
| join_node(const join_node &other) : unfolded_type(other) {} | | join_node(const join_node &other) : unfolded_type(other) {} | |
| }; | | }; | |
| | | | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
|
| class join_node<OutputTuple,queueing>: public internal::unfolded_join_node<
std::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queueing>
{ | | class join_node<OutputTuple,queueing>: public internal::unfolded_join_node<
tbb::flow::tuple_size<OutputTuple>::value, queueing_port, OutputTuple, queu
eing> { | |
| private: | | private: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef typename internal::unfolded_join_node<N, queueing_port, OutputT
uple, queueing> unfolded_type; | | typedef typename internal::unfolded_join_node<N, queueing_port, OutputT
uple, queueing> unfolded_type; | |
| public: | | public: | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef typename unfolded_type::input_ports_type input_ports_type; | | typedef typename unfolded_type::input_ports_type input_ports_type; | |
| join_node(graph &g) : unfolded_type(g) { } | | join_node(graph &g) : unfolded_type(g) { } | |
| join_node(const join_node &other) : unfolded_type(other) {} | | join_node(const join_node &other) : unfolded_type(other) {} | |
| }; | | }; | |
| | | | |
| // template for tag_matching join_node | | // template for tag_matching join_node | |
| template<typename OutputTuple> | | template<typename OutputTuple> | |
|
| class join_node<OutputTuple, tag_matching> : public internal::unfolded_join
_node<std::tuple_size<OutputTuple>::value, | | class join_node<OutputTuple, tag_matching> : public internal::unfolded_join
_node<tbb::flow::tuple_size<OutputTuple>::value, | |
| tag_matching_port, OutputTuple, tag_matching> { | | tag_matching_port, OutputTuple, tag_matching> { | |
| private: | | private: | |
|
| static const int N = std::tuple_size<OutputTuple>::value; | | static const int N = tbb::flow::tuple_size<OutputTuple>::value; | |
| typedef typename internal::unfolded_join_node<N, tag_matching_port, Out
putTuple, tag_matching> unfolded_type; | | typedef typename internal::unfolded_join_node<N, tag_matching_port, Out
putTuple, tag_matching> unfolded_type; | |
| public: | | public: | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| typedef typename unfolded_type::input_ports_type input_ports_type; | | typedef typename unfolded_type::input_ports_type input_ports_type; | |
| template<typename B0, typename B1> | | template<typename B0, typename B1> | |
| join_node(graph &g, B0 b0, B1 b1) : unfolded_type(g, b0, b1) { } | | join_node(graph &g, B0 b0, B1 b1) : unfolded_type(g, b0, b1) { } | |
| template<typename B0, typename B1, typename B2> | | template<typename B0, typename B1, typename B2> | |
| join_node(graph &g, B0 b0, B1 b1, B2 b2) : unfolded_type(g, b0, b1, b2)
{ } | | join_node(graph &g, B0 b0, B1 b1, B2 b2) : unfolded_type(g, b0, b1, b2)
{ } | |
| template<typename B0, typename B1, typename B2, typename B3> | | template<typename B0, typename B1, typename B2, typename B3> | |
| join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : unfolded_type(g, b0,
b1, b2, b3) { } | | join_node(graph &g, B0 b0, B1 b1, B2 b2, B3 b3) : unfolded_type(g, b0,
b1, b2, b3) { } | |
| | | | |
| skipping to change at line 1840 | | skipping to change at line 1993 | |
| join_node(const join_node &other) : unfolded_type(other) {} | | join_node(const join_node &other) : unfolded_type(other) {} | |
| }; | | }; | |
| | | | |
| #if TBB_PREVIEW_GRAPH_NODES | | #if TBB_PREVIEW_GRAPH_NODES | |
| // or node | | // or node | |
| #include "internal/_flow_graph_or_impl.h" | | #include "internal/_flow_graph_or_impl.h" | |
| | | | |
| template<typename InputTuple> | | template<typename InputTuple> | |
| class or_node : public internal::unfolded_or_node<InputTuple> { | | class or_node : public internal::unfolded_or_node<InputTuple> { | |
| private: | | private: | |
|
| static const int N = std::tuple_size<InputTuple>::value; | | static const int N = tbb::flow::tuple_size<InputTuple>::value; | |
| public: | | public: | |
| typedef typename internal::or_output_type<InputTuple>::type output_type
; | | typedef typename internal::or_output_type<InputTuple>::type output_type
; | |
| typedef typename internal::unfolded_or_node<InputTuple> unfolded_type; | | typedef typename internal::unfolded_or_node<InputTuple> unfolded_type; | |
| or_node(graph& g) : unfolded_type(g) { } | | or_node(graph& g) : unfolded_type(g) { } | |
| // Copy constructor | | // Copy constructor | |
| or_node( const or_node& other ) : unfolded_type(other) { } | | or_node( const or_node& other ) : unfolded_type(other) { } | |
| }; | | }; | |
| #endif // TBB_PREVIEW_GRAPH_NODES | | #endif // TBB_PREVIEW_GRAPH_NODES | |
| | | | |
| //! Makes an edge between a single predecessor and a single successor | | //! Makes an edge between a single predecessor and a single successor | |
| | | | |
End of changes. 115 change blocks. |
| 157 lines changed or deleted | | 344 lines changed or added | |
|
| parallel_for.h | | parallel_for.h | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 84 | |
| my_body(parent_.my_body), | | my_body(parent_.my_body), | |
| my_partition(parent_.my_partition,split()) | | my_partition(parent_.my_partition,split()) | |
| { | | { | |
| my_partition.set_affinity(*this); | | my_partition.set_affinity(*this); | |
| my_partition.align_depth( d ); | | my_partition.align_depth( d ); | |
| } | | } | |
| //! Update affinity info, if any. | | //! Update affinity info, if any. | |
| /*override*/ void note_affinity( affinity_id id ) { | | /*override*/ void note_affinity( affinity_id id ) { | |
| my_partition.note_affinity( id ); | | my_partition.note_affinity( id ); | |
| } | | } | |
|
| static void run( const Range& range, const Body& body, const Parti
tioner& partitioner ) { | | static void run( const Range& range, const Body& body, Partitioner
& partitioner ) { | |
| if( !range.empty() ) { | | if( !range.empty() ) { | |
| #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP | | #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP | |
|
| start_for& a = *new(task::allocate_root()) start_for(range,
body,const_cast<Partitioner&>(partitioner)); | | start_for& a = *new(task::allocate_root()) start_for(range,
body,partitioner); | |
| #else | | #else | |
| // Bound context prevents exceptions from body to affect ne
sting or sibling algorithms, | | // Bound context prevents exceptions from body to affect ne
sting or sibling algorithms, | |
| // and allows users to handle exceptions safely by wrapping
parallel_for in the try-block. | | // and allows users to handle exceptions safely by wrapping
parallel_for in the try-block. | |
| task_group_context context; | | task_group_context context; | |
|
| start_for& a = *new(task::allocate_root(context)) start_for
(range,body,const_cast<Partitioner&>(partitioner)); | | start_for& a = *new(task::allocate_root(context)) start_for
(range,body,partitioner); | |
| #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */ | | #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */ | |
| task::spawn_root_and_wait(a); | | task::spawn_root_and_wait(a); | |
| } | | } | |
| } | | } | |
| #if __TBB_TASK_GROUP_CONTEXT | | #if __TBB_TASK_GROUP_CONTEXT | |
|
| static void run( const Range& range, const Body& body, const Parti
tioner& partitioner, task_group_context& context ) { | | static void run( const Range& range, const Body& body, Partitioner
& partitioner, task_group_context& context ) { | |
| if( !range.empty() ) { | | if( !range.empty() ) { | |
|
| start_for& a = *new(task::allocate_root(context)) start_for
(range,body,const_cast<Partitioner&>(partitioner)); | | start_for& a = *new(task::allocate_root(context)) start_for
(range,body,partitioner); | |
| task::spawn_root_and_wait(a); | | task::spawn_root_and_wait(a); | |
| } | | } | |
| } | | } | |
| #endif /* __TBB_TASK_GROUP_CONTEXT */ | | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |
| //! create a continuation task, serve as callback for partitioner | | //! create a continuation task, serve as callback for partitioner | |
| flag_task *create_continuation() { | | flag_task *create_continuation() { | |
| return new( allocate_continuation() ) flag_task(); | | return new( allocate_continuation() ) flag_task(); | |
| } | | } | |
| //! Run body for range | | //! Run body for range | |
| void run_body( Range &r ) { my_body( r ); } | | void run_body( Range &r ) { my_body( r ); } | |
| | | | |
| skipping to change at line 138 | | skipping to change at line 138 | |
| template<typename Function, typename Index> | | template<typename Function, typename Index> | |
| class parallel_for_body : internal::no_assign { | | class parallel_for_body : internal::no_assign { | |
| const Function &my_func; | | const Function &my_func; | |
| const Index my_begin; | | const Index my_begin; | |
| const Index my_step; | | const Index my_step; | |
| public: | | public: | |
| parallel_for_body( const Function& _func, Index& _begin, Index& _st
ep) | | parallel_for_body( const Function& _func, Index& _begin, Index& _st
ep) | |
| : my_func(_func), my_begin(_begin), my_step(_step) {} | | : my_func(_func), my_begin(_begin), my_step(_step) {} | |
| | | | |
| void operator()( tbb::blocked_range<Index>& r ) const { | | void operator()( tbb::blocked_range<Index>& r ) const { | |
|
| | | #if __INTEL_COMPILER | |
| | | #pragma ivdep | |
| | | #endif | |
| for( Index i = r.begin(), k = my_begin + i * my_step; i < r.en
d(); i++, k = k + my_step) | | for( Index i = r.begin(), k = my_begin + i * my_step; i < r.en
d(); i++, k = k + my_step) | |
| my_func( k ); | | my_func( k ); | |
| } | | } | |
| }; | | }; | |
| } // namespace internal | | } // namespace internal | |
| //! @endcond | | //! @endcond | |
| | | | |
| // Requirements on Range concept are documented in blocked_range.h | | // Requirements on Range concept are documented in blocked_range.h | |
| | | | |
| /** \page parallel_for_body_req Requirements on parallel_for body | | /** \page parallel_for_body_req Requirements on parallel_for body | |
| | | | |
| skipping to change at line 162 | | skipping to change at line 165 | |
| **/ | | **/ | |
| | | | |
| /** \name parallel_for | | /** \name parallel_for | |
| See also requirements on \ref range_req "Range" and \ref parallel_for_b
ody_req "parallel_for Body". **/ | | See also requirements on \ref range_req "Range" and \ref parallel_for_b
ody_req "parallel_for Body". **/ | |
| //@{ | | //@{ | |
| | | | |
| //! Parallel iteration over range with default partitioner. | | //! Parallel iteration over range with default partitioner. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body ) { | | void parallel_for( const Range& range, const Body& body ) { | |
|
| internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,bo
dy,__TBB_DEFAULT_PARTITIONER()); | | internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(ra
nge,body,__TBB_DEFAULT_PARTITIONER()); | |
| } | | } | |
| | | | |
| //! Parallel iteration over range with simple partitioner. | | //! Parallel iteration over range with simple partitioner. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, const simple_parti
tioner& partitioner ) { | | void parallel_for( const Range& range, const Body& body, const simple_parti
tioner& partitioner ) { | |
|
| internal::start_for<Range,Body,simple_partitioner>::run(range,body,part
itioner); | | internal::start_for<Range,Body,const simple_partitioner>::run(range,bod
y,partitioner); | |
| } | | } | |
| | | | |
| //! Parallel iteration over range with auto_partitioner. | | //! Parallel iteration over range with auto_partitioner. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, const auto_partiti
oner& partitioner ) { | | void parallel_for( const Range& range, const Body& body, const auto_partiti
oner& partitioner ) { | |
|
| internal::start_for<Range,Body,auto_partitioner>::run(range,body,partit
ioner); | | internal::start_for<Range,Body,const auto_partitioner>::run(range,body,
partitioner); | |
| } | | } | |
| | | | |
| //! Parallel iteration over range with affinity_partitioner. | | //! Parallel iteration over range with affinity_partitioner. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, affinity_partition
er& partitioner ) { | | void parallel_for( const Range& range, const Body& body, affinity_partition
er& partitioner ) { | |
| internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa
rtitioner); | | internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa
rtitioner); | |
| } | | } | |
| | | | |
| #if __TBB_TASK_GROUP_CONTEXT | | #if __TBB_TASK_GROUP_CONTEXT | |
|
| | | //! Parallel iteration over range with default partitioner and user-supplie | |
| | | d context. | |
| | | /** @ingroup algorithms **/ | |
| | | template<typename Range, typename Body> | |
| | | void parallel_for( const Range& range, const Body& body, task_group_context | |
| | | & context ) { | |
| | | internal::start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(ra | |
| | | nge, body, __TBB_DEFAULT_PARTITIONER(), context); | |
| | | } | |
| | | | |
| //! Parallel iteration over range with simple partitioner and user-supplied
context. | | //! Parallel iteration over range with simple partitioner and user-supplied
context. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, const simple_parti
tioner& partitioner, task_group_context& context ) { | | void parallel_for( const Range& range, const Body& body, const simple_parti
tioner& partitioner, task_group_context& context ) { | |
|
| internal::start_for<Range,Body,simple_partitioner>::run(range, body, pa
rtitioner, context); | | internal::start_for<Range,Body,const simple_partitioner>::run(range, bo
dy, partitioner, context); | |
| } | | } | |
| | | | |
| //! Parallel iteration over range with auto_partitioner and user-supplied c
ontext. | | //! Parallel iteration over range with auto_partitioner and user-supplied c
ontext. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, const auto_partiti
oner& partitioner, task_group_context& context ) { | | void parallel_for( const Range& range, const Body& body, const auto_partiti
oner& partitioner, task_group_context& context ) { | |
|
| internal::start_for<Range,Body,auto_partitioner>::run(range, body, part
itioner, context); | | internal::start_for<Range,Body,const auto_partitioner>::run(range, body
, partitioner, context); | |
| } | | } | |
| | | | |
| //! Parallel iteration over range with affinity_partitioner and user-suppli
ed context. | | //! Parallel iteration over range with affinity_partitioner and user-suppli
ed context. | |
| /** @ingroup algorithms **/ | | /** @ingroup algorithms **/ | |
| template<typename Range, typename Body> | | template<typename Range, typename Body> | |
| void parallel_for( const Range& range, const Body& body, affinity_partition
er& partitioner, task_group_context& context ) { | | void parallel_for( const Range& range, const Body& body, affinity_partition
er& partitioner, task_group_context& context ) { | |
| internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa
rtitioner, context); | | internal::start_for<Range,Body,affinity_partitioner>::run(range,body,pa
rtitioner, context); | |
| } | | } | |
| #endif /* __TBB_TASK_GROUP_CONTEXT */ | | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |
| //@} | | //@} | |
| | | | |
| namespace strict_ppl { | | namespace strict_ppl { | |
| | | | |
| //@{ | | //@{ | |
|
| //! Parallel iteration over a range of integers with a step provided | | //! Implementation of parallel iteration over stepped range of integers wit | |
| template <typename Index, typename Function> | | h explicit step and partitioner | |
| void parallel_for(Index first, Index last, Index step, const Function& f) { | | template <typename Index, typename Function, typename Partitioner> | |
| | | void parallel_for_impl(Index first, Index last, Index step, const Function& | |
| | | f, Partitioner& partitioner) { | |
| if (step <= 0 ) | | if (step <= 0 ) | |
| internal::throw_exception(internal::eid_nonpositive_step); // throw
s std::invalid_argument | | internal::throw_exception(internal::eid_nonpositive_step); // throw
s std::invalid_argument | |
| else if (last > first) { | | else if (last > first) { | |
| // Above "else" avoids "potential divide by zero" warning on some p
latforms | | // Above "else" avoids "potential divide by zero" warning on some p
latforms | |
| Index end = (last - first - Index(1)) / step + Index(1); | | Index end = (last - first - Index(1)) / step + Index(1); | |
| tbb::blocked_range<Index> range(static_cast<Index>(0), end); | | tbb::blocked_range<Index> range(static_cast<Index>(0), end); | |
| internal::parallel_for_body<Function, Index> body(f, first, step); | | internal::parallel_for_body<Function, Index> body(f, first, step); | |
|
| tbb::parallel_for(range, body, tbb::auto_partitioner()); | | tbb::parallel_for(range, body, partitioner); | |
| } | | } | |
| } | | } | |
|
| //! Parallel iteration over a range of integers with a default step value | | | |
| | | //! Parallel iteration over a range of integers with a step provided and de | |
| | | fault partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tep, f, auto_partitioner()); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a step provided and si | |
| | | mple partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, c | |
| | | onst simple_partitioner& partitioner) { | |
| | | parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | |
| | | step, f, partitioner); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a step provided and au | |
| | | to partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, c | |
| | | onst auto_partitioner& partitioner) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tep, f, partitioner); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a step provided and af | |
| | | finity partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, a | |
| | | ffinity_partitioner& partitioner) { | |
| | | parallel_for_impl(first, last, step, f, partitioner); | |
| | | } | |
| | | | |
| | | //! Parallel iteration over a range of integers with a default step value a | |
| | | nd default partitioner | |
| template <typename Index, typename Function> | | template <typename Index, typename Function> | |
| void parallel_for(Index first, Index last, const Function& f) { | | void parallel_for(Index first, Index last, const Function& f) { | |
|
| parallel_for(first, last, static_cast<Index>(1), f); | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tatic_cast<Index>(1), f, auto_partitioner()); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a default step value a | |
| | | nd simple partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, const Function& f, const simple_ | |
| | | partitioner& partitioner) { | |
| | | parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | |
| | | static_cast<Index>(1), f, partitioner); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a default step value a | |
| | | nd auto partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, const Function& f, const auto_pa | |
| | | rtitioner& partitioner) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tatic_cast<Index>(1), f, partitioner); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a default step value a | |
| | | nd affinity partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, const Function& f, affinity_part | |
| | | itioner& partitioner) { | |
| | | parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner); | |
| } | | } | |
| | | | |
| #if __TBB_TASK_GROUP_CONTEXT | | #if __TBB_TASK_GROUP_CONTEXT | |
|
| //! Parallel iteration over a range of integers with explicit step and task | | //! Implementation of parallel iteration over stepped range of integers wit | |
| group context | | h explicit step, task group context, and partitioner | |
| template <typename Index, typename Function> | | template <typename Index, typename Function, typename Partitioner> | |
| void parallel_for(Index first, Index last, Index step, const Function& f, t | | void parallel_for_impl(Index first, Index last, Index step, const Function& | |
| bb::task_group_context &context) { | | f, Partitioner& partitioner, tbb::task_group_context &context) { | |
| if (step <= 0 ) | | if (step <= 0 ) | |
| internal::throw_exception(internal::eid_nonpositive_step); // throw
s std::invalid_argument | | internal::throw_exception(internal::eid_nonpositive_step); // throw
s std::invalid_argument | |
| else if (last > first) { | | else if (last > first) { | |
| // Above "else" avoids "potential divide by zero" warning on some p
latforms | | // Above "else" avoids "potential divide by zero" warning on some p
latforms | |
| Index end = (last - first - Index(1)) / step + Index(1); | | Index end = (last - first - Index(1)) / step + Index(1); | |
| tbb::blocked_range<Index> range(static_cast<Index>(0), end); | | tbb::blocked_range<Index> range(static_cast<Index>(0), end); | |
| internal::parallel_for_body<Function, Index> body(f, first, step); | | internal::parallel_for_body<Function, Index> body(f, first, step); | |
|
| tbb::parallel_for(range, body, tbb::auto_partitioner(), context); | | tbb::parallel_for(range, body, partitioner, context); | |
| } | | } | |
| } | | } | |
|
| //! Parallel iteration over a range of integers with a default step value a | | | |
| nd explicit task group context | | //! Parallel iteration over a range of integers with explicit step, task gr | |
| | | oup context, and default partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, t | |
| | | bb::task_group_context &context) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tep, f, auto_partitioner(), context); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with explicit step, task gr | |
| | | oup context, and simple partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, c | |
| | | onst simple_partitioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | |
| | | step, f, partitioner, context); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with explicit step, task gr | |
| | | oup context, and auto partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, c | |
| | | onst auto_partitioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tep, f, partitioner, context); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with explicit step, task gr | |
| | | oup context, and affinity partitioner | |
| | | template <typename Index, typename Function> | |
| | | void parallel_for(Index first, Index last, Index step, const Function& f, a | |
| | | ffinity_partitioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl(first, last, step, f, partitioner, context); | |
| | | } | |
| | | | |
| | | //! Parallel iteration over a range of integers with a default step value, | |
| | | explicit task group context, and default partitioner | |
| template <typename Index, typename Function> | | template <typename Index, typename Function> | |
| void parallel_for(Index first, Index last, const Function& f, tbb::task_gro
up_context &context) { | | void parallel_for(Index first, Index last, const Function& f, tbb::task_gro
up_context &context) { | |
|
| parallel_for(first, last, static_cast<Index>(1), f, context); | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s
tatic_cast<Index>(1), f, auto_partitioner(), context); | |
| } | | } | |
|
| | | //! Parallel iteration over a range of integers with a default step value, | |
| | | explicit task group context, and simple partitioner | |
| | | template <typename Index, typename Function, typename Partitioner> | |
| | | void parallel_for(Index first, Index last, const Function& f, const simple_ | |
| | | partitioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl<Index,Function,const simple_partitioner>(first, last, | |
| | | static_cast<Index>(1), f, partitioner, context); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a default step value, | |
| | | explicit task group context, and auto partitioner | |
| | | template <typename Index, typename Function, typename Partitioner> | |
| | | void parallel_for(Index first, Index last, const Function& f, const auto_pa | |
| | | rtitioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl<Index,Function,const auto_partitioner>(first, last, s | |
| | | tatic_cast<Index>(1), f, partitioner, context); | |
| | | } | |
| | | //! Parallel iteration over a range of integers with a default step value, | |
| | | explicit task group context, and affinity_partitioner | |
| | | template <typename Index, typename Function, typename Partitioner> | |
| | | void parallel_for(Index first, Index last, const Function& f, affinity_part | |
| | | itioner& partitioner, tbb::task_group_context &context) { | |
| | | parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner, c | |
| | | ontext); | |
| | | } | |
| | | | |
| #endif /* __TBB_TASK_GROUP_CONTEXT */ | | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |
| //@} | | //@} | |
| | | | |
| } // namespace strict_ppl | | } // namespace strict_ppl | |
| | | | |
| using strict_ppl::parallel_for; | | using strict_ppl::parallel_for; | |
| | | | |
| } // namespace tbb | | } // namespace tbb | |
| | | | |
| #if TBB_PREVIEW_SERIAL_SUBSET | | #if TBB_PREVIEW_SERIAL_SUBSET | |
| | | | |
End of changes. 21 change blocks. |
| 25 lines changed or deleted | | 155 lines changed or added | |
|
| tuple | | tuple | |
| | | | |
| skipping to change at line 40 | | skipping to change at line 40 | |
| #define __TBB_tuple_H | | #define __TBB_tuple_H | |
| | | | |
| #include <utility> | | #include <utility> | |
| #include "../tbb_stddef.h" | | #include "../tbb_stddef.h" | |
| | | | |
| // build preprocessor variables for varying number of arguments | | // build preprocessor variables for varying number of arguments | |
| // Need the leading comma so the empty __TBB_T_PACK will not cause a syntax
error. | | // Need the leading comma so the empty __TBB_T_PACK will not cause a syntax
error. | |
| #if __TBB_VARIADIC_MAX <= 5 | | #if __TBB_VARIADIC_MAX <= 5 | |
| #define __TBB_T_PACK | | #define __TBB_T_PACK | |
| #define __TBB_U_PACK | | #define __TBB_U_PACK | |
|
| #define __TBB_CLASS_T_PACK | | #define __TBB_TYPENAME_T_PACK | |
| #define __TBB_CLASS_U_PACK | | #define __TBB_TYPENAME_U_PACK | |
| #define __TBB_NULL_TYPE_PACK | | #define __TBB_NULL_TYPE_PACK | |
| #define __TBB_REF_T_PARAM_PACK | | #define __TBB_REF_T_PARAM_PACK | |
| #define __TBB_CONST_REF_T_PARAM_PACK | | #define __TBB_CONST_REF_T_PARAM_PACK | |
| #define __TBB_T_PARAM_LIST_PACK | | #define __TBB_T_PARAM_LIST_PACK | |
| #define __TBB_CONST_NULL_REF_PACK | | #define __TBB_CONST_NULL_REF_PACK | |
| // | | // | |
| #elif __TBB_VARIADIC_MAX == 6 | | #elif __TBB_VARIADIC_MAX == 6 | |
| #define __TBB_T_PACK ,T5 | | #define __TBB_T_PACK ,T5 | |
| #define __TBB_U_PACK ,U5 | | #define __TBB_U_PACK ,U5 | |
|
| #define __TBB_CLASS_T_PACK , class T5 | | #define __TBB_TYPENAME_T_PACK , typename T5 | |
| #define __TBB_CLASS_U_PACK , class U5 | | #define __TBB_TYPENAME_U_PACK , typename U5 | |
| #define __TBB_NULL_TYPE_PACK , null_type | | #define __TBB_NULL_TYPE_PACK , null_type | |
| #define __TBB_REF_T_PARAM_PACK ,T5& t5 | | #define __TBB_REF_T_PARAM_PACK ,T5& t5 | |
| #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5 | | #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5 | |
| #define __TBB_T_PARAM_LIST_PACK ,t5 | | #define __TBB_T_PARAM_LIST_PACK ,t5 | |
| #define __TBB_CONST_NULL_REF_PACK , const null_type& | | #define __TBB_CONST_NULL_REF_PACK , const null_type& | |
| // | | // | |
| #elif __TBB_VARIADIC_MAX == 7 | | #elif __TBB_VARIADIC_MAX == 7 | |
| #define __TBB_T_PACK ,T5, T6 | | #define __TBB_T_PACK ,T5, T6 | |
| #define __TBB_U_PACK ,U5, U6 | | #define __TBB_U_PACK ,U5, U6 | |
|
| #define __TBB_CLASS_T_PACK , class T5 , class T6 | | #define __TBB_TYPENAME_T_PACK , typename T5 , typename T6 | |
| #define __TBB_CLASS_U_PACK , class U5 , class U6 | | #define __TBB_TYPENAME_U_PACK , typename U5 , typename U6 | |
| #define __TBB_NULL_TYPE_PACK , null_type, null_type | | #define __TBB_NULL_TYPE_PACK , null_type, null_type | |
| #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6 | | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6 | |
| #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5, const T6& t6 | | #define __TBB_CONST_REF_T_PARAM_PACK ,const T5& t5, const T6& t6 | |
| #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 | | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 | |
| #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type& | | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type& | |
| // | | // | |
| #elif __TBB_VARIADIC_MAX == 8 | | #elif __TBB_VARIADIC_MAX == 8 | |
| #define __TBB_T_PACK ,T5, T6, T7 | | #define __TBB_T_PACK ,T5, T6, T7 | |
| #define __TBB_U_PACK ,U5, U6, U7 | | #define __TBB_U_PACK ,U5, U6, U7 | |
|
| #define __TBB_CLASS_T_PACK , class T5 , class T6, class T7 | | #define __TBB_TYPENAME_T_PACK , typename T5 , typename T6, typename T7 | |
| #define __TBB_CLASS_U_PACK , class U5 , class U6, class U7 | | #define __TBB_TYPENAME_U_PACK , typename U5 , typename U6, typename U7 | |
| #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type | | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type | |
| #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7 | | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7 | |
| #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7 | | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7 | |
| #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 | | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 | |
| #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type& | | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type& | |
| // | | // | |
| #elif __TBB_VARIADIC_MAX == 9 | | #elif __TBB_VARIADIC_MAX == 9 | |
| #define __TBB_T_PACK ,T5, T6, T7, T8 | | #define __TBB_T_PACK ,T5, T6, T7, T8 | |
| #define __TBB_U_PACK ,U5, U6, U7, U8 | | #define __TBB_U_PACK ,U5, U6, U7, U8 | |
|
| #define __TBB_CLASS_T_PACK , class T5, class T6, class T7, class T8 | | #define __TBB_TYPENAME_T_PACK , typename T5, typename T6, typename T7, type | |
| #define __TBB_CLASS_U_PACK , class U5, class U6, class U7, class U8 | | name T8 | |
| | | #define __TBB_TYPENAME_U_PACK , typename U5, typename U6, typename U7, type | |
| | | name U8 | |
| #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type | | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type | |
| #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8 | | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8 | |
| #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7, const T8& t8 | | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7, const T8& t8 | |
| #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 | | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 | |
| #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type&, const null_type& | | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type&, const null_type& | |
| // | | // | |
| #elif __TBB_VARIADIC_MAX >= 10 | | #elif __TBB_VARIADIC_MAX >= 10 | |
| #define __TBB_T_PACK ,T5, T6, T7, T8, T9 | | #define __TBB_T_PACK ,T5, T6, T7, T8, T9 | |
| #define __TBB_U_PACK ,U5, U6, U7, U8, U9 | | #define __TBB_U_PACK ,U5, U6, U7, U8, U9 | |
|
| #define __TBB_CLASS_T_PACK , class T5, class T6, class T7, class T8, class | | #define __TBB_TYPENAME_T_PACK , typename T5, typename T6, typename T7, type | |
| T9 | | name T8, typename T9 | |
| #define __TBB_CLASS_U_PACK , class U5, class U6, class U7, class U8, class | | #define __TBB_TYPENAME_U_PACK , typename U5, typename U6, typename U7, type | |
| U9 | | name U8, typename U9 | |
| #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type,
null_type | | #define __TBB_NULL_TYPE_PACK , null_type, null_type, null_type, null_type,
null_type | |
| #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8, T9& t9 | | #define __TBB_REF_T_PARAM_PACK ,T5& t5, T6& t6, T7& t7, T8& t8, T9& t9 | |
| #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7, const T8& t8, const T9& t9 | | #define __TBB_CONST_REF_T_PARAM_PACK , const T5& t5, const T6& t6, const T7
& t7, const T8& t8, const T9& t9 | |
| #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 ,t9 | | #define __TBB_T_PARAM_LIST_PACK ,t5 ,t6 ,t7 ,t8 ,t9 | |
| #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type&, const null_type&, const null_type& | | #define __TBB_CONST_NULL_REF_PACK , const null_type&, const null_type&, con
st null_type&, const null_type&, const null_type& | |
| #endif | | #endif | |
| | | | |
| namespace tbb { | | namespace tbb { | |
| namespace interface5 { | | namespace interface5 { | |
|
| | | | |
| namespace internal { | | namespace internal { | |
| struct null_type { }; | | struct null_type { }; | |
| } | | } | |
| using internal::null_type; | | using internal::null_type; | |
| | | | |
| // tuple forward declaration | | // tuple forward declaration | |
|
| template <class T0=null_type, class T1=null_type, class T2=null_type, class | | template <typename T0=null_type, typename T1=null_type, typename T2=null_ty | |
| T3=null_type, class T4=null_type | | pe, | |
| | | typename T3=null_type, typename T4=null_type | |
| #if __TBB_VARIADIC_MAX >= 6 | | #if __TBB_VARIADIC_MAX >= 6 | |
|
| , class T5=null_type | | , typename T5=null_type | |
| #if __TBB_VARIADIC_MAX >= 7 | | #if __TBB_VARIADIC_MAX >= 7 | |
|
| , class T6=null_type | | , typename T6=null_type | |
| #if __TBB_VARIADIC_MAX >= 8 | | #if __TBB_VARIADIC_MAX >= 8 | |
|
| , class T7=null_type | | , typename T7=null_type | |
| #if __TBB_VARIADIC_MAX >= 9 | | #if __TBB_VARIADIC_MAX >= 9 | |
|
| , class T8=null_type | | , typename T8=null_type | |
| #if __TBB_VARIADIC_MAX >= 10 | | #if __TBB_VARIADIC_MAX >= 10 | |
|
| , class T9=null_type | | , typename T9=null_type | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| > | | > | |
| class tuple; | | class tuple; | |
| | | | |
| namespace internal { | | namespace internal { | |
| | | | |
| // const null_type temp | | // const null_type temp | |
| inline const null_type cnull() { return null_type(); } | | inline const null_type cnull() { return null_type(); } | |
| | | | |
| // cons forward declaration | | // cons forward declaration | |
|
| template <class HT, class TT> struct cons; | | template <typename HT, typename TT> struct cons; | |
| | | | |
| // type of a component of the cons | | // type of a component of the cons | |
|
| template<int N, class T> | | template<int N, typename T> | |
| struct component { | | struct component { | |
| typedef typename T::tail_type next; | | typedef typename T::tail_type next; | |
| typedef typename component<N-1,next>::type type; | | typedef typename component<N-1,next>::type type; | |
| }; | | }; | |
| | | | |
|
| template<class T> | | template<typename T> | |
| struct component<0,T> { | | struct component<0,T> { | |
| typedef typename T::head_type type; | | typedef typename T::head_type type; | |
| }; | | }; | |
| | | | |
| template<> | | template<> | |
| struct component<0,null_type> { | | struct component<0,null_type> { | |
| typedef null_type type; | | typedef null_type type; | |
| }; | | }; | |
| | | | |
| // const version of component | | // const version of component | |
| | | | |
|
| template<int N, class T> | | template<int N, typename T> | |
| struct component<N, const T> | | struct component<N, const T> | |
| { | | { | |
| typedef typename T::tail_type next; | | typedef typename T::tail_type next; | |
| typedef const typename component<N-1,next>::type type; | | typedef const typename component<N-1,next>::type type; | |
| }; | | }; | |
| | | | |
|
| template<class T> | | template<typename T> | |
| struct component<0, const T> | | struct component<0, const T> | |
| { | | { | |
| typedef const typename T::head_type type; | | typedef const typename T::head_type type; | |
| }; | | }; | |
| | | | |
| // helper class for getting components of cons | | // helper class for getting components of cons | |
| template< int N> | | template< int N> | |
| struct get_helper { | | struct get_helper { | |
|
| template<class HT, class TT> | | template<typename HT, typename TT> | |
| inline static typename component<N, cons<HT,TT> >::type& get(cons<HT,TT>& t
i) { | | inline static typename component<N, cons<HT,TT> >::type& get(cons<HT,TT>& t
i) { | |
| return get_helper<N-1>::get(ti.tail); | | return get_helper<N-1>::get(ti.tail); | |
| } | | } | |
|
| template<class HT, class TT> | | template<typename HT, typename TT> | |
| inline static typename component<N, cons<HT,TT> >::type const& get(const co
ns<HT,TT>& ti) { | | inline static typename component<N, cons<HT,TT> >::type const& get(const co
ns<HT,TT>& ti) { | |
| return get_helper<N-1>::get(ti.tail); | | return get_helper<N-1>::get(ti.tail); | |
| } | | } | |
| }; | | }; | |
| | | | |
| template<> | | template<> | |
| struct get_helper<0> { | | struct get_helper<0> { | |
|
| template<class HT, class TT> | | template<typename HT, typename TT> | |
| inline static typename component<0, cons<HT,TT> >::type& get(cons<HT,TT>& t
i) { | | inline static typename component<0, cons<HT,TT> >::type& get(cons<HT,TT>& t
i) { | |
| return ti.head; | | return ti.head; | |
| } | | } | |
|
| template<class HT, class TT> | | template<typename HT, typename TT> | |
| inline static typename component<0, cons<HT,TT> >::type const& get(const co
ns<HT,TT>& ti) { | | inline static typename component<0, cons<HT,TT> >::type const& get(const co
ns<HT,TT>& ti) { | |
| return ti.head; | | return ti.head; | |
| } | | } | |
| }; | | }; | |
| | | | |
| // traits adaptor | | // traits adaptor | |
|
| template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_T_PA
CK> | | template <typename T0, typename T1, typename T2, typename T3, typename T4 _
_TBB_TYPENAME_T_PACK> | |
| struct tuple_traits { | | struct tuple_traits { | |
| typedef cons <T0, typename tuple_traits<T1, T2, T3, T4 __TBB_T_PACK , n
ull_type>::U > U; | | typedef cons <T0, typename tuple_traits<T1, T2, T3, T4 __TBB_T_PACK , n
ull_type>::U > U; | |
| }; | | }; | |
| | | | |
|
| template <> | | template <typename T0> | |
| struct tuple_traits<class T0, null_type, null_type, null_type, null_type __ | | struct tuple_traits<T0, null_type, null_type, null_type, null_type __TBB_NU | |
| TBB_NULL_TYPE_PACK > { | | LL_TYPE_PACK > { | |
| typedef cons<T0, null_type> U; | | typedef cons<T0, null_type> U; | |
| }; | | }; | |
| | | | |
| template<> | | template<> | |
| struct tuple_traits<null_type, null_type, null_type, null_type, null_type _
_TBB_NULL_TYPE_PACK > { | | struct tuple_traits<null_type, null_type, null_type, null_type, null_type _
_TBB_NULL_TYPE_PACK > { | |
| typedef null_type U; | | typedef null_type U; | |
| }; | | }; | |
| | | | |
| // core cons defs | | // core cons defs | |
|
| template <class HT, class TT> | | template <typename HT, typename TT> | |
| struct cons{ | | struct cons{ | |
| | | | |
| typedef HT head_type; | | typedef HT head_type; | |
| typedef TT tail_type; | | typedef TT tail_type; | |
| | | | |
|
| HT head; | | head_type head; | |
| TT tail; | | tail_type tail; | |
| | | | |
| static const int length = 1 + tail_type::length; | | static const int length = 1 + tail_type::length; | |
| | | | |
| // default constructors | | // default constructors | |
| explicit cons() : head(), tail() { } | | explicit cons() : head(), tail() { } | |
| | | | |
| // non-default constructors | | // non-default constructors | |
| cons(head_type& h, const tail_type& t) : head(h), tail(t) { } | | cons(head_type& h, const tail_type& t) : head(h), tail(t) { } | |
| | | | |
|
| template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_
T_PACK > | | template <typename T0, typename T1, typename T2, typename T3, typename
T4 __TBB_TYPENAME_T_PACK > | |
| cons(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4&
t4 __TBB_CONST_REF_T_PARAM_PACK) : | | cons(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4&
t4 __TBB_CONST_REF_T_PARAM_PACK) : | |
| head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK, cnull()) { } | | head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK, cnull()) { } | |
| | | | |
|
| template <class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_
T_PACK > | | template <typename T0, typename T1, typename T2, typename T3, typename
T4 __TBB_TYPENAME_T_PACK > | |
| cons(T0& t0, T1& t1, T2& t2, T3& t3, T4& t4 __TBB_REF_T_PARAM_PACK) : | | cons(T0& t0, T1& t1, T2& t2, T3& t3, T4& t4 __TBB_REF_T_PARAM_PACK) : | |
| head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK , cnull()) {
} | | head(t0), tail(t1, t2, t3, t4 __TBB_T_PARAM_LIST_PACK , cnull()) {
} | |
| | | | |
|
| template <class HT1, class TT1> | | template <typename HT1, typename TT1> | |
| cons(const cons<HT1,TT1>& other) : head(other.head), tail(other.tail) {
} | | cons(const cons<HT1,TT1>& other) : head(other.head), tail(other.tail) {
} | |
| | | | |
| cons& operator=(const cons& other) { head = other.head; tail = other.ta
il; return *this; } | | cons& operator=(const cons& other) { head = other.head; tail = other.ta
il; return *this; } | |
| | | | |
| friend bool operator==(const cons& me, const cons& other) { | | friend bool operator==(const cons& me, const cons& other) { | |
| return me.head == other.head && me.tail == other.tail; | | return me.head == other.head && me.tail == other.tail; | |
| } | | } | |
| friend bool operator<(const cons& me, const cons& other) { | | friend bool operator<(const cons& me, const cons& other) { | |
| return me.head < other.head || (!(other.head < me.head) && me.tail
< other.tail); | | return me.head < other.head || (!(other.head < me.head) && me.tail
< other.tail); | |
| } | | } | |
| friend bool operator>(const cons& me, const cons& other) { return othe
r<me; } | | friend bool operator>(const cons& me, const cons& other) { return othe
r<me; } | |
| friend bool operator!=(const cons& me, const cons& other) { return !(me
==other); } | | friend bool operator!=(const cons& me, const cons& other) { return !(me
==other); } | |
| friend bool operator>=(const cons& me, const cons& other) { return !(me
<other); } | | friend bool operator>=(const cons& me, const cons& other) { return !(me
<other); } | |
| friend bool operator<=(const cons& me, const cons& other) { return !(me
>other); } | | friend bool operator<=(const cons& me, const cons& other) { return !(me
>other); } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator==(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { | | friend bool operator==(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { | |
| return me.head == other.head && me.tail == other.tail; | | return me.head == other.head && me.tail == other.tail; | |
| } | | } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator<(const cons<HT,TT>& me, const cons<HT1,TT1>& other
) { | | friend bool operator<(const cons<HT,TT>& me, const cons<HT1,TT1>& other
) { | |
| return me.head < other.head || (!(other.head < me.head) && me.tail
< other.tail); | | return me.head < other.head || (!(other.head < me.head) && me.tail
< other.tail); | |
| } | | } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator>(const cons<HT,TT>& me, const cons<HT1,TT1>& other
) { return other<me; } | | friend bool operator>(const cons<HT,TT>& me, const cons<HT1,TT1>& other
) { return other<me; } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator!=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me==other); } | | friend bool operator!=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me==other); } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator>=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me<other); } | | friend bool operator>=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me<other); } | |
| | | | |
|
| template<class HT1, class TT1> | | template<typename HT1, typename TT1> | |
| friend bool operator<=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me>other); } | | friend bool operator<=(const cons<HT,TT>& me, const cons<HT1,TT1>& othe
r) { return !(me>other); } | |
| | | | |
| }; // cons | | }; // cons | |
| | | | |
|
| template <class HT> | | template <typename HT> | |
| struct cons<HT,null_type> { | | struct cons<HT,null_type> { | |
| | | | |
| typedef HT head_type; | | typedef HT head_type; | |
| typedef null_type tail_type; | | typedef null_type tail_type; | |
|
| static const int length = 1; | | | |
| head_type head; | | head_type head; | |
| | | | |
|
| | | static const int length = 1; | |
| | | | |
| // default constructor | | // default constructor | |
| cons() : head() { /*std::cout << "default constructor 1\n";*/ } | | cons() : head() { /*std::cout << "default constructor 1\n";*/ } | |
| | | | |
| cons(const null_type&, const null_type&, const null_type&, const null_t
ype&, const null_type& __TBB_CONST_NULL_REF_PACK) : head() { /*std::cout <<
"default constructor 2\n";*/ } | | cons(const null_type&, const null_type&, const null_type&, const null_t
ype&, const null_type& __TBB_CONST_NULL_REF_PACK) : head() { /*std::cout <<
"default constructor 2\n";*/ } | |
| | | | |
| // non-default constructor | | // non-default constructor | |
|
| template<class T1> | | template<typename T1> | |
| cons(T1& t1, const null_type&, const null_type&, const null_type&, cons
t null_type& __TBB_CONST_NULL_REF_PACK) : head(t1) { /*std::cout << "non-de
fault a1, t1== " << t1 << "\n";*/} | | cons(T1& t1, const null_type&, const null_type&, const null_type&, cons
t null_type& __TBB_CONST_NULL_REF_PACK) : head(t1) { /*std::cout << "non-de
fault a1, t1== " << t1 << "\n";*/} | |
| | | | |
| cons(head_type& h, const null_type& = null_type() ) : head(h) { } | | cons(head_type& h, const null_type& = null_type() ) : head(h) { } | |
| cons(const head_type& t0, const null_type&, const null_type&, const nul
l_type&, const null_type& __TBB_CONST_NULL_REF_PACK) : head(t0) { } | | cons(const head_type& t0, const null_type&, const null_type&, const nul
l_type&, const null_type& __TBB_CONST_NULL_REF_PACK) : head(t0) { } | |
| | | | |
| // converting constructor | | // converting constructor | |
|
| template<class HT1> | | template<typename HT1> | |
| cons(HT1 h1, const null_type&, const null_type&, const null_type&, cons
t null_type& __TBB_CONST_NULL_REF_PACK) : head(h1) { } | | cons(HT1 h1, const null_type&, const null_type&, const null_type&, cons
t null_type& __TBB_CONST_NULL_REF_PACK) : head(h1) { } | |
| | | | |
| // copy constructor | | // copy constructor | |
|
| template<class HT1> | | template<typename HT1> | |
| cons( const cons<HT1, null_type>& other) : head(other.head) { } | | cons( const cons<HT1, null_type>& other) : head(other.head) { } | |
| | | | |
| // assignment operator | | // assignment operator | |
| cons& operator=(const cons& other) { head = other.head; return *this; } | | cons& operator=(const cons& other) { head = other.head; return *this; } | |
| | | | |
| friend bool operator==(const cons& me, const cons& other) { return me.h
ead == other.head; } | | friend bool operator==(const cons& me, const cons& other) { return me.h
ead == other.head; } | |
| friend bool operator<(const cons& me, const cons& other) { return me.he
ad < other.head; } | | friend bool operator<(const cons& me, const cons& other) { return me.he
ad < other.head; } | |
| friend bool operator>(const cons& me, const cons& other) { return other
<me; } | | friend bool operator>(const cons& me, const cons& other) { return other
<me; } | |
| friend bool operator!=(const cons& me, const cons& other) {return !(me=
=other); } | | friend bool operator!=(const cons& me, const cons& other) {return !(me=
=other); } | |
| friend bool operator<=(const cons& me, const cons& other) {return !(me>
other); } | | friend bool operator<=(const cons& me, const cons& other) {return !(me>
other); } | |
| friend bool operator>=(const cons& me, const cons& other) {return !(me<
other); } | | friend bool operator>=(const cons& me, const cons& other) {return !(me<
other); } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator==(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { | | friend bool operator==(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { | |
| return me.head == other.head; | | return me.head == other.head; | |
| } | | } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator<(const cons<HT,null_type>& me, const cons<HT1,null
_type>& other) { | | friend bool operator<(const cons<HT,null_type>& me, const cons<HT1,null
_type>& other) { | |
| return me.head < other.head; | | return me.head < other.head; | |
| } | | } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator>(const cons<HT,null_type>& me, const cons<HT1,null
_type>& other) { return other<me; } | | friend bool operator>(const cons<HT,null_type>& me, const cons<HT1,null
_type>& other) { return other<me; } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator!=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me==other); } | | friend bool operator!=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me==other); } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator<=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me>other); } | | friend bool operator<=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me>other); } | |
| | | | |
|
| template<class HT1> | | template<typename HT1> | |
| friend bool operator>=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me<other); } | | friend bool operator>=(const cons<HT,null_type>& me, const cons<HT1,nul
l_type>& other) { return !(me<other); } | |
| | | | |
| }; // cons | | }; // cons | |
| | | | |
| template <> | | template <> | |
| struct cons<null_type,null_type> { typedef null_type tail_type; static cons
t int length = 0; }; | | struct cons<null_type,null_type> { typedef null_type tail_type; static cons
t int length = 0; }; | |
| | | | |
| // wrapper for default constructor | | // wrapper for default constructor | |
|
| template<class T> | | template<typename T> | |
| inline const T wrap_dcons(T*) { return T(); } | | inline const T wrap_dcons(T*) { return T(); } | |
|
| | | | |
| } // namespace internal | | } // namespace internal | |
| | | | |
| // tuple definition | | // tuple definition | |
|
| template<class T0, class T1, class T2, class T3, class T4 __TBB_CLASS_T_PAC
K > | | template<typename T0, typename T1, typename T2, typename T3, typename T4 __
TBB_TYPENAME_T_PACK > | |
| class tuple : public internal::tuple_traits<T0, T1, T2, T3, T4 __TBB_T_PACK
>::U { | | class tuple : public internal::tuple_traits<T0, T1, T2, T3, T4 __TBB_T_PACK
>::U { | |
| // friends | | // friends | |
|
| template <class T> friend class tuple_size; | | template <typename T> friend class tuple_size; | |
| template<int N, class T> friend struct tuple_element; | | template<int N, typename T> friend struct tuple_element; | |
| | | | |
| // stl components | | // stl components | |
| typedef tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > value_type; | | typedef tuple<T0,T1,T2,T3,T4 __TBB_T_PACK > value_type; | |
| typedef value_type *pointer; | | typedef value_type *pointer; | |
| typedef const value_type *const_pointer; | | typedef const value_type *const_pointer; | |
| typedef value_type &reference; | | typedef value_type &reference; | |
| typedef const value_type &const_reference; | | typedef const value_type &const_reference; | |
| typedef size_t size_type; | | typedef size_t size_type; | |
| | | | |
| typedef typename internal::tuple_traits<T0,T1,T2,T3, T4 __TBB_T_PACK >:
:U my_cons; | | typedef typename internal::tuple_traits<T0,T1,T2,T3, T4 __TBB_T_PACK >:
:U my_cons; | |
|
| public: | | | |
| | | | |
|
| | | public: | |
| tuple(const T0& t0=internal::wrap_dcons((T0*)NULL) | | tuple(const T0& t0=internal::wrap_dcons((T0*)NULL) | |
| ,const T1& t1=internal::wrap_dcons((T1*)NULL) | | ,const T1& t1=internal::wrap_dcons((T1*)NULL) | |
| ,const T2& t2=internal::wrap_dcons((T2*)NULL) | | ,const T2& t2=internal::wrap_dcons((T2*)NULL) | |
| ,const T3& t3=internal::wrap_dcons((T3*)NULL) | | ,const T3& t3=internal::wrap_dcons((T3*)NULL) | |
| ,const T4& t4=internal::wrap_dcons((T4*)NULL) | | ,const T4& t4=internal::wrap_dcons((T4*)NULL) | |
| #if __TBB_VARIADIC_MAX >= 6 | | #if __TBB_VARIADIC_MAX >= 6 | |
| ,const T5& t5=internal::wrap_dcons((T5*)NULL) | | ,const T5& t5=internal::wrap_dcons((T5*)NULL) | |
| #if __TBB_VARIADIC_MAX >= 7 | | #if __TBB_VARIADIC_MAX >= 7 | |
| ,const T6& t6=internal::wrap_dcons((T6*)NULL) | | ,const T6& t6=internal::wrap_dcons((T6*)NULL) | |
| #if __TBB_VARIADIC_MAX >= 8 | | #if __TBB_VARIADIC_MAX >= 8 | |
| | | | |
| skipping to change at line 387 | | skipping to change at line 392 | |
| #if __TBB_VARIADIC_MAX >= 9 | | #if __TBB_VARIADIC_MAX >= 9 | |
| ,const T8& t8=internal::wrap_dcons((T8*)NULL) | | ,const T8& t8=internal::wrap_dcons((T8*)NULL) | |
| #if __TBB_VARIADIC_MAX >= 10 | | #if __TBB_VARIADIC_MAX >= 10 | |
| ,const T9& t9=internal::wrap_dcons((T9*)NULL) | | ,const T9& t9=internal::wrap_dcons((T9*)NULL) | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| #endif | | #endif | |
| ) : | | ) : | |
|
| internal::tuple_traits<T0,T1,T2,T3,T4 __TBB_T_PACK >::U(t0,t1,t2,t3
,t4 __TBB_T_PARAM_LIST_PACK) { } | | my_cons(t0,t1,t2,t3,t4 __TBB_T_PARAM_LIST_PACK) { } | |
| | | | |
| template<int N> | | template<int N> | |
| struct internal_tuple_element { | | struct internal_tuple_element { | |
| typedef typename internal::component<N,my_cons>::type type; | | typedef typename internal::component<N,my_cons>::type type; | |
| }; | | }; | |
| | | | |
| template<int N> | | template<int N> | |
| typename internal_tuple_element<N>::type& get() { return internal::get_
helper<N>::get(*this); } | | typename internal_tuple_element<N>::type& get() { return internal::get_
helper<N>::get(*this); } | |
| | | | |
| template<int N> | | template<int N> | |
| typename internal_tuple_element<N>::type const& get() const { return in
ternal::get_helper<N>::get(*this); } | | typename internal_tuple_element<N>::type const& get() const { return in
ternal::get_helper<N>::get(*this); } | |
| | | | |
|
| template<class U1, class U2> | | template<typename U1, typename U2> | |
| tuple& operator=(const internal::cons<U1,U2>& other) { | | tuple& operator=(const internal::cons<U1,U2>& other) { | |
| my_cons::operator=(other); | | my_cons::operator=(other); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| template<class U1, class U2> | | template<typename U1, typename U2> | |
| tuple& operator=(const std::pair<U1,U2>& other) { | | tuple& operator=(const std::pair<U1,U2>& other) { | |
| // __TBB_ASSERT(tuple_size<value_type>::value == 2, "Invalid size f
or pair to tuple assignment"); | | // __TBB_ASSERT(tuple_size<value_type>::value == 2, "Invalid size f
or pair to tuple assignment"); | |
| this->head = other.first; | | this->head = other.first; | |
| this->tail.head = other.second; | | this->tail.head = other.second; | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| friend bool operator==(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)==(other);} | | friend bool operator==(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)==(other);} | |
| friend bool operator<(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)<(other);} | | friend bool operator<(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)<(other);} | |
| friend bool operator>(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)>(other);} | | friend bool operator>(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)>(other);} | |
| friend bool operator!=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)!=(other);} | | friend bool operator!=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)!=(other);} | |
| friend bool operator>=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)>=(other);} | | friend bool operator>=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)>=(other);} | |
| friend bool operator<=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)<=(other);} | | friend bool operator<=(const tuple& me, const tuple& other) {return sta
tic_cast<const my_cons &>(me)<=(other);} | |
| | | | |
|
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator==(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | | | |
| B_U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)==(other); | | | |
| } | | | |
| | | | |
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator<(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TBB | | | |
| _U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)<(other); | | | |
| } | | | |
| | | | |
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator>(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TBB | | | |
| _U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)>(other); | | | |
| } | | | |
| | | | |
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator!=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | | | |
| B_U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)!=(other); | | | |
| } | | | |
| | | | |
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator>=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | | | |
| B_U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)>=(other); | | | |
| } | | | |
| | | | |
| template<class U0, class U1, class U2, class U3, class U4 __TBB_CLASS_U | | | |
| _PACK > | | | |
| friend bool operator<=(const tuple& me, const tuple<U0,U1,U2,U3,U4 __TB | | | |
| B_U_PACK >& other) { | | | |
| return static_cast<const my_cons &>(me)<=(other); | | | |
| } | | | |
| | | | |
| }; // tuple | | }; // tuple | |
| | | | |
| // empty tuple | | // empty tuple | |
| template<> | | template<> | |
| class tuple<null_type, null_type, null_type, null_type, null_type __TBB_NUL
L_TYPE_PACK > : public null_type { | | class tuple<null_type, null_type, null_type, null_type, null_type __TBB_NUL
L_TYPE_PACK > : public null_type { | |
|
| typedef null_type inherited; | | | |
| }; | | }; | |
| | | | |
| // helper classes | | // helper classes | |
| | | | |
|
| template < class T> | | template < typename T> | |
| class tuple_size { | | class tuple_size { | |
| public: | | public: | |
| static const size_t value = 1 + tuple_size<typename T::tail_type>::valu
e; | | static const size_t value = 1 + tuple_size<typename T::tail_type>::valu
e; | |
| }; | | }; | |
| | | | |
| template <> | | template <> | |
| class tuple_size<tuple<> > { | | class tuple_size<tuple<> > { | |
| public: | | public: | |
| static const size_t value = 0; | | static const size_t value = 0; | |
| }; | | }; | |
| | | | |
| template <> | | template <> | |
| class tuple_size<null_type> { | | class tuple_size<null_type> { | |
| public: | | public: | |
| static const size_t value = 0; | | static const size_t value = 0; | |
| }; | | }; | |
| | | | |
|
| template<int N, class T> | | template<int N, typename T> | |
| struct tuple_element { | | struct tuple_element { | |
| typedef typename internal::component<N, typename T::my_cons>::type type
; | | typedef typename internal::component<N, typename T::my_cons>::type type
; | |
| }; | | }; | |
| | | | |
|
| template<int N, class T0, class T1, class T2, class T3, class T4 __TBB_CLAS
S_T_PACK > | | template<int N, typename T0, typename T1, typename T2, typename T3, typenam
e T4 __TBB_TYPENAME_T_PACK > | |
| inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >
>::type& | | inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >
>::type& | |
|
| get(tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return t.get<N>(); } | | get(tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return internal::get_help
er<N>::get(t); } | |
| | | | |
|
| template<int N, class T0, class T1, class T2, class T3, class T4 __TBB_CLAS
S_T_PACK > | | template<int N, typename T0, typename T1, typename T2, typename T3, typenam
e T4 __TBB_TYPENAME_T_PACK > | |
| inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >
>::type const& | | inline static typename tuple_element<N,tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >
>::type const& | |
|
| get(const tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return t.get<N>();
} | | get(const tuple<T0,T1,T2,T3,T4 __TBB_T_PACK >& t) { return internal::ge
t_helper<N>::get(t); } | |
| | | | |
| } // interface5 | | } // interface5 | |
| } // tbb | | } // tbb | |
| | | | |
| #if !__TBB_CPP11_TUPLE_PRESENT | | #if !__TBB_CPP11_TUPLE_PRESENT | |
|
| namespace std { | | namespace tbb { | |
| using tbb::interface5::tuple; | | namespace flow { | |
| using tbb::interface5::tuple_size; | | using tbb::interface5::tuple; | |
| using tbb::interface5::tuple_element; | | using tbb::interface5::tuple_size; | |
| using tbb::interface5::get; | | using tbb::interface5::tuple_element; | |
| | | using tbb::interface5::get; | |
| | | } | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #undef __TBB_T_PACK | | #undef __TBB_T_PACK | |
| #undef __TBB_U_PACK | | #undef __TBB_U_PACK | |
|
| #undef __TBB_CLASS_T_PACK | | #undef __TBB_TYPENAME_T_PACK | |
| #undef __TBB_CLASS_U_PACK | | #undef __TBB_TYPENAME_U_PACK | |
| #undef __TBB_NULL_TYPE_PACK | | #undef __TBB_NULL_TYPE_PACK | |
| #undef __TBB_REF_T_PARAM_PACK | | #undef __TBB_REF_T_PARAM_PACK | |
| #undef __TBB_CONST_REF_T_PARAM_PACK | | #undef __TBB_CONST_REF_T_PARAM_PACK | |
| #undef __TBB_T_PARAM_LIST_PACK | | #undef __TBB_T_PARAM_LIST_PACK | |
| #undef __TBB_CONST_NULL_REF_PACK | | #undef __TBB_CONST_NULL_REF_PACK | |
| | | | |
| #endif /* __TBB_tuple_H */ | | #endif /* __TBB_tuple_H */ | |
| | | | |
End of changes. 66 change blocks. |
| 121 lines changed or deleted | | 87 lines changed or added | |
|