151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2020-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
17b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19b15aabb3Stbbdev #endif
20b15aabb3Stbbdev 
21*de0109beSIlya Mishin #define CONFORMANCE_CONTINUE_NODE
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev #include "conformance_flowgraph.h"
2451c0b2f7Stbbdev 
2551c0b2f7Stbbdev //! \file conformance_continue_node.cpp
2651c0b2f7Stbbdev //! \brief Test for [flow_graph.continue_node] specification
2751c0b2f7Stbbdev 
28*de0109beSIlya Mishin using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/true/*enable for queue_node successor*/>;
2951c0b2f7Stbbdev 
3051c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
31*de0109beSIlya Mishin 
32*de0109beSIlya Mishin template <typename ExpectedType, typename Body>
test_deduction_guides_common(Body body)33*de0109beSIlya Mishin void test_deduction_guides_common(Body body) {
34*de0109beSIlya Mishin     using namespace tbb::flow;
35*de0109beSIlya Mishin     graph g;
36*de0109beSIlya Mishin 
37*de0109beSIlya Mishin     continue_node c1(g, body);
38*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c1), continue_node<ExpectedType>>);
39*de0109beSIlya Mishin 
40*de0109beSIlya Mishin     continue_node c2(g, body, lightweight());
41*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c2), continue_node<ExpectedType, lightweight>>);
42*de0109beSIlya Mishin 
43*de0109beSIlya Mishin     continue_node c3(g, 5, body);
44*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c3), continue_node<ExpectedType>>);
45*de0109beSIlya Mishin 
46*de0109beSIlya Mishin     continue_node c4(g, 5, body, lightweight());
47*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c4), continue_node<ExpectedType, lightweight>>);
48*de0109beSIlya Mishin 
49*de0109beSIlya Mishin     continue_node c5(g, body, node_priority_t(5));
50*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c5), continue_node<ExpectedType>>);
51*de0109beSIlya Mishin 
52*de0109beSIlya Mishin     continue_node c6(g, body, lightweight(), node_priority_t(5));
53*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c6), continue_node<ExpectedType, lightweight>>);
54*de0109beSIlya Mishin 
55*de0109beSIlya Mishin     continue_node c7(g, 5, body, node_priority_t(5));
56*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c7), continue_node<ExpectedType>>);
57*de0109beSIlya Mishin 
58*de0109beSIlya Mishin     continue_node c8(g, 5, body, lightweight(), node_priority_t(5));
59*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c8), continue_node<ExpectedType, lightweight>>);
60*de0109beSIlya Mishin 
61*de0109beSIlya Mishin #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
62*de0109beSIlya Mishin     broadcast_node<continue_msg> b(g);
63*de0109beSIlya Mishin 
64*de0109beSIlya Mishin     continue_node c9(follows(b), body);
65*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c9), continue_node<ExpectedType>>);
66*de0109beSIlya Mishin 
67*de0109beSIlya Mishin     continue_node c10(follows(b), body, lightweight());
68*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c10), continue_node<ExpectedType, lightweight>>);
69*de0109beSIlya Mishin 
70*de0109beSIlya Mishin     continue_node c11(follows(b), 5, body);
71*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c11), continue_node<ExpectedType>>);
72*de0109beSIlya Mishin 
73*de0109beSIlya Mishin     continue_node c12(follows(b), 5, body, lightweight());
74*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c12), continue_node<ExpectedType, lightweight>>);
75*de0109beSIlya Mishin 
76*de0109beSIlya Mishin     continue_node c13(follows(b), body, node_priority_t(5));
77*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c13), continue_node<ExpectedType>>);
78*de0109beSIlya Mishin 
79*de0109beSIlya Mishin     continue_node c14(follows(b), body, lightweight(), node_priority_t(5));
80*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c14), continue_node<ExpectedType, lightweight>>);
81*de0109beSIlya Mishin 
82*de0109beSIlya Mishin     continue_node c15(follows(b), 5, body, node_priority_t(5));
83*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c15), continue_node<ExpectedType>>);
84*de0109beSIlya Mishin 
85*de0109beSIlya Mishin     continue_node c16(follows(b), 5, body, lightweight(), node_priority_t(5));
86*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c16), continue_node<ExpectedType, lightweight>>);
87*de0109beSIlya Mishin #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
88*de0109beSIlya Mishin 
89*de0109beSIlya Mishin     continue_node c17(c1);
90*de0109beSIlya Mishin     static_assert(std::is_same_v<decltype(c17), continue_node<ExpectedType>>);
91*de0109beSIlya Mishin }
92*de0109beSIlya Mishin 
continue_body_f(const tbb::flow::continue_msg &)93*de0109beSIlya Mishin int continue_body_f(const tbb::flow::continue_msg&) { return 1; }
continue_void_body_f(const tbb::flow::continue_msg &)94*de0109beSIlya Mishin void continue_void_body_f(const tbb::flow::continue_msg&) {}
95*de0109beSIlya Mishin 
test_deduction_guides()9651c0b2f7Stbbdev void test_deduction_guides() {
97*de0109beSIlya Mishin     using tbb::flow::continue_msg;
98*de0109beSIlya Mishin     test_deduction_guides_common<int>([](const continue_msg&)->int { return 1; } );
99*de0109beSIlya Mishin     test_deduction_guides_common<continue_msg>([](const continue_msg&) {});
10051c0b2f7Stbbdev 
101*de0109beSIlya Mishin     test_deduction_guides_common<int>([](const continue_msg&) mutable ->int { return 1; });
102*de0109beSIlya Mishin     test_deduction_guides_common<continue_msg>([](const continue_msg&) mutable {});
10351c0b2f7Stbbdev 
104*de0109beSIlya Mishin     test_deduction_guides_common<int>(continue_body_f);
105*de0109beSIlya Mishin     test_deduction_guides_common<continue_msg>(continue_void_body_f);
10651c0b2f7Stbbdev }
10751c0b2f7Stbbdev 
108*de0109beSIlya Mishin #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
10951c0b2f7Stbbdev 
110*de0109beSIlya Mishin //! Test execution of node body
111*de0109beSIlya Mishin //! Test node can do try_put call
112*de0109beSIlya Mishin //! \brief \ref interface \ref requirement
113*de0109beSIlya Mishin TEST_CASE("continue body") {
114*de0109beSIlya Mishin     conformance::test_body_exec<oneapi::tbb::flow::continue_node<output_msg>, oneapi::tbb::flow::continue_msg, output_msg>();
11551c0b2f7Stbbdev }
11651c0b2f7Stbbdev 
117*de0109beSIlya Mishin //! Test continue_node is a graph_node, receiver<continue_msg>, and sender<Output>
118*de0109beSIlya Mishin //! \brief \ref interface
119*de0109beSIlya Mishin TEST_CASE("continue_node superclasses"){
120*de0109beSIlya Mishin     conformance::test_inheritance<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg, int>();
121*de0109beSIlya Mishin     conformance::test_inheritance<oneapi::tbb::flow::continue_node<void*>, oneapi::tbb::flow::continue_msg, void*>();
122*de0109beSIlya Mishin     conformance::test_inheritance<oneapi::tbb::flow::continue_node<output_msg>, oneapi::tbb::flow::continue_msg, output_msg>();
12351c0b2f7Stbbdev }
12451c0b2f7Stbbdev 
12551c0b2f7Stbbdev //! Test body copying and copy_body logic
126*de0109beSIlya Mishin //! Test the body object passed to a node is copied
12751c0b2f7Stbbdev //! \brief \ref interface
12851c0b2f7Stbbdev TEST_CASE("continue_node and body copying"){
129*de0109beSIlya Mishin     conformance::test_copy_body_function<oneapi::tbb::flow::continue_node<int>, conformance::copy_counting_object<int, oneapi::tbb::flow::continue_msg>>();
13051c0b2f7Stbbdev }
13151c0b2f7Stbbdev 
13251c0b2f7Stbbdev //! Test deduction guides
13351c0b2f7Stbbdev //! \brief \ref interface \ref requirement
13451c0b2f7Stbbdev TEST_CASE("Deduction guides"){
13551c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
13651c0b2f7Stbbdev     test_deduction_guides();
13751c0b2f7Stbbdev #endif
13851c0b2f7Stbbdev }
13951c0b2f7Stbbdev 
140*de0109beSIlya Mishin //! Test node broadcast messages to successors
141*de0109beSIlya Mishin //! \brief \ref requirement
142*de0109beSIlya Mishin TEST_CASE("continue_node broadcast"){
143*de0109beSIlya Mishin     conformance::counting_functor<int> fun(conformance::expected);
144*de0109beSIlya Mishin     conformance::test_forwarding<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg, int>(1, fun);
14551c0b2f7Stbbdev }
14651c0b2f7Stbbdev 
147*de0109beSIlya Mishin //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
148*de0109beSIlya Mishin //! \brief \ref requirement
149*de0109beSIlya Mishin TEST_CASE("continue_node buffering"){
150*de0109beSIlya Mishin     conformance::dummy_functor<int> fun;
151*de0109beSIlya Mishin     conformance::test_buffering<oneapi::tbb::flow::continue_node<int>, oneapi::tbb::flow::continue_msg>(fun);
152*de0109beSIlya Mishin }
153*de0109beSIlya Mishin 
154*de0109beSIlya Mishin //! Test all node costructors
155*de0109beSIlya Mishin //! \brief \ref requirement
156*de0109beSIlya Mishin TEST_CASE("continue_node constructors"){
157*de0109beSIlya Mishin     using namespace oneapi::tbb::flow;
158*de0109beSIlya Mishin     graph g;
159*de0109beSIlya Mishin 
160*de0109beSIlya Mishin     conformance::counting_functor<int> fun;
161*de0109beSIlya Mishin 
162*de0109beSIlya Mishin     continue_node<int> proto1(g, fun);
163*de0109beSIlya Mishin     continue_node<int> proto2(g, fun, oneapi::tbb::flow::node_priority_t(1));
164*de0109beSIlya Mishin     continue_node<int> proto3(g, 2, fun);
165*de0109beSIlya Mishin     continue_node<int> proto4(g, 2, fun, oneapi::tbb::flow::node_priority_t(1));
166*de0109beSIlya Mishin 
167*de0109beSIlya Mishin     continue_node<int, lightweight> lw_node1(g, fun, lightweight());
168*de0109beSIlya Mishin     continue_node<int, lightweight> lw_node2(g, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
169*de0109beSIlya Mishin     continue_node<int, lightweight> lw_node3(g, 2, fun, lightweight());
170*de0109beSIlya Mishin     continue_node<int, lightweight> lw_node4(g, 2, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
171*de0109beSIlya Mishin }
172*de0109beSIlya Mishin 
173*de0109beSIlya Mishin //! The node that is constructed has a reference to the same graph object as src,
174*de0109beSIlya Mishin //! 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*de0109beSIlya Mishin //! The predecessors and successors of src are not copied.
176*de0109beSIlya Mishin //! \brief \ref interface
177*de0109beSIlya Mishin TEST_CASE("continue_node copy constructor"){
178*de0109beSIlya Mishin     using namespace oneapi::tbb::flow;
179*de0109beSIlya Mishin     graph g;
180*de0109beSIlya Mishin 
181*de0109beSIlya Mishin     conformance::dummy_functor<oneapi::tbb::flow::continue_msg> fun1;
182*de0109beSIlya Mishin     using counting_body = conformance::copy_counting_object<output_msg, oneapi::tbb::flow::continue_msg>;
183*de0109beSIlya Mishin     counting_body fun2;
184*de0109beSIlya Mishin 
185*de0109beSIlya Mishin     continue_node<oneapi::tbb::flow::continue_msg> node0(g, fun1);
186*de0109beSIlya Mishin     continue_node<output_msg> node1(g, 2, fun2);
187*de0109beSIlya Mishin     conformance::test_push_receiver<output_msg> node2(g);
188*de0109beSIlya Mishin     conformance::test_push_receiver<output_msg> node3(g);
189*de0109beSIlya Mishin 
190*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node0, node1);
191*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node1, node2);
192*de0109beSIlya Mishin 
193*de0109beSIlya Mishin     continue_node<output_msg> node_copy(node1);
194*de0109beSIlya Mishin 
195*de0109beSIlya Mishin     counting_body b2 = copy_body<counting_body, continue_node<output_msg>>(node_copy);
196*de0109beSIlya Mishin 
197*de0109beSIlya Mishin     CHECK_MESSAGE((fun2.copy_count + 1 < b2.copy_count), "constructor should copy bodies");
198*de0109beSIlya Mishin 
199*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node_copy, node3);
200*de0109beSIlya Mishin 
201*de0109beSIlya Mishin     node_copy.try_put(oneapi::tbb::flow::continue_msg());
202*de0109beSIlya Mishin     g.wait_for_all();
203*de0109beSIlya Mishin 
204*de0109beSIlya Mishin     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*de0109beSIlya Mishin 
206*de0109beSIlya Mishin     node_copy.try_put(oneapi::tbb::flow::continue_msg());
207*de0109beSIlya Mishin     g.wait_for_all();
208*de0109beSIlya Mishin 
209*de0109beSIlya Mishin     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*de0109beSIlya Mishin 
211*de0109beSIlya Mishin     node1.try_put(oneapi::tbb::flow::continue_msg());
212*de0109beSIlya Mishin     node1.try_put(oneapi::tbb::flow::continue_msg());
213*de0109beSIlya Mishin     node0.try_put(oneapi::tbb::flow::continue_msg());
214*de0109beSIlya Mishin     g.wait_for_all();
215*de0109beSIlya Mishin 
216*de0109beSIlya Mishin     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*de0109beSIlya Mishin }
218*de0109beSIlya Mishin 
219*de0109beSIlya Mishin //! Test continue_node wait for their predecessors to complete before executing, but no explicit data is passed across the incoming edges.
220*de0109beSIlya Mishin //! \brief \ref requirement
221*de0109beSIlya Mishin TEST_CASE("continue_node number_of_predecessors") {
222*de0109beSIlya Mishin     oneapi::tbb::flow::graph g;
223*de0109beSIlya Mishin 
224*de0109beSIlya Mishin     conformance::counting_functor<int> fun;
225*de0109beSIlya Mishin 
226*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node1(g, fun);
227*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node2(g, 1, fun);
228*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node3(g, 1, fun);
229*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<int> node4(g, fun);
230*de0109beSIlya Mishin 
231*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node1, node2);
232*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node2, node4);
233*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node1, node3);
234*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node1, node3);
235*de0109beSIlya Mishin     oneapi::tbb::flow::remove_edge(node1, node3);
236*de0109beSIlya Mishin     oneapi::tbb::flow::make_edge(node3, node4);
237*de0109beSIlya Mishin     node3.try_put(oneapi::tbb::flow::continue_msg());
238*de0109beSIlya Mishin     node2.try_put(oneapi::tbb::flow::continue_msg());
239*de0109beSIlya Mishin     node1.try_put(oneapi::tbb::flow::continue_msg());
240*de0109beSIlya Mishin 
241*de0109beSIlya Mishin     g.wait_for_all();
242*de0109beSIlya Mishin     CHECK_MESSAGE((fun.execute_count == 4), "Node wait for their predecessors to complete before executing");
243*de0109beSIlya Mishin }
244*de0109beSIlya Mishin 
245*de0109beSIlya Mishin //! Test nodes for execution with priority in single-threaded configuration
246*de0109beSIlya Mishin //! \brief \ref requirement
247*de0109beSIlya Mishin TEST_CASE("continue_node priority support"){
248*de0109beSIlya Mishin     conformance::test_priority<oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg, int>, oneapi::tbb::flow::continue_msg>();
249*de0109beSIlya Mishin }
250*de0109beSIlya Mishin 
251*de0109beSIlya Mishin //! Test node Output class meet the CopyConstructible requirements.
252*de0109beSIlya Mishin //! \brief \ref requirement
253*de0109beSIlya Mishin TEST_CASE("continue_node Output class") {
254*de0109beSIlya Mishin     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*de0109beSIlya Mishin }
256*de0109beSIlya Mishin 
257*de0109beSIlya Mishin //! Test body `try_put' statement not wait for the execution of the body to complete
258*de0109beSIlya Mishin //! \brief \ref requirement
259*de0109beSIlya Mishin TEST_CASE("continue_node `try_put' statement not wait for the execution of the body to complete") {
260*de0109beSIlya Mishin     conformance::wait_flag_body body;
261*de0109beSIlya Mishin     oneapi::tbb::flow::graph g;
262*de0109beSIlya Mishin 
263*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<oneapi::tbb::flow::continue_msg> node1(g, body);
264*de0109beSIlya Mishin     node1.try_put(oneapi::tbb::flow::continue_msg());
265*de0109beSIlya Mishin     conformance::wait_flag_body::flag.store(true);
266*de0109beSIlya Mishin     g.wait_for_all();
26751c0b2f7Stbbdev }
268