1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2005-2020 Intel Corporation 3*51c0b2f7Stbbdev 4*51c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 5*51c0b2f7Stbbdev you may not use this file except in compliance with the License. 6*51c0b2f7Stbbdev You may obtain a copy of the License at 7*51c0b2f7Stbbdev 8*51c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 9*51c0b2f7Stbbdev 10*51c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 11*51c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 12*51c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*51c0b2f7Stbbdev See the License for the specific language governing permissions and 14*51c0b2f7Stbbdev limitations under the License. 15*51c0b2f7Stbbdev */ 16*51c0b2f7Stbbdev 17*51c0b2f7Stbbdev #include "common/config.h" 18*51c0b2f7Stbbdev 19*51c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these 20*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually 21*51c0b2f7Stbbdev // released. 22*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1 23*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 24*51c0b2f7Stbbdev 25*51c0b2f7Stbbdev #include "common/test.h" 26*51c0b2f7Stbbdev #include "common/utils.h" 27*51c0b2f7Stbbdev #include "common/utils_assert.h" 28*51c0b2f7Stbbdev #include "common/graph_utils.h" 29*51c0b2f7Stbbdev 30*51c0b2f7Stbbdev 31*51c0b2f7Stbbdev //! \file test_split_node.cpp 32*51c0b2f7Stbbdev //! \brief Test for [flow_graph.split_node] specification 33*51c0b2f7Stbbdev 34*51c0b2f7Stbbdev 35*51c0b2f7Stbbdev #if defined(_MSC_VER) && _MSC_VER < 1600 36*51c0b2f7Stbbdev #pragma warning (disable : 4503) //disabling the "decorated name length exceeded" warning for VS2008 and earlier 37*51c0b2f7Stbbdev #endif 38*51c0b2f7Stbbdev 39*51c0b2f7Stbbdev // 40*51c0b2f7Stbbdev // Tests 41*51c0b2f7Stbbdev // 42*51c0b2f7Stbbdev 43*51c0b2f7Stbbdev const int Count = 300; 44*51c0b2f7Stbbdev const int MaxPorts = 10; 45*51c0b2f7Stbbdev const int MaxNInputs = 5; // max # of input_nodes to register for each split_node input in parallel test 46*51c0b2f7Stbbdev 47*51c0b2f7Stbbdev std::vector<bool> flags; // for checking output 48*51c0b2f7Stbbdev 49*51c0b2f7Stbbdev template<typename T> 50*51c0b2f7Stbbdev class name_of { 51*51c0b2f7Stbbdev public: 52*51c0b2f7Stbbdev static const char* name() { return "Unknown"; } 53*51c0b2f7Stbbdev }; 54*51c0b2f7Stbbdev template<> 55*51c0b2f7Stbbdev class name_of<int> { 56*51c0b2f7Stbbdev public: 57*51c0b2f7Stbbdev static const char* name() { return "int"; } 58*51c0b2f7Stbbdev }; 59*51c0b2f7Stbbdev template<> 60*51c0b2f7Stbbdev class name_of<float> { 61*51c0b2f7Stbbdev public: 62*51c0b2f7Stbbdev static const char* name() { return "float"; } 63*51c0b2f7Stbbdev }; 64*51c0b2f7Stbbdev template<> 65*51c0b2f7Stbbdev class name_of<double> { 66*51c0b2f7Stbbdev public: 67*51c0b2f7Stbbdev static const char* name() { return "double"; } 68*51c0b2f7Stbbdev }; 69*51c0b2f7Stbbdev template<> 70*51c0b2f7Stbbdev class name_of<long> { 71*51c0b2f7Stbbdev public: 72*51c0b2f7Stbbdev static const char* name() { return "long"; } 73*51c0b2f7Stbbdev }; 74*51c0b2f7Stbbdev template<> 75*51c0b2f7Stbbdev class name_of<short> { 76*51c0b2f7Stbbdev public: 77*51c0b2f7Stbbdev static const char* name() { return "short"; } 78*51c0b2f7Stbbdev }; 79*51c0b2f7Stbbdev 80*51c0b2f7Stbbdev // T must be arithmetic, and shouldn't wrap around for reasonable sizes of Count (which is now 150, and maxPorts is 10, 81*51c0b2f7Stbbdev // so the max number generated right now is 1500 or so.) Input will generate a series of TT with value 82*51c0b2f7Stbbdev // (init_val + (i-1)*addend) * my_mult, where i is the i-th invocation of the body. We are attaching addend 83*51c0b2f7Stbbdev // input nodes to a join_port, and each will generate part of the numerical series the port is expecting 84*51c0b2f7Stbbdev // to receive. If there is only one input node, the series order will be maintained; if more than one, 85*51c0b2f7Stbbdev // this is not guaranteed. 86*51c0b2f7Stbbdev 87*51c0b2f7Stbbdev template<int N> 88*51c0b2f7Stbbdev struct tuple_helper { 89*51c0b2f7Stbbdev template<typename TupleType> 90*51c0b2f7Stbbdev static void set_element( TupleType &t, int i) { 91*51c0b2f7Stbbdev std::get<N-1>(t) = (typename std::tuple_element<N-1,TupleType>::type)(i * (N+1)); 92*51c0b2f7Stbbdev tuple_helper<N-1>::set_element(t, i); 93*51c0b2f7Stbbdev } 94*51c0b2f7Stbbdev }; 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev template<> 97*51c0b2f7Stbbdev struct tuple_helper<1> { 98*51c0b2f7Stbbdev template<typename TupleType> 99*51c0b2f7Stbbdev static void set_element(TupleType &t, int i) { 100*51c0b2f7Stbbdev std::get<0>(t) = (typename std::tuple_element<0,TupleType>::type)(i * 2); 101*51c0b2f7Stbbdev } 102*51c0b2f7Stbbdev }; 103*51c0b2f7Stbbdev 104*51c0b2f7Stbbdev // if we start N input_bodys they will all have the addend N, and my_count should be initialized to 0 .. N-1. 105*51c0b2f7Stbbdev // the output tuples should have all the sequence, but the order will in general vary. 106*51c0b2f7Stbbdev template<typename TupleType> 107*51c0b2f7Stbbdev class my_input_body { 108*51c0b2f7Stbbdev typedef TupleType TT; 109*51c0b2f7Stbbdev static const int N = std::tuple_size<TT>::value; 110*51c0b2f7Stbbdev int my_count; 111*51c0b2f7Stbbdev int addend; 112*51c0b2f7Stbbdev public: 113*51c0b2f7Stbbdev my_input_body(int init_val, int addto) : my_count(init_val), addend(addto) { } 114*51c0b2f7Stbbdev TT operator()( tbb::flow_control &fc) { 115*51c0b2f7Stbbdev if(my_count >= Count){ 116*51c0b2f7Stbbdev fc.stop(); 117*51c0b2f7Stbbdev return TT(); 118*51c0b2f7Stbbdev } 119*51c0b2f7Stbbdev TT v; 120*51c0b2f7Stbbdev tuple_helper<N>::set_element(v, my_count); 121*51c0b2f7Stbbdev my_count += addend; 122*51c0b2f7Stbbdev return v; 123*51c0b2f7Stbbdev } 124*51c0b2f7Stbbdev }; 125*51c0b2f7Stbbdev 126*51c0b2f7Stbbdev // allocator for split_node. 127*51c0b2f7Stbbdev 128*51c0b2f7Stbbdev template<int N, typename SType> 129*51c0b2f7Stbbdev class makeSplit { 130*51c0b2f7Stbbdev public: 131*51c0b2f7Stbbdev static SType *create(tbb::flow::graph& g) { 132*51c0b2f7Stbbdev SType *temp = new SType(g); 133*51c0b2f7Stbbdev return temp; 134*51c0b2f7Stbbdev } 135*51c0b2f7Stbbdev static void destroy(SType *p) { delete p; } 136*51c0b2f7Stbbdev }; 137*51c0b2f7Stbbdev 138*51c0b2f7Stbbdev // holder for sink_node pointers for eventual deletion 139*51c0b2f7Stbbdev 140*51c0b2f7Stbbdev static void* all_sink_nodes[MaxPorts]; 141*51c0b2f7Stbbdev 142*51c0b2f7Stbbdev 143*51c0b2f7Stbbdev template<int ELEM, typename SType> 144*51c0b2f7Stbbdev class sink_node_helper { 145*51c0b2f7Stbbdev public: 146*51c0b2f7Stbbdev typedef typename SType::input_type TT; 147*51c0b2f7Stbbdev typedef typename std::tuple_element<ELEM-1,TT>::type IT; 148*51c0b2f7Stbbdev typedef typename tbb::flow::queue_node<IT> my_sink_node_type; 149*51c0b2f7Stbbdev static void print_parallel_remark() { 150*51c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::print_parallel_remark(); 151*51c0b2f7Stbbdev INFO(", " << name_of<IT>::name()); 152*51c0b2f7Stbbdev } 153*51c0b2f7Stbbdev static void print_serial_remark() { 154*51c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::print_serial_remark(); 155*51c0b2f7Stbbdev INFO(", " << name_of<IT>::name()); 156*51c0b2f7Stbbdev } 157*51c0b2f7Stbbdev static void add_sink_nodes(SType &my_split, tbb::flow::graph &g) { 158*51c0b2f7Stbbdev my_sink_node_type *new_node = new my_sink_node_type(g); 159*51c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<ELEM-1>(my_split) , *new_node); 160*51c0b2f7Stbbdev all_sink_nodes[ELEM-1] = (void *)new_node; 161*51c0b2f7Stbbdev sink_node_helper<ELEM-1, SType>::add_sink_nodes(my_split, g); 162*51c0b2f7Stbbdev } 163*51c0b2f7Stbbdev 164*51c0b2f7Stbbdev static void check_sink_values() { 165*51c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[ELEM-1]); 166*51c0b2f7Stbbdev for(int i = 0; i < Count; ++i) { 167*51c0b2f7Stbbdev IT v{}; 168*51c0b2f7Stbbdev CHECK_MESSAGE(dp->try_get(v), ""); 169*51c0b2f7Stbbdev flags[((int)v) / (ELEM+1)] = true; 170*51c0b2f7Stbbdev } 171*51c0b2f7Stbbdev for(int i = 0; i < Count; ++i) { 172*51c0b2f7Stbbdev CHECK_MESSAGE(flags[i], ""); 173*51c0b2f7Stbbdev flags[i] = false; // reset for next test 174*51c0b2f7Stbbdev } 175*51c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::check_sink_values(); 176*51c0b2f7Stbbdev } 177*51c0b2f7Stbbdev static void remove_sink_nodes(SType& my_split) { 178*51c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[ELEM-1]); 179*51c0b2f7Stbbdev tbb::flow::remove_edge( tbb::flow::output_port<ELEM-1>(my_split) , *dp); 180*51c0b2f7Stbbdev delete dp; 181*51c0b2f7Stbbdev sink_node_helper<ELEM-1, SType>::remove_sink_nodes(my_split); 182*51c0b2f7Stbbdev } 183*51c0b2f7Stbbdev }; 184*51c0b2f7Stbbdev 185*51c0b2f7Stbbdev template<typename SType> 186*51c0b2f7Stbbdev class sink_node_helper<1, SType> { 187*51c0b2f7Stbbdev typedef typename SType::input_type TT; 188*51c0b2f7Stbbdev typedef typename std::tuple_element<0,TT>::type IT; 189*51c0b2f7Stbbdev typedef typename tbb::flow::queue_node<IT> my_sink_node_type; 190*51c0b2f7Stbbdev public: 191*51c0b2f7Stbbdev static void print_parallel_remark() { 192*51c0b2f7Stbbdev INFO("Parallel test of split_node< " << name_of<IT>::name()); 193*51c0b2f7Stbbdev } 194*51c0b2f7Stbbdev static void print_serial_remark() { 195*51c0b2f7Stbbdev INFO("Serial test of split_node< " << name_of<IT>::name()); 196*51c0b2f7Stbbdev } 197*51c0b2f7Stbbdev static void add_sink_nodes(SType &my_split, tbb::flow::graph &g) { 198*51c0b2f7Stbbdev my_sink_node_type *new_node = new my_sink_node_type(g); 199*51c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(my_split) , *new_node); 200*51c0b2f7Stbbdev all_sink_nodes[0] = (void *)new_node; 201*51c0b2f7Stbbdev } 202*51c0b2f7Stbbdev static void check_sink_values() { 203*51c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[0]); 204*51c0b2f7Stbbdev for(int i = 0; i < Count; ++i) { 205*51c0b2f7Stbbdev IT v{}; 206*51c0b2f7Stbbdev CHECK_MESSAGE(dp->try_get(v), ""); 207*51c0b2f7Stbbdev flags[((int)v) / 2] = true; 208*51c0b2f7Stbbdev } 209*51c0b2f7Stbbdev for(int i = 0; i < Count; ++i) { 210*51c0b2f7Stbbdev CHECK_MESSAGE(flags[i], ""); 211*51c0b2f7Stbbdev flags[i] = false; // reset for next test 212*51c0b2f7Stbbdev } 213*51c0b2f7Stbbdev } 214*51c0b2f7Stbbdev static void remove_sink_nodes(SType& my_split) { 215*51c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[0]); 216*51c0b2f7Stbbdev tbb::flow::remove_edge( tbb::flow::output_port<0>(my_split) , *dp); 217*51c0b2f7Stbbdev delete dp; 218*51c0b2f7Stbbdev } 219*51c0b2f7Stbbdev }; 220*51c0b2f7Stbbdev 221*51c0b2f7Stbbdev // parallel_test: create input_nodes that feed tuples into the split node 222*51c0b2f7Stbbdev // and queue_nodes that receive the output. 223*51c0b2f7Stbbdev template<typename SType> 224*51c0b2f7Stbbdev class parallel_test { 225*51c0b2f7Stbbdev public: 226*51c0b2f7Stbbdev typedef typename SType::input_type TType; 227*51c0b2f7Stbbdev typedef tbb::flow::input_node<TType> input_type; 228*51c0b2f7Stbbdev static const int N = std::tuple_size<TType>::value; 229*51c0b2f7Stbbdev 230*51c0b2f7Stbbdev static void test() { 231*51c0b2f7Stbbdev input_type* all_input_nodes[MaxNInputs]; 232*51c0b2f7Stbbdev sink_node_helper<N,SType>::print_parallel_remark(); 233*51c0b2f7Stbbdev INFO(" >\n"); 234*51c0b2f7Stbbdev for(int i=0; i < MaxPorts; ++i) { 235*51c0b2f7Stbbdev all_sink_nodes[i] = NULL; 236*51c0b2f7Stbbdev } 237*51c0b2f7Stbbdev // try test for # inputs 1 .. MaxNInputs 238*51c0b2f7Stbbdev for(int nInputs = 1; nInputs <= MaxNInputs; ++nInputs) { 239*51c0b2f7Stbbdev tbb::flow::graph g; 240*51c0b2f7Stbbdev SType* my_split = makeSplit<N,SType>::create(g); 241*51c0b2f7Stbbdev 242*51c0b2f7Stbbdev // add sinks first so when inputs start spitting out values they are there to catch them 243*51c0b2f7Stbbdev sink_node_helper<N, SType>::add_sink_nodes((*my_split), g); 244*51c0b2f7Stbbdev 245*51c0b2f7Stbbdev // now create nInputs input_nodes, each spitting out i, i+nInputs, i+2*nInputs ... 246*51c0b2f7Stbbdev // each element of the tuple is i*(n+1), where n is the tuple element index (1-N) 247*51c0b2f7Stbbdev for(int i = 0; i < nInputs; ++i) { 248*51c0b2f7Stbbdev // create input node 249*51c0b2f7Stbbdev input_type *s = new input_type(g, my_input_body<TType>(i, nInputs) ); 250*51c0b2f7Stbbdev tbb::flow::make_edge(*s, *my_split); 251*51c0b2f7Stbbdev all_input_nodes[i] = s; 252*51c0b2f7Stbbdev s->activate(); 253*51c0b2f7Stbbdev } 254*51c0b2f7Stbbdev 255*51c0b2f7Stbbdev g.wait_for_all(); 256*51c0b2f7Stbbdev 257*51c0b2f7Stbbdev // check that we got Count values in each output queue, and all the index values 258*51c0b2f7Stbbdev // are there. 259*51c0b2f7Stbbdev sink_node_helper<N, SType>::check_sink_values(); 260*51c0b2f7Stbbdev 261*51c0b2f7Stbbdev sink_node_helper<N, SType>::remove_sink_nodes(*my_split); 262*51c0b2f7Stbbdev for(int i = 0; i < nInputs; ++i) { 263*51c0b2f7Stbbdev delete all_input_nodes[i]; 264*51c0b2f7Stbbdev } 265*51c0b2f7Stbbdev makeSplit<N,SType>::destroy(my_split); 266*51c0b2f7Stbbdev } 267*51c0b2f7Stbbdev } 268*51c0b2f7Stbbdev }; 269*51c0b2f7Stbbdev 270*51c0b2f7Stbbdev // 271*51c0b2f7Stbbdev // Single predecessor, single accepting successor at each port 272*51c0b2f7Stbbdev 273*51c0b2f7Stbbdev template<typename SType> 274*51c0b2f7Stbbdev void test_one_serial( SType &my_split, tbb::flow::graph &g) { 275*51c0b2f7Stbbdev typedef typename SType::input_type TType; 276*51c0b2f7Stbbdev static const int TUPLE_SIZE = std::tuple_size<TType>::value; 277*51c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::add_sink_nodes(my_split,g); 278*51c0b2f7Stbbdev typedef TType q3_input_type; 279*51c0b2f7Stbbdev tbb::flow::queue_node< q3_input_type > q3(g); 280*51c0b2f7Stbbdev 281*51c0b2f7Stbbdev tbb::flow::make_edge( q3, my_split ); 282*51c0b2f7Stbbdev 283*51c0b2f7Stbbdev // fill the queue with its value one-at-a-time 284*51c0b2f7Stbbdev flags.clear(); 285*51c0b2f7Stbbdev for (int i = 0; i < Count; ++i ) { 286*51c0b2f7Stbbdev TType v; 287*51c0b2f7Stbbdev tuple_helper<TUPLE_SIZE>::set_element(v, i); 288*51c0b2f7Stbbdev CHECK_MESSAGE(my_split.try_put(v), ""); 289*51c0b2f7Stbbdev flags.push_back(false); 290*51c0b2f7Stbbdev } 291*51c0b2f7Stbbdev 292*51c0b2f7Stbbdev g.wait_for_all(); 293*51c0b2f7Stbbdev 294*51c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE,SType>::check_sink_values(); 295*51c0b2f7Stbbdev 296*51c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::remove_sink_nodes(my_split); 297*51c0b2f7Stbbdev 298*51c0b2f7Stbbdev } 299*51c0b2f7Stbbdev 300*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 301*51c0b2f7Stbbdev void test_follows_and_precedes_api() { 302*51c0b2f7Stbbdev using namespace tbb::flow; 303*51c0b2f7Stbbdev using msg_t = std::tuple<int, float, double>; 304*51c0b2f7Stbbdev 305*51c0b2f7Stbbdev graph g; 306*51c0b2f7Stbbdev 307*51c0b2f7Stbbdev function_node<msg_t, msg_t> f1(g, unlimited, [](msg_t msg) { return msg; } ); 308*51c0b2f7Stbbdev auto f2(f1); 309*51c0b2f7Stbbdev auto f3(f1); 310*51c0b2f7Stbbdev 311*51c0b2f7Stbbdev std::atomic<int> body_calls; 312*51c0b2f7Stbbdev body_calls = 0; 313*51c0b2f7Stbbdev 314*51c0b2f7Stbbdev function_node<int, int> f4(g, unlimited, [&](int val) { ++body_calls; return val; } ); 315*51c0b2f7Stbbdev function_node<float, float> f5(g, unlimited, [&](float val) { ++body_calls; return val; } ); 316*51c0b2f7Stbbdev function_node<double, double> f6(g, unlimited, [&](double val) { ++body_calls; return val; } ); 317*51c0b2f7Stbbdev 318*51c0b2f7Stbbdev split_node<msg_t> following_node(follows(f1, f2, f3)); 319*51c0b2f7Stbbdev make_edge(output_port<0>(following_node), f4); 320*51c0b2f7Stbbdev make_edge(output_port<1>(following_node), f5); 321*51c0b2f7Stbbdev make_edge(output_port<2>(following_node), f6); 322*51c0b2f7Stbbdev 323*51c0b2f7Stbbdev split_node<msg_t> preceding_node(precedes(f4, f5, f6)); 324*51c0b2f7Stbbdev make_edge(f1, preceding_node); 325*51c0b2f7Stbbdev make_edge(f2, preceding_node); 326*51c0b2f7Stbbdev make_edge(f3, preceding_node); 327*51c0b2f7Stbbdev 328*51c0b2f7Stbbdev msg_t msg(1, 2.2f, 3.3); 329*51c0b2f7Stbbdev f1.try_put(msg); 330*51c0b2f7Stbbdev f2.try_put(msg); 331*51c0b2f7Stbbdev f3.try_put(msg); 332*51c0b2f7Stbbdev 333*51c0b2f7Stbbdev g.wait_for_all(); 334*51c0b2f7Stbbdev 335*51c0b2f7Stbbdev // <number of try puts> * <number of splits by a input node> * <number of input nodes> 336*51c0b2f7Stbbdev CHECK_MESSAGE( ((body_calls == 3*3*2)), "Not exact edge quantity was made"); 337*51c0b2f7Stbbdev } 338*51c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 339*51c0b2f7Stbbdev 340*51c0b2f7Stbbdev template<typename SType> 341*51c0b2f7Stbbdev class serial_test { 342*51c0b2f7Stbbdev typedef typename SType::input_type TType; 343*51c0b2f7Stbbdev static const int TUPLE_SIZE = std::tuple_size<TType>::value; 344*51c0b2f7Stbbdev static const int ELEMS = 3; 345*51c0b2f7Stbbdev public: 346*51c0b2f7Stbbdev static void test() { 347*51c0b2f7Stbbdev tbb::flow::graph g; 348*51c0b2f7Stbbdev flags.reserve(Count); 349*51c0b2f7Stbbdev SType* my_split = makeSplit<TUPLE_SIZE,SType>::create(g); 350*51c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::print_serial_remark(); INFO(" >\n"); 351*51c0b2f7Stbbdev 352*51c0b2f7Stbbdev test_output_ports_return_ref(*my_split); 353*51c0b2f7Stbbdev 354*51c0b2f7Stbbdev test_one_serial<SType>(*my_split, g); 355*51c0b2f7Stbbdev // build the vector with copy construction from the used split node. 356*51c0b2f7Stbbdev std::vector<SType>split_vector(ELEMS, *my_split); 357*51c0b2f7Stbbdev // destroy the tired old split_node in case we're accidentally reusing pieces of it. 358*51c0b2f7Stbbdev makeSplit<TUPLE_SIZE,SType>::destroy(my_split); 359*51c0b2f7Stbbdev 360*51c0b2f7Stbbdev 361*51c0b2f7Stbbdev for(int e = 0; e < ELEMS; ++e) { // exercise each of the vector elements 362*51c0b2f7Stbbdev test_one_serial<SType>(split_vector[e], g); 363*51c0b2f7Stbbdev } 364*51c0b2f7Stbbdev } 365*51c0b2f7Stbbdev 366*51c0b2f7Stbbdev }; // serial_test 367*51c0b2f7Stbbdev 368*51c0b2f7Stbbdev template< 369*51c0b2f7Stbbdev template<typename> class TestType, // serial_test or parallel_test 370*51c0b2f7Stbbdev typename TupleType > // type of the input of the split 371*51c0b2f7Stbbdev struct generate_test { 372*51c0b2f7Stbbdev typedef tbb::flow::split_node<TupleType> split_node_type; 373*51c0b2f7Stbbdev static void do_test() { 374*51c0b2f7Stbbdev TestType<split_node_type>::test(); 375*51c0b2f7Stbbdev } 376*51c0b2f7Stbbdev }; // generate_test 377*51c0b2f7Stbbdev 378*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 379*51c0b2f7Stbbdev 380*51c0b2f7Stbbdev void test_deduction_guides() { 381*51c0b2f7Stbbdev using namespace tbb::flow; 382*51c0b2f7Stbbdev using tuple_type = std::tuple<int, int>; 383*51c0b2f7Stbbdev 384*51c0b2f7Stbbdev graph g; 385*51c0b2f7Stbbdev split_node<tuple_type> s0(g); 386*51c0b2f7Stbbdev 387*51c0b2f7Stbbdev split_node s1(s0); 388*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s1), split_node<tuple_type>>); 389*51c0b2f7Stbbdev 390*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 391*51c0b2f7Stbbdev broadcast_node<tuple_type> b1(g), b2(g); 392*51c0b2f7Stbbdev broadcast_node<int> b3(g), b4(g); 393*51c0b2f7Stbbdev 394*51c0b2f7Stbbdev split_node s2(follows(b1, b2)); 395*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s2), split_node<tuple_type>>); 396*51c0b2f7Stbbdev 397*51c0b2f7Stbbdev split_node s3(precedes(b3, b4)); 398*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s3), split_node<tuple_type>>); 399*51c0b2f7Stbbdev #endif 400*51c0b2f7Stbbdev } 401*51c0b2f7Stbbdev 402*51c0b2f7Stbbdev #endif 403*51c0b2f7Stbbdev 404*51c0b2f7Stbbdev //! Test output ports and message passing with different input tuples 405*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing 406*51c0b2f7Stbbdev TEST_CASE("Tuple tests"){ 407*51c0b2f7Stbbdev for (int p = 0; p < 2; ++p) { 408*51c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double> >::do_test(); 409*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 4 410*51c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, int, long> >::do_test(); 411*51c0b2f7Stbbdev #endif 412*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 6 413*51c0b2f7Stbbdev generate_test<serial_test, std::tuple<double, double, int, long, int, short> >::do_test(); 414*51c0b2f7Stbbdev #endif 415*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 8 416*51c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, double, double, float, int, float, long> >::do_test(); 417*51c0b2f7Stbbdev #endif 418*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 10 419*51c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, int, double, double, float, long, int, float, long> >::do_test(); 420*51c0b2f7Stbbdev #endif 421*51c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, double> >::do_test(); 422*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 3 423*51c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, int, long> >::do_test(); 424*51c0b2f7Stbbdev #endif 425*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 5 426*51c0b2f7Stbbdev generate_test<parallel_test, std::tuple<double, double, int, int, short> >::do_test(); 427*51c0b2f7Stbbdev #endif 428*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 7 429*51c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, int, double, float, long, float, long> >::do_test(); 430*51c0b2f7Stbbdev #endif 431*51c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 9 432*51c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, double, int, double, double, long, int, float, long> >::do_test(); 433*51c0b2f7Stbbdev #endif 434*51c0b2f7Stbbdev } 435*51c0b2f7Stbbdev } 436*51c0b2f7Stbbdev 437*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 438*51c0b2f7Stbbdev //! Test decution guides 439*51c0b2f7Stbbdev //! \brief \ref requirement 440*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){ 441*51c0b2f7Stbbdev test_follows_and_precedes_api(); 442*51c0b2f7Stbbdev } 443*51c0b2f7Stbbdev #endif 444*51c0b2f7Stbbdev 445*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 446*51c0b2f7Stbbdev //! Test decution guides 447*51c0b2f7Stbbdev //! \brief \ref requirement 448*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 449*51c0b2f7Stbbdev test_deduction_guides(); 450*51c0b2f7Stbbdev } 451*51c0b2f7Stbbdev #endif 452*51c0b2f7Stbbdev 453