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 #include "conformance_flowgraph.h"
22 
23 using input_msg = conformance::message</*default_ctor*/true, /*copy_ctor*/true, /*copy_assign*/false>;
24 using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/true, /*copy_assign*/false>;
25 
26 //! \file conformance_function_node.cpp
27 //! \brief Test for [flow_graph.function_node] specification
28 
29 /*
30     Test node deduction guides
31 */
32 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
33 
34 int function_body_f(const int&) { return 1; }
35 
36 template <typename Body>
37 void test_deduction_guides_common(Body body) {
38     using namespace tbb::flow;
39     graph g;
40 
41     function_node f1(g, unlimited, body);
42     static_assert(std::is_same_v<decltype(f1), function_node<int, int>>);
43 
44     function_node f2(g, unlimited, body, rejecting());
45     static_assert(std::is_same_v<decltype(f2), function_node<int, int, rejecting>>);
46 
47     function_node f3(g, unlimited, body, node_priority_t(5));
48     static_assert(std::is_same_v<decltype(f3), function_node<int, int>>);
49 
50     function_node f4(g, unlimited, body, rejecting(), node_priority_t(5));
51     static_assert(std::is_same_v<decltype(f4), function_node<int, int, rejecting>>);
52 
53 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
54     function_node f5(follows(f2), unlimited, body);
55     static_assert(std::is_same_v<decltype(f5), function_node<int, int>>);
56 
57     function_node f6(follows(f5), unlimited, body, rejecting());
58     static_assert(std::is_same_v<decltype(f6), function_node<int, int, rejecting>>);
59 
60     function_node f7(follows(f6), unlimited, body, node_priority_t(5));
61     static_assert(std::is_same_v<decltype(f7), function_node<int, int>>);
62 
63     function_node f8(follows(f7), unlimited, body, rejecting(), node_priority_t(5));
64     static_assert(std::is_same_v<decltype(f8), function_node<int, int, rejecting>>);
65 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
66 
67     function_node f9(f1);
68     static_assert(std::is_same_v<decltype(f9), function_node<int, int>>);
69 }
70 
71 void test_deduction_guides() {
72     test_deduction_guides_common([](const int&)->int { return 1; });
73     test_deduction_guides_common([](const int&) mutable ->int { return 1; });
74     test_deduction_guides_common(function_body_f);
75 }
76 
77 #endif
78 
79 //! Test calling function body
80 //! \brief \ref interface \ref requirement
81 TEST_CASE("Test function_node body") {
82     conformance::test_body_exec<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>(oneapi::tbb::flow::unlimited);
83 }
84 
85 //! Test function_node constructors
86 //! \brief \ref requirement
87 TEST_CASE("function_node constructors"){
88     using namespace oneapi::tbb::flow;
89     graph g;
90 
91     conformance::counting_functor<int> fun;
92 
93     function_node<int, int> fn1(g, unlimited, fun);
94     function_node<int, int> fn2(g, unlimited, fun, oneapi::tbb::flow::node_priority_t(1));
95 
96     function_node<int, int, lightweight> lw_node1(g, serial, fun, lightweight());
97     function_node<int, int, lightweight> lw_node2(g, serial, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1));
98 }
99 
100 //! 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.
101 //! The predecessors and successors of src are not copied.
102 //! \brief \ref requirement
103 TEST_CASE("function_node copy constructor"){
104     conformance::test_copy_ctor<oneapi::tbb::flow::function_node<int, int>>();
105 }
106 
107 //! Test node reject the incoming message if the concurrency limit achieved.
108 //! \brief \ref interface
109 TEST_CASE("function_node with rejecting policy"){
110     conformance::test_rejecting<oneapi::tbb::flow::function_node<int, int, oneapi::tbb::flow::rejecting>>();
111 }
112 
113 //! Test body copying and copy_body logic
114 //! Test the body object passed to a node is copied
115 //! \brief \ref interface
116 TEST_CASE("function_node and body copying"){
117     conformance::test_copy_body_function<oneapi::tbb::flow::function_node<int, int>, conformance::copy_counting_object<int>>(oneapi::tbb::flow::unlimited);
118 }
119 
120 //! Test function_node is a graph_node, receiver<Input>, and sender<Output>
121 //! \brief \ref interface
122 TEST_CASE("function_node superclasses"){
123     conformance::test_inheritance<oneapi::tbb::flow::function_node<int, int>, int, int>();
124     conformance::test_inheritance<oneapi::tbb::flow::function_node<void*, float>, void*, float>();
125     conformance::test_inheritance<oneapi::tbb::flow::function_node<input_msg, output_msg>, input_msg, output_msg>();
126 }
127 
128 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed.
129 //! \brief \ref requirement
130 TEST_CASE("function_node buffering"){
131     conformance::dummy_functor<int> fun;
132     conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::rejecting>, input_msg>(oneapi::tbb::flow::unlimited, fun);
133     conformance::test_buffering<oneapi::tbb::flow::function_node<input_msg, int, oneapi::tbb::flow::queueing>, input_msg>(oneapi::tbb::flow::unlimited, fun);
134 }
135 
136 //! Test node broadcast messages to successors
137 //! \brief \ref requirement
138 TEST_CASE("function_node broadcast"){
139     conformance::counting_functor<int> fun(conformance::expected);
140     conformance::test_forwarding<oneapi::tbb::flow::function_node<input_msg, int>, input_msg, int>(1, oneapi::tbb::flow::unlimited, fun);
141 }
142 
143 //! Test deduction guides
144 //! \brief \ref interface \ref requirement
145 TEST_CASE("Deduction guides"){
146 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
147     test_deduction_guides();
148 #endif
149 }
150 
151 //! Test priorities work in single-threaded configuration
152 //! \brief \ref requirement
153 TEST_CASE("function_node priority support"){
154     conformance::test_priority<oneapi::tbb::flow::function_node<input_msg, int>, input_msg>(oneapi::tbb::flow::unlimited);
155 }
156 
157 //! Test function_node has a user-settable concurrency limit. It can be set to one of predefined values.
158 //! The user can also provide a value of type std::size_t to limit concurrency.
159 //! Test that not more than limited threads works in parallel.
160 //! \brief \ref requirement
161 TEST_CASE("concurrency follows set limits"){
162     conformance::test_concurrency<oneapi::tbb::flow::function_node<int, int>>();
163 }
164 
165 //! Test node Input class meet the DefaultConstructible and CopyConstructible requirements and Output class meet the CopyConstructible requirements.
166 //! \brief \ref interface \ref requirement
167 TEST_CASE("Test function_node Output and Input class") {
168     using Body = conformance::copy_counting_object<int>;
169     conformance::test_output_input_class<oneapi::tbb::flow::function_node<Body, Body>, Body>();
170 }
171