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 //! \file conformance_composite_node.cpp 24 //! \brief Test for [flow_graph.composite_node] specification 25 26 class adder : public oneapi::tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int>> { 27 oneapi::tbb::flow::join_node<std::tuple<int,int>, oneapi::tbb::flow::queueing> j; 28 oneapi::tbb::flow::function_node<std::tuple<int,int>, int> f; 29 oneapi::tbb::flow::queue_node<int> qn; 30 using base_type = oneapi::tbb::flow::composite_node<std::tuple<int,int>, std::tuple<int>>; 31 32 struct f_body { 33 int operator()(const std::tuple<int,int> &t) { 34 int sum = std::get<0>(t) + std::get<1>(t); 35 return sum; 36 } 37 }; 38 39 public: 40 adder(oneapi::tbb::flow::graph &g) : base_type(g), j(g), f(g, oneapi::tbb::flow::unlimited, f_body()), qn(g) { 41 make_edge(j, f); 42 make_edge(f, qn); 43 44 base_type::input_ports_type input_tuple(oneapi::tbb::flow::input_port<0>(j), oneapi::tbb::flow::input_port<1>(j)); 45 base_type::output_ports_type output_tuple(qn); 46 base_type::set_external_ports(input_tuple, output_tuple); 47 } 48 }; 49 50 template<int N, typename T1, typename T2> 51 struct compare { 52 static void compare_refs(T1 tuple1, T2 tuple2) { 53 CHECK_MESSAGE(( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly"); 54 compare<N-1, T1, T2>::compare_refs(tuple1, tuple2); 55 } 56 }; 57 58 template<typename T1, typename T2> 59 struct compare<1, T1, T2> { 60 static void compare_refs(T1 tuple1, T2 tuple2) { 61 CHECK_MESSAGE((&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set"); 62 } 63 }; 64 65 //! Test inheritance relations 66 //! \brief \ref interface 67 TEST_CASE("composite_node superclasses"){ 68 CHECK_MESSAGE((std::is_base_of<oneapi::tbb::flow::graph_node, adder>::value), "composite_node should be derived from graph_node"); 69 } 70 71 //! Test composite_node ports 72 //! \brief \ref interface \ref requirement 73 TEST_CASE("composite_node ports"){ 74 oneapi::tbb::flow::graph g; 75 76 using InputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, int, int, int, int, 77 int, int, int, int, int, int, int, int>; 78 79 using OutputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, oneapi::tbb::flow::tagged_msg<size_t, int, float>, 80 int, int, int, int, int, int, int, int, int, int, int, int>; 81 82 using EmptyTupleType= std::tuple<>; 83 84 using input_output_type = oneapi::tbb::flow::composite_node<InputTupleType, OutputTupleType>; 85 using input_only_type = oneapi::tbb::flow::composite_node<InputTupleType, EmptyTupleType>; 86 using output_only_type = oneapi::tbb::flow::composite_node<EmptyTupleType, OutputTupleType>; 87 88 const size_t NUM_INPUTS = std::tuple_size<InputTupleType>::value; 89 const size_t NUM_OUTPUTS = std::tuple_size<OutputTupleType>::value; 90 91 using body = conformance::dummy_functor<int>; 92 93 //node types 94 oneapi::tbb::flow::continue_node<tbb::flow::continue_msg> ct(g, body()); 95 oneapi::tbb::flow::split_node< std::tuple<int, int> > s(g); 96 oneapi::tbb::flow::input_node<int> src(g, body()); 97 oneapi::tbb::flow::function_node<int, int> fxn(g, oneapi::tbb::flow::unlimited, body()); 98 oneapi::tbb::flow::multifunction_node<int, std::tuple<int, int> > m_fxn(g, oneapi::tbb::flow::unlimited, body()); 99 oneapi::tbb::flow::broadcast_node<int> bc(g); 100 oneapi::tbb::flow::limiter_node<int> lim(g, 2); 101 oneapi::tbb::flow::indexer_node<int, float> ind(g); 102 oneapi::tbb::flow::join_node< std::tuple< int, int >, oneapi::tbb::flow::queueing > j(g); 103 oneapi::tbb::flow::queue_node<int> q(g); 104 oneapi::tbb::flow::buffer_node<int> bf(g); 105 oneapi::tbb::flow::priority_queue_node<int> pq(g); 106 oneapi::tbb::flow::write_once_node<int> wo(g); 107 oneapi::tbb::flow::overwrite_node<int> ovw(g); 108 oneapi::tbb::flow::sequencer_node<int> seq(g, conformance::sequencer_functor<int>()); 109 110 auto input_tuple = std::tie(ct, s, m_fxn, fxn, bc, oneapi::tbb::flow::input_port<0>(j), lim, q, oneapi::tbb::flow::input_port<0>(ind), 111 pq, ovw, wo, bf, seq); 112 auto output_tuple = std::tie(ct,j, ind, fxn, src, bc, oneapi::tbb::flow::output_port<0>(s), lim, oneapi::tbb::flow::output_port<0>(m_fxn), 113 q, pq, ovw, wo, bf, seq); 114 115 //composite_node with both input_ports and output_ports 116 input_output_type a_node(g); 117 a_node.set_external_ports(input_tuple, output_tuple); 118 119 a_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 120 a_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 121 122 auto a_node_input_ports_ptr = a_node.input_ports(); 123 compare<NUM_INPUTS-1, decltype(a_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(a_node_input_ports_ptr, input_tuple); 124 CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(a_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 125 126 auto a_node_output_ports_ptr = a_node.output_ports(); 127 compare<NUM_OUTPUTS-1, decltype(a_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(a_node_output_ports_ptr, output_tuple); 128 CHECK_MESSAGE((NUM_OUTPUTS == std::tuple_size<decltype(a_node_output_ports_ptr)>::value), "not all declared output ports were bound to nodes"); 129 130 //composite_node with only input_ports 131 input_only_type b_node(g); 132 b_node.set_external_ports(input_tuple); 133 134 b_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 135 b_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 136 137 auto b_node_input_ports_ptr = b_node.input_ports(); 138 compare<NUM_INPUTS-1, decltype(b_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(b_node_input_ports_ptr, input_tuple); 139 CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(b_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 140 141 //composite_node with only output_ports 142 output_only_type c_node(g); 143 c_node.set_external_ports(output_tuple); 144 145 // Reset is not suppose to do anything. Check that it can be called. 146 g.reset(); 147 148 c_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 149 150 c_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 151 152 auto c_node_output_ports_ptr = c_node.output_ports(); 153 compare<NUM_OUTPUTS-1, decltype(c_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(c_node_output_ports_ptr, output_tuple); 154 CHECK_MESSAGE(NUM_OUTPUTS == std::tuple_size<decltype(c_node_output_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 155 } 156 157 //! Test composite_node construction and message passing 158 //! \brief \ref interface \ref requirement 159 TEST_CASE("composite_node construction and message test"){ 160 using namespace oneapi::tbb::flow; 161 graph g; 162 split_node<std::tuple<int, int, int, int>> s(g); 163 adder a0(g); 164 adder a1(g); 165 adder a2(g); 166 167 make_edge(output_port<0>(s), input_port<0>(a0)); 168 make_edge(output_port<1>(s), input_port<1>(a0)); 169 170 make_edge(output_port<0>(a0),input_port<0>(a1)); 171 make_edge(output_port<2>(s), input_port<1>(a1)); 172 173 make_edge(output_port<0>(a1), input_port<0>(a2)); 174 make_edge(output_port<3>(s), input_port<1>(a2)); 175 176 s.try_put(std::make_tuple(1,3,5,7)); 177 g.wait_for_all(); 178 179 int tmp = -1; 180 CHECK_MESSAGE((output_port<0>(a2).try_get(tmp) == true), "Composite node should produce a value"); 181 CHECK_MESSAGE((tmp == 1+3+5+7), "Composite node should produce correct sum"); 182 } 183