1 /*
2 Copyright (c) 2020-2023 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 #if __INTEL_COMPILER && _MSC_VER
18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19 #endif
20
21 #include "conformance_flowgraph.h"
22 #include "common/test_invoke.h"
23
24 using input_msg = conformance::message</*default_ctor*/true, /*copy_ctor*/true, /*copy_assign*/false>;
25 using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/false>;
26
27 //! \file conformance_function_node.cpp
28 //! \brief Test for [flow_graph.function_node] specification
29
30 /*
31 Test node deduction guides
32 */
33 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
34
function_body_f(const int &)35 int function_body_f(const int&) { return 1; }
36
37 template <typename Body>
test_deduction_guides_common(Body body)38 void test_deduction_guides_common(Body body) {
39 using namespace tbb::flow;
40 graph g;
41
42 function_node f1(g, unlimited, body);
43 static_assert(std::is_same_v<decltype(f1), function_node<int, int>>);
44
45 function_node f2(g, unlimited, body, rejecting());
46 static_assert(std::is_same_v<decltype(f2), function_node<int, int, rejecting>>);
47
48 function_node f3(g, unlimited, body, node_priority_t(5));
49 static_assert(std::is_same_v<decltype(f3), function_node<int, int>>);
50
51 function_node f4(g, unlimited, body, rejecting(), node_priority_t(5));
52 static_assert(std::is_same_v<decltype(f4), function_node<int, int, rejecting>>);
53
54 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
55 function_node f5(follows(f2), unlimited, body);
56 static_assert(std::is_same_v<decltype(f5), function_node<int, int>>);
57
58 function_node f6(follows(f5), unlimited, body, rejecting());
59 static_assert(std::is_same_v<decltype(f6), function_node<int, int, rejecting>>);
60
61 function_node f7(follows(f6), unlimited, body, node_priority_t(5));
62 static_assert(std::is_same_v<decltype(f7), function_node<int, int>>);
63
64 function_node f8(follows(f7), unlimited, body, rejecting(), node_priority_t(5));
65 static_assert(std::is_same_v<decltype(f8), function_node<int, int, rejecting>>);
66 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
67
68 function_node f9(f1);
69 static_assert(std::is_same_v<decltype(f9), function_node<int, int>>);
70 }
71
test_deduction_guides()72 void test_deduction_guides() {
73 test_deduction_guides_common([](const int&)->int { return 1; });
74 test_deduction_guides_common([](const int&) mutable ->int { return 1; });
75 test_deduction_guides_common(function_body_f);
76 }
77
78 #endif
79
80 #if __TBB_CPP17_INVOKE_PRESENT
81
82 template <typename InputType, typename OutputType1, typename OutputType2,
83 typename Body1, typename Body2>
test_fn_invoke_basic(const Body1 & body1,const Body2 & body2)84 void test_fn_invoke_basic(const Body1& body1, const Body2& body2) {
85 using namespace oneapi::tbb::flow;
86
87 graph g;
88
89 function_node<InputType, OutputType1> f1(g, unlimited, body1);
90 function_node<OutputType1, OutputType2> f2(g, unlimited, body2);
91 buffer_node<OutputType2> buf(g);
92
93 make_edge(f1, f2);
94 make_edge(f2, buf);
95
96 f1.try_put(InputType{OutputType1{1}});
97
98 g.wait_for_all();
99
100 std::size_t result = 0;
101 CHECK(buf.try_get(result));
102 CHECK(result == 1);
103 CHECK(!buf.try_get(result));
104 }
105
test_fn_invoke()106 void test_fn_invoke() {
107 using output_type = test_invoke::SmartID<std::size_t>;
108 using input_type = test_invoke::SmartID<output_type>;
109 // Testing pointer to member function
110 test_fn_invoke_basic<input_type, output_type, std::size_t>(&input_type::get_id, &output_type::get_id);
111 // Testing pointer to member object
112 test_fn_invoke_basic<input_type, output_type, std::size_t>(&input_type::id, &output_type::id);
113 }
114 #endif // __TBB_CPP17_INVOKE_PRESENT
115
116 //! Test calling function body
117 //! \brief \ref interface \ref requirement
118 TEST_CASE("Test function_node body") {
119 conformance::test_body_exec<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>(oneapi::tbb::flow::unlimited);
120 }
121
122 //! Test function_node constructors
123 //! \brief \ref requirement
124 TEST_CASE("function_node constructors"){
125 using namespace oneapi::tbb::flow;
126 graph g;
127
128 conformance::counting_functor<int> fun;
129
130 function_node<int, int> fn1(g, unlimited, fun);
131 function_node<int, int> fn2(g, unlimited, fun, oneapi::tbb::flow::node_priority_t(1));
132
133 function_node<int, int, lightweight> lw_node1(g, serial, fun, lightweight());
134 function_node<int, int, lightweight> lw_node2(g, serial, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
135 }
136
137 //! The node that is constructed has a reference to the same graph object as src, has a copy of the initial body used by src, and has the same concurrency threshold as src.
138 //! The predecessors and successors of src are not copied.
139 //! \brief \ref requirement
140 TEST_CASE("function_node copy constructor"){
141 conformance::test_copy_ctor<oneapi::tbb::flow::function_node<int, int>>();
142 }
143
144 //! Test node reject the incoming message if the concurrency limit achieved.
145 //! \brief \ref interface
146 TEST_CASE("function_node with rejecting policy"){
147 conformance::test_rejecting<oneapi::tbb::flow::function_node<int, int, oneapi::tbb::flow::rejecting>>();
148 }
149
150 //! Test body copying and copy_body logic
151 //! Test the body object passed to a node is copied
152 //! \brief \ref interface
153 TEST_CASE("function_node and body copying"){
154 conformance::test_copy_body_function<oneapi::tbb::flow::function_node<int, int>, conformance::copy_counting_object<int>>(oneapi::tbb::flow::unlimited);
155 }
156
157 //! Test function_node is a graph_node, receiver<Input>, and sender<Output>
158 //! \brief \ref interface
159 TEST_CASE("function_node superclasses"){
160 conformance::test_inheritance<oneapi::tbb::flow::function_node<int, int>, int, int>();
161 conformance::test_inheritance<oneapi::tbb::flow::function_node<void*, float>, void*, float>();
162 conformance::test_inheritance<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>();
163 }
164
165 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
166 //! \brief \ref requirement
167 TEST_CASE("function_node buffering"){
168 conformance::dummy_functor<int> fun;
169 conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::rejecting>, input_msg>(oneapi::tbb::flow::unlimited, fun);
170 conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::queueing>, input_msg>(oneapi::tbb::flow::unlimited, fun);
171 }
172
173 //! Test node broadcast messages to successors
174 //! \brief \ref requirement
175 TEST_CASE("function_node broadcast"){
176 conformance::counting_functor<int> fun(conformance::expected);
177 conformance::test_forwarding<oneapi::tbb::flow::function_node<input_msg, int>, input_msg, int>(1, oneapi::tbb::flow::unlimited, fun);
178 }
179
180 //! Test deduction guides
181 //! \brief \ref interface \ref requirement
182 TEST_CASE("Deduction guides"){
183 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
184 test_deduction_guides();
185 #endif
186 }
187
188 //! Test priorities work in single-threaded configuration
189 //! \brief \ref requirement
190 TEST_CASE("function_node priority support"){
191 conformance::test_priority<oneapi::tbb::flow::function_node<input_msg, int>, input_msg>(oneapi::tbb::flow::unlimited);
192 }
193
194 //! Test function_node has a user-settable concurrency limit. It can be set to one of predefined values.
195 //! The user can also provide a value of type std::size_t to limit concurrency.
196 //! Test that not more than limited threads works in parallel.
197 //! \brief \ref requirement
198 TEST_CASE("concurrency follows set limits"){
199 conformance::test_concurrency<oneapi::tbb::flow::function_node<int, int>>();
200 }
201
202 //! Test node Input class meet the DefaultConstructible and CopyConstructible requirements and Output class meet the CopyConstructible requirements.
203 //! \brief \ref interface \ref requirement
204 TEST_CASE("Test function_node Output and Input class") {
205 using Body = conformance::copy_counting_object<int>;
206 conformance::test_output_input_class<oneapi::tbb::flow::function_node<Body, Body>, Body>();
207 }
208
209 #if __TBB_CPP17_INVOKE_PRESENT
210 //! Test that function_node uses std::invoke to execute the body
211 //! \brief \ref interface \ref requirement
212 TEST_CASE("Test function_node and std::invoke") {
213 test_fn_invoke();
214 }
215 #endif
216