1 /*
2     Copyright (c) 2005-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #ifndef __TBB__flow_graph_indexer_impl_H
18 #define __TBB__flow_graph_indexer_impl_H
19 
20 #ifndef __TBB_flow_graph_H
21 #error Do not #include this internal file directly; use public TBB headers instead.
22 #endif
23 
24 // included in namespace tbb::detail::d1
25 
26 #include "_flow_graph_types_impl.h"
27 
28     // Output of the indexer_node is a tbb::flow::tagged_msg, and will be of
29     // the form  tagged_msg<tag, result>
30     // where the value of tag will indicate which result was put to the
31     // successor.
32 
33     template<typename IndexerNodeBaseType, typename T, size_t K>
do_try_put(const T & v,void * p)34     graph_task* do_try_put(const T &v, void *p) {
35         typename IndexerNodeBaseType::output_type o(K, v);
36         return reinterpret_cast<IndexerNodeBaseType *>(p)->try_put_task(&o);
37     }
38 
39     template<typename TupleTypes,int N>
40     struct indexer_helper {
41         template<typename IndexerNodeBaseType, typename PortTuple>
set_indexer_node_pointerindexer_helper42         static inline void set_indexer_node_pointer(PortTuple &my_input, IndexerNodeBaseType *p, graph& g) {
43             typedef typename std::tuple_element<N-1, TupleTypes>::type T;
44             graph_task* (*indexer_node_put_task)(const T&, void *) = do_try_put<IndexerNodeBaseType, T, N-1>;
45             std::get<N-1>(my_input).set_up(p, indexer_node_put_task, g);
46             indexer_helper<TupleTypes,N-1>::template set_indexer_node_pointer<IndexerNodeBaseType,PortTuple>(my_input, p, g);
47         }
48     };
49 
50     template<typename TupleTypes>
51     struct indexer_helper<TupleTypes,1> {
52         template<typename IndexerNodeBaseType, typename PortTuple>
53         static inline void set_indexer_node_pointer(PortTuple &my_input, IndexerNodeBaseType *p, graph& g) {
54             typedef typename std::tuple_element<0, TupleTypes>::type T;
55             graph_task* (*indexer_node_put_task)(const T&, void *) = do_try_put<IndexerNodeBaseType, T, 0>;
56             std::get<0>(my_input).set_up(p, indexer_node_put_task, g);
57         }
58     };
59 
60     template<typename T>
61     class indexer_input_port : public receiver<T> {
62     private:
63         void* my_indexer_ptr;
64         typedef graph_task* (* forward_function_ptr)(T const &, void* );
65         forward_function_ptr my_try_put_task;
66         graph* my_graph;
67     public:
68         void set_up(void* p, forward_function_ptr f, graph& g) {
69             my_indexer_ptr = p;
70             my_try_put_task = f;
71             my_graph = &g;
72         }
73 
74     protected:
75         template< typename R, typename B > friend class run_and_put_task;
76         template<typename X, typename Y> friend class broadcast_cache;
77         template<typename X, typename Y> friend class round_robin_cache;
78         graph_task* try_put_task(const T &v) override {
79             return my_try_put_task(v, my_indexer_ptr);
80         }
81 
82         graph& graph_reference() const override {
83             return *my_graph;
84         }
85     };
86 
87     template<typename InputTuple, typename OutputType, typename StructTypes>
88     class indexer_node_FE {
89     public:
90         static const int N = std::tuple_size<InputTuple>::value;
91         typedef OutputType output_type;
92         typedef InputTuple input_type;
93 
94         // Some versions of Intel(R) C++ Compiler fail to generate an implicit constructor for the class which has std::tuple as a member.
95         indexer_node_FE() : my_inputs() {}
96 
97         input_type &input_ports() { return my_inputs; }
98     protected:
99         input_type my_inputs;
100     };
101 
102     //! indexer_node_base
103     template<typename InputTuple, typename OutputType, typename StructTypes>
104     class indexer_node_base : public graph_node, public indexer_node_FE<InputTuple, OutputType,StructTypes>,
105                            public sender<OutputType> {
106     protected:
107        using graph_node::my_graph;
108     public:
109         static const size_t N = std::tuple_size<InputTuple>::value;
110         typedef OutputType output_type;
111         typedef StructTypes tuple_types;
112         typedef typename sender<output_type>::successor_type successor_type;
113         typedef indexer_node_FE<InputTuple, output_type,StructTypes> input_ports_type;
114 
115     private:
116         // ----------- Aggregator ------------
117         enum op_type { reg_succ, rem_succ, try__put_task
118         };
119         typedef indexer_node_base<InputTuple,output_type,StructTypes> class_type;
120 
121         class indexer_node_base_operation : public aggregated_operation<indexer_node_base_operation> {
122         public:
123             char type;
124             union {
125                 output_type const *my_arg;
126                 successor_type *my_succ;
127                 graph_task* bypass_t;
128             };
129             indexer_node_base_operation(const output_type* e, op_type t) :
130                 type(char(t)), my_arg(e) {}
131             indexer_node_base_operation(const successor_type &s, op_type t) : type(char(t)),
132                 my_succ(const_cast<successor_type *>(&s)) {}
133         };
134 
135         typedef aggregating_functor<class_type, indexer_node_base_operation> handler_type;
136         friend class aggregating_functor<class_type, indexer_node_base_operation>;
137         aggregator<handler_type, indexer_node_base_operation> my_aggregator;
138 
139         void handle_operations(indexer_node_base_operation* op_list) {
140             indexer_node_base_operation *current;
141             while(op_list) {
142                 current = op_list;
143                 op_list = op_list->next;
144                 switch(current->type) {
145 
146                 case reg_succ:
147                     my_successors.register_successor(*(current->my_succ));
148                     current->status.store( SUCCEEDED, std::memory_order_release);
149                     break;
150 
151                 case rem_succ:
152                     my_successors.remove_successor(*(current->my_succ));
153                     current->status.store( SUCCEEDED, std::memory_order_release);
154                     break;
155                 case try__put_task: {
156                         current->bypass_t = my_successors.try_put_task(*(current->my_arg));
157                         current->status.store( SUCCEEDED, std::memory_order_release);  // return of try_put_task actual return value
158                     }
159                     break;
160                 }
161             }
162         }
163         // ---------- end aggregator -----------
164     public:
165         indexer_node_base(graph& g) : graph_node(g), input_ports_type(), my_successors(this) {
166             indexer_helper<StructTypes,N>::set_indexer_node_pointer(this->my_inputs, this, g);
167             my_aggregator.initialize_handler(handler_type(this));
168         }
169 
170         indexer_node_base(const indexer_node_base& other)
171             : graph_node(other.my_graph), input_ports_type(), sender<output_type>(), my_successors(this)
172         {
173             indexer_helper<StructTypes,N>::set_indexer_node_pointer(this->my_inputs, this, other.my_graph);
174             my_aggregator.initialize_handler(handler_type(this));
175         }
176 
177         bool register_successor(successor_type &r) override {
178             indexer_node_base_operation op_data(r, reg_succ);
179             my_aggregator.execute(&op_data);
180             return op_data.status == SUCCEEDED;
181         }
182 
183         bool remove_successor( successor_type &r) override {
184             indexer_node_base_operation op_data(r, rem_succ);
185             my_aggregator.execute(&op_data);
186             return op_data.status == SUCCEEDED;
187         }
188 
189         graph_task* try_put_task(output_type const *v) { // not a virtual method in this class
190             indexer_node_base_operation op_data(v, try__put_task);
191             my_aggregator.execute(&op_data);
192             return op_data.bypass_t;
193         }
194 
195     protected:
196         void reset_node(reset_flags f) override {
197             if(f & rf_clear_edges) {
198                 my_successors.clear();
199             }
200         }
201 
202     private:
203         broadcast_cache<output_type, null_rw_mutex> my_successors;
204     };  //indexer_node_base
205 
206 
207     template<int N, typename InputTuple> struct input_types;
208 
209     template<typename InputTuple>
210     struct input_types<1, InputTuple> {
211         typedef typename std::tuple_element<0, InputTuple>::type first_type;
212         typedef tagged_msg<size_t, first_type > type;
213     };
214 
215     template<typename InputTuple>
216     struct input_types<2, InputTuple> {
217         typedef typename std::tuple_element<0, InputTuple>::type first_type;
218         typedef typename std::tuple_element<1, InputTuple>::type second_type;
219         typedef tagged_msg<size_t, first_type, second_type> type;
220     };
221 
222     template<typename InputTuple>
223     struct input_types<3, InputTuple> {
224         typedef typename std::tuple_element<0, InputTuple>::type first_type;
225         typedef typename std::tuple_element<1, InputTuple>::type second_type;
226         typedef typename std::tuple_element<2, InputTuple>::type third_type;
227         typedef tagged_msg<size_t, first_type, second_type, third_type> type;
228     };
229 
230     template<typename InputTuple>
231     struct input_types<4, InputTuple> {
232         typedef typename std::tuple_element<0, InputTuple>::type first_type;
233         typedef typename std::tuple_element<1, InputTuple>::type second_type;
234         typedef typename std::tuple_element<2, InputTuple>::type third_type;
235         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
236         typedef tagged_msg<size_t, first_type, second_type, third_type,
237                                                       fourth_type> type;
238     };
239 
240     template<typename InputTuple>
241     struct input_types<5, InputTuple> {
242         typedef typename std::tuple_element<0, InputTuple>::type first_type;
243         typedef typename std::tuple_element<1, InputTuple>::type second_type;
244         typedef typename std::tuple_element<2, InputTuple>::type third_type;
245         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
246         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
247         typedef tagged_msg<size_t, first_type, second_type, third_type,
248                                                       fourth_type, fifth_type> type;
249     };
250 
251     template<typename InputTuple>
252     struct input_types<6, InputTuple> {
253         typedef typename std::tuple_element<0, InputTuple>::type first_type;
254         typedef typename std::tuple_element<1, InputTuple>::type second_type;
255         typedef typename std::tuple_element<2, InputTuple>::type third_type;
256         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
257         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
258         typedef typename std::tuple_element<5, InputTuple>::type sixth_type;
259         typedef tagged_msg<size_t, first_type, second_type, third_type,
260                                                       fourth_type, fifth_type, sixth_type> type;
261     };
262 
263     template<typename InputTuple>
264     struct input_types<7, InputTuple> {
265         typedef typename std::tuple_element<0, InputTuple>::type first_type;
266         typedef typename std::tuple_element<1, InputTuple>::type second_type;
267         typedef typename std::tuple_element<2, InputTuple>::type third_type;
268         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
269         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
270         typedef typename std::tuple_element<5, InputTuple>::type sixth_type;
271         typedef typename std::tuple_element<6, InputTuple>::type seventh_type;
272         typedef tagged_msg<size_t, first_type, second_type, third_type,
273                                                       fourth_type, fifth_type, sixth_type,
274                                                       seventh_type> type;
275     };
276 
277 
278     template<typename InputTuple>
279     struct input_types<8, InputTuple> {
280         typedef typename std::tuple_element<0, InputTuple>::type first_type;
281         typedef typename std::tuple_element<1, InputTuple>::type second_type;
282         typedef typename std::tuple_element<2, InputTuple>::type third_type;
283         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
284         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
285         typedef typename std::tuple_element<5, InputTuple>::type sixth_type;
286         typedef typename std::tuple_element<6, InputTuple>::type seventh_type;
287         typedef typename std::tuple_element<7, InputTuple>::type eighth_type;
288         typedef tagged_msg<size_t, first_type, second_type, third_type,
289                                                       fourth_type, fifth_type, sixth_type,
290                                                       seventh_type, eighth_type> type;
291     };
292 
293 
294     template<typename InputTuple>
295     struct input_types<9, InputTuple> {
296         typedef typename std::tuple_element<0, InputTuple>::type first_type;
297         typedef typename std::tuple_element<1, InputTuple>::type second_type;
298         typedef typename std::tuple_element<2, InputTuple>::type third_type;
299         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
300         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
301         typedef typename std::tuple_element<5, InputTuple>::type sixth_type;
302         typedef typename std::tuple_element<6, InputTuple>::type seventh_type;
303         typedef typename std::tuple_element<7, InputTuple>::type eighth_type;
304         typedef typename std::tuple_element<8, InputTuple>::type nineth_type;
305         typedef tagged_msg<size_t, first_type, second_type, third_type,
306                                                       fourth_type, fifth_type, sixth_type,
307                                                       seventh_type, eighth_type, nineth_type> type;
308     };
309 
310     template<typename InputTuple>
311     struct input_types<10, InputTuple> {
312         typedef typename std::tuple_element<0, InputTuple>::type first_type;
313         typedef typename std::tuple_element<1, InputTuple>::type second_type;
314         typedef typename std::tuple_element<2, InputTuple>::type third_type;
315         typedef typename std::tuple_element<3, InputTuple>::type fourth_type;
316         typedef typename std::tuple_element<4, InputTuple>::type fifth_type;
317         typedef typename std::tuple_element<5, InputTuple>::type sixth_type;
318         typedef typename std::tuple_element<6, InputTuple>::type seventh_type;
319         typedef typename std::tuple_element<7, InputTuple>::type eighth_type;
320         typedef typename std::tuple_element<8, InputTuple>::type nineth_type;
321         typedef typename std::tuple_element<9, InputTuple>::type tenth_type;
322         typedef tagged_msg<size_t, first_type, second_type, third_type,
323                                                       fourth_type, fifth_type, sixth_type,
324                                                       seventh_type, eighth_type, nineth_type,
325                                                       tenth_type> type;
326     };
327 
328     // type generators
329     template<typename OutputTuple>
330     struct indexer_types : public input_types<std::tuple_size<OutputTuple>::value, OutputTuple> {
331         static const int N = std::tuple_size<OutputTuple>::value;
332         typedef typename input_types<N, OutputTuple>::type output_type;
333         typedef typename wrap_tuple_elements<N,indexer_input_port,OutputTuple>::type input_ports_type;
334         typedef indexer_node_FE<input_ports_type,output_type,OutputTuple> indexer_FE_type;
335         typedef indexer_node_base<input_ports_type, output_type, OutputTuple> indexer_base_type;
336     };
337 
338     template<class OutputTuple>
339     class unfolded_indexer_node : public indexer_types<OutputTuple>::indexer_base_type {
340     public:
341         typedef typename indexer_types<OutputTuple>::input_ports_type input_ports_type;
342         typedef OutputTuple tuple_types;
343         typedef typename indexer_types<OutputTuple>::output_type output_type;
344     private:
345         typedef typename indexer_types<OutputTuple>::indexer_base_type base_type;
346     public:
347         unfolded_indexer_node(graph& g) : base_type(g) {}
348         unfolded_indexer_node(const unfolded_indexer_node &other) : base_type(other) {}
349     };
350 
351 #endif  /* __TBB__flow_graph_indexer_impl_H */
352