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