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