151c0b2f7Stbbdev /*
2*a088cfa0SKonstantin Boyarinov Copyright (c) 2020-2023 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
2151c0b2f7Stbbdev #include "conformance_flowgraph.h"
22*a088cfa0SKonstantin Boyarinov #include "common/test_invoke.h"
2351c0b2f7Stbbdev
24de0109beSIlya Mishin using input_msg = conformance::message</*default_ctor*/true, /*copy_ctor*/true, /*copy_assign*/false>;
25de0109beSIlya Mishin using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/false>;
26de0109beSIlya Mishin
2751c0b2f7Stbbdev //! \file conformance_function_node.cpp
2851c0b2f7Stbbdev //! \brief Test for [flow_graph.function_node] specification
2951c0b2f7Stbbdev
3051c0b2f7Stbbdev /*
31de0109beSIlya Mishin Test node deduction guides
3251c0b2f7Stbbdev */
3351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
34de0109beSIlya Mishin
function_body_f(const int &)35de0109beSIlya Mishin int function_body_f(const int&) { return 1; }
36de0109beSIlya Mishin
37de0109beSIlya Mishin template <typename Body>
test_deduction_guides_common(Body body)38de0109beSIlya Mishin void test_deduction_guides_common(Body body) {
39de0109beSIlya Mishin using namespace tbb::flow;
4051c0b2f7Stbbdev graph g;
4151c0b2f7Stbbdev
4251c0b2f7Stbbdev function_node f1(g, unlimited, body);
43de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f1), function_node<int, int>>);
44de0109beSIlya Mishin
45de0109beSIlya Mishin function_node f2(g, unlimited, body, rejecting());
46de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f2), function_node<int, int, rejecting>>);
47de0109beSIlya Mishin
48de0109beSIlya Mishin function_node f3(g, unlimited, body, node_priority_t(5));
49de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f3), function_node<int, int>>);
50de0109beSIlya Mishin
51de0109beSIlya Mishin function_node f4(g, unlimited, body, rejecting(), node_priority_t(5));
52de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f4), function_node<int, int, rejecting>>);
53de0109beSIlya Mishin
54de0109beSIlya Mishin #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
55de0109beSIlya Mishin function_node f5(follows(f2), unlimited, body);
56de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f5), function_node<int, int>>);
57de0109beSIlya Mishin
58de0109beSIlya Mishin function_node f6(follows(f5), unlimited, body, rejecting());
59de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f6), function_node<int, int, rejecting>>);
60de0109beSIlya Mishin
61de0109beSIlya Mishin function_node f7(follows(f6), unlimited, body, node_priority_t(5));
62de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f7), function_node<int, int>>);
63de0109beSIlya Mishin
64de0109beSIlya Mishin function_node f8(follows(f7), unlimited, body, rejecting(), node_priority_t(5));
65de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f8), function_node<int, int, rejecting>>);
66de0109beSIlya Mishin #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
67de0109beSIlya Mishin
68de0109beSIlya Mishin function_node f9(f1);
69de0109beSIlya Mishin static_assert(std::is_same_v<decltype(f9), function_node<int, int>>);
7051c0b2f7Stbbdev }
71de0109beSIlya Mishin
test_deduction_guides()72de0109beSIlya Mishin void test_deduction_guides() {
73de0109beSIlya Mishin test_deduction_guides_common([](const int&)->int { return 1; });
74de0109beSIlya Mishin test_deduction_guides_common([](const int&) mutable ->int { return 1; });
75de0109beSIlya Mishin test_deduction_guides_common(function_body_f);
76de0109beSIlya Mishin }
77de0109beSIlya Mishin
7851c0b2f7Stbbdev #endif
7951c0b2f7Stbbdev
80*a088cfa0SKonstantin Boyarinov #if __TBB_CPP17_INVOKE_PRESENT
81*a088cfa0SKonstantin Boyarinov
82*a088cfa0SKonstantin Boyarinov template <typename InputType, typename OutputType1, typename OutputType2,
83*a088cfa0SKonstantin Boyarinov typename Body1, typename Body2>
test_fn_invoke_basic(const Body1 & body1,const Body2 & body2)84*a088cfa0SKonstantin Boyarinov void test_fn_invoke_basic(const Body1& body1, const Body2& body2) {
85*a088cfa0SKonstantin Boyarinov using namespace oneapi::tbb::flow;
86*a088cfa0SKonstantin Boyarinov
87*a088cfa0SKonstantin Boyarinov graph g;
88*a088cfa0SKonstantin Boyarinov
89*a088cfa0SKonstantin Boyarinov function_node<InputType, OutputType1> f1(g, unlimited, body1);
90*a088cfa0SKonstantin Boyarinov function_node<OutputType1, OutputType2> f2(g, unlimited, body2);
91*a088cfa0SKonstantin Boyarinov buffer_node<OutputType2> buf(g);
92*a088cfa0SKonstantin Boyarinov
93*a088cfa0SKonstantin Boyarinov make_edge(f1, f2);
94*a088cfa0SKonstantin Boyarinov make_edge(f2, buf);
95*a088cfa0SKonstantin Boyarinov
96*a088cfa0SKonstantin Boyarinov f1.try_put(InputType{OutputType1{1}});
97*a088cfa0SKonstantin Boyarinov
98*a088cfa0SKonstantin Boyarinov g.wait_for_all();
99*a088cfa0SKonstantin Boyarinov
100*a088cfa0SKonstantin Boyarinov std::size_t result = 0;
101*a088cfa0SKonstantin Boyarinov CHECK(buf.try_get(result));
102*a088cfa0SKonstantin Boyarinov CHECK(result == 1);
103*a088cfa0SKonstantin Boyarinov CHECK(!buf.try_get(result));
104*a088cfa0SKonstantin Boyarinov }
105*a088cfa0SKonstantin Boyarinov
test_fn_invoke()106*a088cfa0SKonstantin Boyarinov void test_fn_invoke() {
107*a088cfa0SKonstantin Boyarinov using output_type = test_invoke::SmartID<std::size_t>;
108*a088cfa0SKonstantin Boyarinov using input_type = test_invoke::SmartID<output_type>;
109*a088cfa0SKonstantin Boyarinov // Testing pointer to member function
110*a088cfa0SKonstantin Boyarinov test_fn_invoke_basic<input_type, output_type, std::size_t>(&input_type::get_id, &output_type::get_id);
111*a088cfa0SKonstantin Boyarinov // Testing pointer to member object
112*a088cfa0SKonstantin Boyarinov test_fn_invoke_basic<input_type, output_type, std::size_t>(&input_type::id, &output_type::id);
113*a088cfa0SKonstantin Boyarinov }
114*a088cfa0SKonstantin Boyarinov #endif // __TBB_CPP17_INVOKE_PRESENT
115*a088cfa0SKonstantin Boyarinov
116de0109beSIlya Mishin //! Test calling function body
117de0109beSIlya Mishin //! \brief \ref interface \ref requirement
118de0109beSIlya Mishin TEST_CASE("Test function_node body") {
119de0109beSIlya Mishin conformance::test_body_exec<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>(oneapi::tbb::flow::unlimited);
12051c0b2f7Stbbdev }
12151c0b2f7Stbbdev
122de0109beSIlya Mishin //! Test function_node constructors
123de0109beSIlya Mishin //! \brief \ref requirement
124de0109beSIlya Mishin TEST_CASE("function_node constructors"){
12549e08aacStbbdev using namespace oneapi::tbb::flow;
12651c0b2f7Stbbdev graph g;
12751c0b2f7Stbbdev
128de0109beSIlya Mishin conformance::counting_functor<int> fun;
12951c0b2f7Stbbdev
130de0109beSIlya Mishin function_node<int, int> fn1(g, unlimited, fun);
131de0109beSIlya Mishin function_node<int, int> fn2(g, unlimited, fun, oneapi::tbb::flow::node_priority_t(1));
132de0109beSIlya Mishin
133de0109beSIlya Mishin function_node<int, int, lightweight> lw_node1(g, serial, fun, lightweight());
134de0109beSIlya Mishin function_node<int, int, lightweight> lw_node2(g, serial, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
13551c0b2f7Stbbdev }
13651c0b2f7Stbbdev
137de0109beSIlya Mishin //! 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.
138de0109beSIlya Mishin //! The predecessors and successors of src are not copied.
139de0109beSIlya Mishin //! \brief \ref requirement
140de0109beSIlya Mishin TEST_CASE("function_node copy constructor"){
141de0109beSIlya Mishin conformance::test_copy_ctor<oneapi::tbb::flow::function_node<int, int>>();
14251c0b2f7Stbbdev }
14351c0b2f7Stbbdev
144de0109beSIlya Mishin //! Test node reject the incoming message if the concurrency limit achieved.
14551c0b2f7Stbbdev //! \brief \ref interface
14651c0b2f7Stbbdev TEST_CASE("function_node with rejecting policy"){
147de0109beSIlya Mishin conformance::test_rejecting<oneapi::tbb::flow::function_node<int, int, oneapi::tbb::flow::rejecting>>();
14851c0b2f7Stbbdev }
14951c0b2f7Stbbdev
15051c0b2f7Stbbdev //! Test body copying and copy_body logic
151de0109beSIlya Mishin //! Test the body object passed to a node is copied
15251c0b2f7Stbbdev //! \brief \ref interface
15351c0b2f7Stbbdev TEST_CASE("function_node and body copying"){
154de0109beSIlya Mishin conformance::test_copy_body_function<oneapi::tbb::flow::function_node<int, int>, conformance::copy_counting_object<int>>(oneapi::tbb::flow::unlimited);
15551c0b2f7Stbbdev }
15651c0b2f7Stbbdev
157de0109beSIlya Mishin //! Test function_node is a graph_node, receiver<Input>, and sender<Output>
15851c0b2f7Stbbdev //! \brief \ref interface
15951c0b2f7Stbbdev TEST_CASE("function_node superclasses"){
160de0109beSIlya Mishin conformance::test_inheritance<oneapi::tbb::flow::function_node<int, int>, int, int>();
161de0109beSIlya Mishin conformance::test_inheritance<oneapi::tbb::flow::function_node<void*, float>, void*, float>();
162de0109beSIlya Mishin conformance::test_inheritance<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>();
16351c0b2f7Stbbdev }
16451c0b2f7Stbbdev
165de0109beSIlya Mishin //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
16651c0b2f7Stbbdev //! \brief \ref requirement
16751c0b2f7Stbbdev TEST_CASE("function_node buffering"){
168de0109beSIlya Mishin conformance::dummy_functor<int> fun;
169de0109beSIlya Mishin conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::rejecting>, input_msg>(oneapi::tbb::flow::unlimited, fun);
170de0109beSIlya Mishin conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::queueing>, input_msg>(oneapi::tbb::flow::unlimited, fun);
17151c0b2f7Stbbdev }
17251c0b2f7Stbbdev
173de0109beSIlya Mishin //! Test node broadcast messages to successors
17451c0b2f7Stbbdev //! \brief \ref requirement
17551c0b2f7Stbbdev TEST_CASE("function_node broadcast"){
176de0109beSIlya Mishin conformance::counting_functor<int> fun(conformance::expected);
177de0109beSIlya Mishin conformance::test_forwarding<oneapi::tbb::flow::function_node<input_msg, int>, input_msg, int>(1, oneapi::tbb::flow::unlimited, fun);
17851c0b2f7Stbbdev }
17951c0b2f7Stbbdev
18051c0b2f7Stbbdev //! Test deduction guides
18151c0b2f7Stbbdev //! \brief \ref interface \ref requirement
18251c0b2f7Stbbdev TEST_CASE("Deduction guides"){
18351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
18451c0b2f7Stbbdev test_deduction_guides();
18551c0b2f7Stbbdev #endif
18651c0b2f7Stbbdev }
18751c0b2f7Stbbdev
18851c0b2f7Stbbdev //! Test priorities work in single-threaded configuration
18951c0b2f7Stbbdev //! \brief \ref requirement
19051c0b2f7Stbbdev TEST_CASE("function_node priority support"){
191de0109beSIlya Mishin conformance::test_priority<oneapi::tbb::flow::function_node<input_msg, int>, input_msg>(oneapi::tbb::flow::unlimited);
19251c0b2f7Stbbdev }
19351c0b2f7Stbbdev
194de0109beSIlya Mishin //! Test function_node has a user-settable concurrency limit. It can be set to one of predefined values.
195de0109beSIlya Mishin //! The user can also provide a value of type std::size_t to limit concurrency.
196de0109beSIlya Mishin //! Test that not more than limited threads works in parallel.
19751c0b2f7Stbbdev //! \brief \ref requirement
19851c0b2f7Stbbdev TEST_CASE("concurrency follows set limits"){
199de0109beSIlya Mishin conformance::test_concurrency<oneapi::tbb::flow::function_node<int, int>>();
20051c0b2f7Stbbdev }
20151c0b2f7Stbbdev
202de0109beSIlya Mishin //! Test node Input class meet the DefaultConstructible and CopyConstructible requirements and Output class meet the CopyConstructible requirements.
20351c0b2f7Stbbdev //! \brief \ref interface \ref requirement
204de0109beSIlya Mishin TEST_CASE("Test function_node Output and Input class") {
205de0109beSIlya Mishin using Body = conformance::copy_counting_object<int>;
206de0109beSIlya Mishin conformance::test_output_input_class<oneapi::tbb::flow::function_node<Body, Body>, Body>();
20751c0b2f7Stbbdev }
208*a088cfa0SKonstantin Boyarinov
209*a088cfa0SKonstantin Boyarinov #if __TBB_CPP17_INVOKE_PRESENT
210*a088cfa0SKonstantin Boyarinov //! Test that function_node uses std::invoke to execute the body
211*a088cfa0SKonstantin Boyarinov //! \brief \ref interface \ref requirement
212*a088cfa0SKonstantin Boyarinov TEST_CASE("Test function_node and std::invoke") {
213*a088cfa0SKonstantin Boyarinov test_fn_invoke();
214*a088cfa0SKonstantin Boyarinov }
215*a088cfa0SKonstantin Boyarinov #endif
216