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_body_impl_H
18 #define __TBB__flow_graph_body_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 (in flow_graph.h)
25 
26 typedef std::uint64_t tag_value;
27 
28 
29 // TODO revamp: find out if there is already helper for has_policy.
30 template<typename ... Policies> struct Policy {};
31 
32 template<typename ... Policies> struct has_policy;
33 
34 template<typename ExpectedPolicy, typename FirstPolicy, typename ...Policies>
35 struct has_policy<ExpectedPolicy, FirstPolicy, Policies...> :
36     std::integral_constant<bool, has_policy<ExpectedPolicy, FirstPolicy>::value ||
37                                  has_policy<ExpectedPolicy, Policies...>::value> {};
38 
39 template<typename ExpectedPolicy, typename SinglePolicy>
40 struct has_policy<ExpectedPolicy, SinglePolicy> :
41     std::integral_constant<bool, std::is_same<ExpectedPolicy, SinglePolicy>::value> {};
42 
43 template<typename ExpectedPolicy, typename ...Policies>
44 struct has_policy<ExpectedPolicy, Policy<Policies...> > : has_policy<ExpectedPolicy, Policies...> {};
45 
46 namespace graph_policy_namespace {
47 
48     struct rejecting { };
49     struct reserving { };
50     struct queueing  { };
51     struct lightweight  { };
52 
53     // K == type of field used for key-matching.  Each tag-matching port will be provided
54     // functor that, given an object accepted by the port, will return the
55     /// field of type K being used for matching.
56     template<typename K, typename KHash=tbb_hash_compare<typename std::decay<K>::type > >
57         __TBB_requires(tbb::detail::hash_compare<KHash, K>)
58     struct key_matching {
59         typedef K key_type;
60         typedef typename std::decay<K>::type base_key_type;
61         typedef KHash hash_compare_type;
62     };
63 
64     // old tag_matching join's new specifier
65     typedef key_matching<tag_value> tag_matching;
66 
67     // Aliases for Policy combinations
68     typedef Policy<queueing, lightweight> queueing_lightweight;
69     typedef Policy<rejecting, lightweight> rejecting_lightweight;
70 
71 } // namespace graph_policy_namespace
72 
73 // -------------- function_body containers ----------------------
74 
75 //! A functor that takes no input and generates a value of type Output
76 template< typename Output >
77 class input_body : no_assign {
78 public:
79     virtual ~input_body() {}
80     virtual Output operator()(flow_control& fc) = 0;
81     virtual input_body* clone() = 0;
82 };
83 
84 //! The leaf for input_body
85 template< typename Output, typename Body>
86 class input_body_leaf : public input_body<Output> {
87 public:
88     input_body_leaf( const Body &_body ) : body(_body) { }
89     Output operator()(flow_control& fc) override { return body(fc); }
90     input_body_leaf* clone() override {
91         return new input_body_leaf< Output, Body >(body);
92     }
93     Body get_body() { return body; }
94 private:
95     Body body;
96 };
97 
98 //! A functor that takes an Input and generates an Output
99 template< typename Input, typename Output >
100 class function_body : no_assign {
101 public:
102     virtual ~function_body() {}
103     virtual Output operator()(const Input &input) = 0;
104     virtual function_body* clone() = 0;
105 };
106 
107 //! the leaf for function_body
108 template <typename Input, typename Output, typename B>
109 class function_body_leaf : public function_body< Input, Output > {
110 public:
111     function_body_leaf( const B &_body ) : body(_body) { }
112     Output operator()(const Input &i) override { return body(i); }
113     B get_body() { return body; }
114     function_body_leaf* clone() override {
115         return new function_body_leaf< Input, Output, B >(body);
116     }
117 private:
118     B body;
119 };
120 
121 //! the leaf for function_body specialized for Input and output of continue_msg
122 template <typename B>
123 class function_body_leaf< continue_msg, continue_msg, B> : public function_body< continue_msg, continue_msg > {
124 public:
125     function_body_leaf( const B &_body ) : body(_body) { }
126     continue_msg operator()( const continue_msg &i ) override {
127         body(i);
128         return i;
129     }
130     B get_body() { return body; }
131     function_body_leaf* clone() override {
132         return new function_body_leaf< continue_msg, continue_msg, B >(body);
133     }
134 private:
135     B body;
136 };
137 
138 //! the leaf for function_body specialized for Output of continue_msg
139 template <typename Input, typename B>
140 class function_body_leaf< Input, continue_msg, B> : public function_body< Input, continue_msg > {
141 public:
142     function_body_leaf( const B &_body ) : body(_body) { }
143     continue_msg operator()(const Input &i) override {
144         body(i);
145         return continue_msg();
146     }
147     B get_body() { return body; }
148     function_body_leaf* clone() override {
149         return new function_body_leaf< Input, continue_msg, B >(body);
150     }
151 private:
152     B body;
153 };
154 
155 //! the leaf for function_body specialized for Input of continue_msg
156 template <typename Output, typename B>
157 class function_body_leaf< continue_msg, Output, B > : public function_body< continue_msg, Output > {
158 public:
159     function_body_leaf( const B &_body ) : body(_body) { }
160     Output operator()(const continue_msg &i) override {
161         return body(i);
162     }
163     B get_body() { return body; }
164     function_body_leaf* clone() override {
165         return new function_body_leaf< continue_msg, Output, B >(body);
166     }
167 private:
168     B body;
169 };
170 
171 //! function_body that takes an Input and a set of output ports
172 template<typename Input, typename OutputSet>
173 class multifunction_body : no_assign {
174 public:
175     virtual ~multifunction_body () {}
176     virtual void operator()(const Input &/* input*/, OutputSet &/*oset*/) = 0;
177     virtual multifunction_body* clone() = 0;
178     virtual void* get_body_ptr() = 0;
179 };
180 
181 //! leaf for multifunction.  OutputSet can be a std::tuple or a vector.
182 template<typename Input, typename OutputSet, typename B >
183 class multifunction_body_leaf : public multifunction_body<Input, OutputSet> {
184 public:
185     multifunction_body_leaf(const B &_body) : body(_body) { }
186     void operator()(const Input &input, OutputSet &oset) override {
187         body(input, oset); // body may explicitly put() to one or more of oset.
188     }
189     void* get_body_ptr() override { return &body; }
190     multifunction_body_leaf* clone() override {
191         return new multifunction_body_leaf<Input, OutputSet,B>(body);
192     }
193 
194 private:
195     B body;
196 };
197 
198 // ------ function bodies for hash_buffers and key-matching joins.
199 
200 template<typename Input, typename Output>
201 class type_to_key_function_body : no_assign {
202     public:
203         virtual ~type_to_key_function_body() {}
204         virtual Output operator()(const Input &input) = 0;  // returns an Output
205         virtual type_to_key_function_body* clone() = 0;
206 };
207 
208 // specialization for ref output
209 template<typename Input, typename Output>
210 class type_to_key_function_body<Input,Output&> : no_assign {
211     public:
212         virtual ~type_to_key_function_body() {}
213         virtual const Output & operator()(const Input &input) = 0;  // returns a const Output&
214         virtual type_to_key_function_body* clone() = 0;
215 };
216 
217 template <typename Input, typename Output, typename B>
218 class type_to_key_function_body_leaf : public type_to_key_function_body<Input, Output> {
219 public:
220     type_to_key_function_body_leaf( const B &_body ) : body(_body) { }
221     Output operator()(const Input &i) override { return body(i); }
222     type_to_key_function_body_leaf* clone() override {
223         return new type_to_key_function_body_leaf< Input, Output, B>(body);
224     }
225 private:
226     B body;
227 };
228 
229 template <typename Input, typename Output, typename B>
230 class type_to_key_function_body_leaf<Input,Output&,B> : public type_to_key_function_body< Input, Output&> {
231 public:
232     type_to_key_function_body_leaf( const B &_body ) : body(_body) { }
233     const Output& operator()(const Input &i) override {
234         return body(i);
235     }
236     type_to_key_function_body_leaf* clone() override {
237         return new type_to_key_function_body_leaf< Input, Output&, B>(body);
238     }
239 private:
240     B body;
241 };
242 
243 // --------------------------- end of function_body containers ------------------------
244 
245 // --------------------------- node task bodies ---------------------------------------
246 
247 //! A task that calls a node's forward_task function
248 template< typename NodeType >
249 class forward_task_bypass : public graph_task {
250     NodeType &my_node;
251 public:
252     forward_task_bypass( graph& g, small_object_allocator& allocator, NodeType &n
253                          , node_priority_t node_priority = no_priority
254     ) : graph_task(g, allocator, node_priority),
255     my_node(n) {}
256 
257     task* execute(execution_data& ed) override {
258         graph_task* next_task = my_node.forward_task();
259         if (SUCCESSFULLY_ENQUEUED == next_task)
260             next_task = nullptr;
261         else if (next_task)
262             next_task = prioritize_task(my_node.graph_reference(), *next_task);
263         finalize(ed);
264         return next_task;
265     }
266 };
267 
268 //! A task that calls a node's apply_body_bypass function, passing in an input of type Input
269 //  return the task* unless it is SUCCESSFULLY_ENQUEUED, in which case return NULL
270 template< typename NodeType, typename Input >
271 class apply_body_task_bypass : public graph_task {
272     NodeType &my_node;
273     Input my_input;
274 public:
275 
276     apply_body_task_bypass( graph& g, small_object_allocator& allocator, NodeType &n, const Input &i
277                             , node_priority_t node_priority = no_priority
278     ) : graph_task(g, allocator, node_priority),
279         my_node(n), my_input(i) {}
280 
281     task* execute(execution_data& ed) override {
282         graph_task* next_task = my_node.apply_body_bypass( my_input );
283         if (SUCCESSFULLY_ENQUEUED == next_task)
284             next_task = nullptr;
285         else if (next_task)
286             next_task = prioritize_task(my_node.graph_reference(), *next_task);
287         finalize(ed);
288         return next_task;
289 
290     }
291 };
292 
293 //! A task that calls a node's apply_body_bypass function with no input
294 template< typename NodeType >
295 class input_node_task_bypass : public graph_task {
296     NodeType &my_node;
297 public:
298     input_node_task_bypass( graph& g, small_object_allocator& allocator, NodeType &n )
299         : graph_task(g, allocator), my_node(n) {}
300 
301     task* execute(execution_data& ed) override {
302         graph_task* next_task = my_node.apply_body_bypass( );
303         if (SUCCESSFULLY_ENQUEUED == next_task)
304             next_task = nullptr;
305         else if (next_task)
306             next_task = prioritize_task(my_node.graph_reference(), *next_task);
307         finalize(ed);
308         return next_task;
309     }
310 
311 };
312 
313 // ------------------------ end of node task bodies -----------------------------------
314 
315 template<typename T, typename DecrementType, typename DummyType = void>
316 class threshold_regulator;
317 
318 template<typename T, typename DecrementType>
319 class threshold_regulator<T, DecrementType,
320                   typename std::enable_if<std::is_integral<DecrementType>::value>::type>
321     : public receiver<DecrementType>, no_copy
322 {
323     T* my_node;
324 protected:
325 
326     graph_task* try_put_task( const DecrementType& value ) override {
327         graph_task* result = my_node->decrement_counter( value );
328         if( !result )
329             result = SUCCESSFULLY_ENQUEUED;
330         return result;
331     }
332 
333     graph& graph_reference() const override {
334         return my_node->my_graph;
335     }
336 
337     template<typename U, typename V> friend class limiter_node;
338     void reset_receiver( reset_flags ) {}
339 
340 public:
341     threshold_regulator(T* owner) : my_node(owner) {
342         // Do not work with the passed pointer here as it may not be fully initialized yet
343     }
344 };
345 
346 template<typename T>
347 class threshold_regulator<T, continue_msg, void> : public continue_receiver, no_copy {
348 
349     T *my_node;
350 
351     graph_task* execute() override {
352         return my_node->decrement_counter( 1 );
353     }
354 
355 protected:
356 
357     graph& graph_reference() const override {
358         return my_node->my_graph;
359     }
360 
361 public:
362 
363     typedef continue_msg input_type;
364     typedef continue_msg output_type;
365     threshold_regulator(T* owner)
366         : continue_receiver( /*number_of_predecessors=*/0, no_priority ), my_node(owner)
367     {
368         // Do not work with the passed pointer here as it may not be fully initialized yet
369     }
370 };
371 
372 #endif // __TBB__flow_graph_body_impl_H
373