1 /*
2 Copyright (c) 2020-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 #if __INTEL_COMPILER && _MSC_VER
18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19 #endif
20
21 #define CONFORMANCE_CONTINUE_NODE
22
23 #include "conformance_flowgraph.h"
24
25 //! \file conformance_continue_node.cpp
26 //! \brief Test for [flow_graph.continue_node] specification
27
28 using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/true/*enable for queue_node successor*/>;
29
30 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
31
32 template <typename ExpectedType, typename Body>
test_deduction_guides_common(Body body)33 void test_deduction_guides_common(Body body) {
34 using namespace tbb::flow;
35 graph g;
36
37 continue_node c1(g, body);
38 static_assert(std::is_same_v<decltype(c1), continue_node<ExpectedType>>);
39
40 continue_node c2(g, body, lightweight());
41 static_assert(std::is_same_v<decltype(c2), continue_node<ExpectedType, lightweight>>);
42
43 continue_node c3(g, 5, body);
44 static_assert(std::is_same_v<decltype(c3), continue_node<ExpectedType>>);
45
46 continue_node c4(g, 5, body, lightweight());
47 static_assert(std::is_same_v<decltype(c4), continue_node<ExpectedType, lightweight>>);
48
49 continue_node c5(g, body, node_priority_t(5));
50 static_assert(std::is_same_v<decltype(c5), continue_node<ExpectedType>>);
51
52 continue_node c6(g, body, lightweight(), node_priority_t(5));
53 static_assert(std::is_same_v<decltype(c6), continue_node<ExpectedType, lightweight>>);
54
55 continue_node c7(g, 5, body, node_priority_t(5));
56 static_assert(std::is_same_v<decltype(c7), continue_node<ExpectedType>>);
57
58 continue_node c8(g, 5, body, lightweight(), node_priority_t(5));
59 static_assert(std::is_same_v<decltype(c8), continue_node<ExpectedType, lightweight>>);
60
61 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
62 broadcast_node<continue_msg> b(g);
63
64 continue_node c9(follows(b), body);
65 static_assert(std::is_same_v<decltype(c9), continue_node<ExpectedType>>);
66
67 continue_node c10(follows(b), body, lightweight());
68 static_assert(std::is_same_v<decltype(c10), continue_node<ExpectedType, lightweight>>);
69
70 continue_node c11(follows(b), 5, body);
71 static_assert(std::is_same_v<decltype(c11), continue_node<ExpectedType>>);
72
73 continue_node c12(follows(b), 5, body, lightweight());
74 static_assert(std::is_same_v<decltype(c12), continue_node<ExpectedType, lightweight>>);
75
76 continue_node c13(follows(b), body, node_priority_t(5));
77 static_assert(std::is_same_v<decltype(c13), continue_node<ExpectedType>>);
78
79 continue_node c14(follows(b), body, lightweight(), node_priority_t(5));
80 static_assert(std::is_same_v<decltype(c14), continue_node<ExpectedType, lightweight>>);
81
82 continue_node c15(follows(b), 5, body, node_priority_t(5));
83 static_assert(std::is_same_v<decltype(c15), continue_node<ExpectedType>>);
84
85 continue_node c16(follows(b), 5, body, lightweight(), node_priority_t(5));
86 static_assert(std::is_same_v<decltype(c16), continue_node<ExpectedType, lightweight>>);
87 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
88
89 continue_node c17(c1);
90 static_assert(std::is_same_v<decltype(c17), continue_node<ExpectedType>>);
91 }
92
continue_body_f(const tbb::flow::continue_msg &)93 int continue_body_f(const tbb::flow::continue_msg&) { return 1; }
continue_void_body_f(const tbb::flow::continue_msg &)94 void continue_void_body_f(const tbb::flow::continue_msg&) {}
95
test_deduction_guides()96 void test_deduction_guides() {
97 using tbb::flow::continue_msg;
98 test_deduction_guides_common<int>([](const continue_msg&)->int { return 1; } );
99 test_deduction_guides_common<continue_msg>([](const continue_msg&) {});
100
101 test_deduction_guides_common<int>([](const continue_msg&) mutable ->int { return 1; });
102 test_deduction_guides_common<continue_msg>([](const continue_msg&) mutable {});
103
104 test_deduction_guides_common<int>(continue_body_f);
105 test_deduction_guides_common<continue_msg>(continue_void_body_f);
106 }
107
108 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
109
110 //! Test execution of node body
111 //! Test node can do try_put call
112 //! \brief \ref interface \ref requirement
113 TEST_CASE("continue body") {
114 conformance::test_body_exec<oneapi::tbb::flow::continue_node<output_msg>, oneapi::tbb::flow::continue_msg, output_msg>();
115 }
116
117 //! Test continue_node is a graph_node, receiver<continue_msg>, and sender<Output>
118 //! \brief \ref interface
119 TEST_CASE("continue_node superclasses"){
120 conformance::test_inheritance<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg, int>();
121 conformance::test_inheritance<oneapi::tbb::flow::continue_node<void*>, oneapi::tbb::flow::continue_msg, void*>();
122 conformance::test_inheritance<oneapi::tbb::flow::continue_node<output_msg>, oneapi::tbb::flow::continue_msg, output_msg>();
123 }
124
125 //! Test body copying and copy_body logic
126 //! Test the body object passed to a node is copied
127 //! \brief \ref interface
128 TEST_CASE("continue_node and body copying"){
129 conformance::test_copy_body_function<oneapi::tbb::flow::continue_node<int>, conformance::copy_counting_object<int, oneapi::tbb::flow::continue_msg>>();
130 }
131
132 //! Test deduction guides
133 //! \brief \ref interface \ref requirement
134 TEST_CASE("Deduction guides"){
135 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
136 test_deduction_guides();
137 #endif
138 }
139
140 //! Test node broadcast messages to successors
141 //! \brief \ref requirement
142 TEST_CASE("continue_node broadcast"){
143 conformance::counting_functor<int> fun(conformance::expected);
144 conformance::test_forwarding<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg, int>(1, fun);
145 }
146
147 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
148 //! \brief \ref requirement
149 TEST_CASE("continue_node buffering"){
150 conformance::dummy_functor<int> fun;
151 conformance::test_buffering<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg>(fun);
152 }
153
154 //! Test all node costructors
155 //! \brief \ref requirement
156 TEST_CASE("continue_node constructors"){
157 using namespace oneapi::tbb::flow;
158 graph g;
159
160 conformance::counting_functor<int> fun;
161
162 continue_node<int> proto1(g, fun);
163 continue_node<int> proto2(g, fun, oneapi::tbb::flow::node_priority_t(1));
164 continue_node<int> proto3(g, 2, fun);
165 continue_node<int> proto4(g, 2, fun, oneapi::tbb::flow::node_priority_t(1));
166
167 continue_node<int, lightweight> lw_node1(g, fun, lightweight());
168 continue_node<int, lightweight> lw_node2(g, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
169 continue_node<int, lightweight> lw_node3(g, 2, fun, lightweight());
170 continue_node<int, lightweight> lw_node4(g, 2, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
171 }
172
173 //! The node that is constructed has a reference to the same graph object as src,
174 //! has a copy of the initial body used by src, and only has a non-zero threshold if src is constructed with a non-zero threshold..
175 //! The predecessors and successors of src are not copied.
176 //! \brief \ref interface
177 TEST_CASE("continue_node copy constructor"){
178 using namespace oneapi::tbb::flow;
179 graph g;
180
181 conformance::dummy_functor<oneapi::tbb::flow::continue_msg> fun1;
182 using counting_body = conformance::copy_counting_object<output_msg, oneapi::tbb::flow::continue_msg>;
183 counting_body fun2;
184
185 continue_node<oneapi::tbb::flow::continue_msg> node0(g, fun1);
186 continue_node<output_msg> node1(g, 2, fun2);
187 conformance::test_push_receiver<output_msg> node2(g);
188 conformance::test_push_receiver<output_msg> node3(g);
189
190 oneapi::tbb::flow::make_edge(node0, node1);
191 oneapi::tbb::flow::make_edge(node1, node2);
192
193 continue_node<output_msg> node_copy(node1);
194
195 counting_body b2 = copy_body<counting_body, continue_node<output_msg>>(node_copy);
196
197 CHECK_MESSAGE((fun2.copy_count + 1 < b2.copy_count), "constructor should copy bodies");
198
199 oneapi::tbb::flow::make_edge(node_copy, node3);
200
201 node_copy.try_put(oneapi::tbb::flow::continue_msg());
202 g.wait_for_all();
203
204 CHECK_MESSAGE((conformance::get_values(node2).size() == 0 && conformance::get_values(node3).size() == 0), "Copied node doesn`t copy successor, but copy number of predecessors");
205
206 node_copy.try_put(oneapi::tbb::flow::continue_msg());
207 g.wait_for_all();
208
209 CHECK_MESSAGE((conformance::get_values(node2).size() == 0 && conformance::get_values(node3).size() == 1), "Copied node doesn`t copy successor, but copy number of predecessors");
210
211 node1.try_put(oneapi::tbb::flow::continue_msg());
212 node1.try_put(oneapi::tbb::flow::continue_msg());
213 node0.try_put(oneapi::tbb::flow::continue_msg());
214 g.wait_for_all();
215
216 CHECK_MESSAGE((conformance::get_values(node2).size() == 1 && conformance::get_values(node3).size() == 0), "Copied node doesn`t copy predecessor, but copy number of predecessors");
217 }
218
219 //! Test continue_node wait for their predecessors to complete before executing, but no explicit data is passed across the incoming edges.
220 //! \brief \ref requirement
221 TEST_CASE("continue_node number_of_predecessors") {
222 oneapi::tbb::flow::graph g;
223
224 conformance::counting_functor<int> fun;
225
226 oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node1(g, fun);
227 oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node2(g, 1, fun);
228 oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node3(g, 1, fun);
229 oneapi::tbb::flow::continue_node<int> node4(g, fun);
230
231 oneapi::tbb::flow::make_edge(node1, node2);
232 oneapi::tbb::flow::make_edge(node2, node4);
233 oneapi::tbb::flow::make_edge(node1, node3);
234 oneapi::tbb::flow::make_edge(node1, node3);
235 oneapi::tbb::flow::remove_edge(node1, node3);
236 oneapi::tbb::flow::make_edge(node3, node4);
237 node3.try_put(oneapi::tbb::flow::continue_msg());
238 node2.try_put(oneapi::tbb::flow::continue_msg());
239 node1.try_put(oneapi::tbb::flow::continue_msg());
240
241 g.wait_for_all();
242 CHECK_MESSAGE((fun.execute_count == 4), "Node wait for their predecessors to complete before executing");
243 }
244
245 //! Test nodes for execution with priority in single-threaded configuration
246 //! \brief \ref requirement
247 TEST_CASE("continue_node priority support"){
248 conformance::test_priority<oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg, int>, oneapi::tbb::flow::continue_msg>();
249 }
250
251 //! Test node Output class meet the CopyConstructible requirements.
252 //! \brief \ref requirement
253 TEST_CASE("continue_node Output class") {
254 conformance::test_output_class<oneapi::tbb::flow::continue_node<conformance::copy_counting_object<int, oneapi::tbb::flow::continue_msg>>, conformance::copy_counting_object<int, oneapi::tbb::flow::continue_msg>>();
255 }
256
257 //! Test body `try_put' statement not wait for the execution of the body to complete
258 //! \brief \ref requirement
259 TEST_CASE("continue_node `try_put' statement not wait for the execution of the body to complete") {
260 conformance::wait_flag_body body;
261 oneapi::tbb::flow::graph g;
262
263 oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node1(g, body);
264 node1.try_put(oneapi::tbb::flow::continue_msg());
265 conformance::wait_flag_body::flag.store(true);
266 g.wait_for_all();
267 }
268