1 /* 2 Copyright (c) 2005-2022 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 "common/config.h" 22 23 #include "tbb/flow_graph.h" 24 25 #include "common/test.h" 26 #include "common/utils.h" 27 #include "common/utils_assert.h" 28 #include "common/test_follows_and_precedes_api.h" 29 30 31 //! \file test_indexer_node.cpp 32 //! \brief Test for [flow_graph.indexer_node] specification 33 34 35 #if defined(_MSC_VER) && _MSC_VER < 1600 36 #pragma warning (disable : 4503) //disabling the "decorated name length exceeded" warning for VS2008 and earlier 37 #endif 38 39 const int Count = 150; 40 const int MaxPorts = 10; 41 const int MaxNInputs = 5; // max # of input_nodes to register for each indexer_node input in parallel test 42 bool outputCheck[MaxPorts][Count]; // for checking output 43 44 void 45 check_outputCheck( int nUsed, int maxCnt) { 46 for(int i=0; i < nUsed; ++i) { 47 for( int j = 0; j < maxCnt; ++j) { 48 CHECK_MESSAGE(outputCheck[i][j], ""); 49 } 50 } 51 } 52 53 void 54 reset_outputCheck( int nUsed, int maxCnt) { 55 for(int i=0; i < nUsed; ++i) { 56 for( int j = 0; j < maxCnt; ++j) { 57 outputCheck[i][j] = false; 58 } 59 } 60 } 61 62 class test_class { 63 public: 64 test_class() { my_val = 0; } 65 test_class(int i) { my_val = i; } 66 operator int() { return my_val; } 67 private: 68 int my_val; 69 }; 70 71 template<typename T> 72 class name_of { 73 public: 74 static const char* name() { return "Unknown"; } 75 }; 76 template<> 77 class name_of<int> { 78 public: 79 static const char* name() { return "int"; } 80 }; 81 template<> 82 class name_of<float> { 83 public: 84 static const char* name() { return "float"; } 85 }; 86 template<> 87 class name_of<double> { 88 public: 89 static const char* name() { return "double"; } 90 }; 91 template<> 92 class name_of<long> { 93 public: 94 static const char* name() { return "long"; } 95 }; 96 template<> 97 class name_of<short> { 98 public: 99 static const char* name() { return "short"; } 100 }; 101 template<> 102 class name_of<test_class> { 103 public: 104 static const char* name() { return "test_class"; } 105 }; 106 107 // TT must be arithmetic, and shouldn't wrap around for reasonable sizes of Count (which is now 150, and maxPorts is 10, 108 // so the max number generated right now is 1500 or so.) Input will generate a series of TT with value 109 // (init_val + (i-1)*addend) * my_mult, where i is the i-th invocation of the body. We are attaching addend 110 // input nodes to a indexer_port, and each will generate part of the numerical series the port is expecting 111 // to receive. If there is only one input node, the series order will be maintained; if more than one, 112 // this is not guaranteed. 113 // The manual specifies bodies can be assigned, so we can't hide the operator=. 114 template<typename TT> 115 class my_input_body { 116 TT my_mult; 117 int my_count; 118 int addend; 119 public: 120 my_input_body(TT multiplier, int init_val, int addto) : my_mult(multiplier), my_count(init_val), addend(addto) { } 121 TT operator()( tbb::flow_control& fc) { 122 int lc = my_count; 123 TT ret = my_mult * (TT)my_count; 124 my_count += addend; 125 if ( lc < Count){ 126 return ret; 127 }else{ 128 fc.stop(); 129 return TT(); 130 } 131 } 132 }; 133 134 // allocator for indexer_node. 135 136 template<typename IType> 137 class makeIndexer { 138 public: 139 static IType *create() { 140 IType *temp = new IType(); 141 return temp; 142 } 143 static void destroy(IType *p) { delete p; } 144 }; 145 146 template<int ELEM, typename INT> 147 struct getval_helper { 148 149 typedef typename INT::output_type OT; 150 typedef typename std::tuple_element<ELEM-1, typename INT::tuple_types>::type stored_type; 151 152 static int get_integer_val(OT const &o) { 153 stored_type res = tbb::flow::cast_to<stored_type>(o); 154 return (int)res; 155 } 156 }; 157 158 // holder for input_node pointers for eventual deletion 159 160 static void* all_input_nodes[MaxPorts][MaxNInputs]; 161 162 template<int ELEM, typename INT> 163 class input_node_helper { 164 public: 165 typedef INT indexer_node_type; 166 typedef typename indexer_node_type::output_type TT; 167 typedef typename std::tuple_element<ELEM-1,typename INT::tuple_types>::type IT; 168 typedef typename tbb::flow::input_node<IT> my_input_node_type; 169 static void print_remark() { 170 input_node_helper<ELEM-1,INT>::print_remark(); 171 INFO(", " << name_of<IT>::name()); 172 } 173 static void add_input_nodes(indexer_node_type &my_indexer, tbb::flow::graph &g, int nInputs) { 174 for(int i=0; i < nInputs; ++i) { 175 my_input_node_type *new_node = new my_input_node_type(g, my_input_body<IT>((IT)(ELEM+1), i, nInputs)); 176 tbb::flow::make_edge(*new_node, tbb::flow::input_port<ELEM-1>(my_indexer)); 177 178 all_input_nodes[ELEM-1][i] = (void *)new_node; 179 new_node->activate(); 180 } 181 182 // add the next input_node 183 input_node_helper<ELEM-1, INT>::add_input_nodes(my_indexer, g, nInputs); 184 } 185 static void check_value(TT &v) { 186 if(v.tag() == ELEM-1) { 187 int ival = getval_helper<ELEM,INT>::get_integer_val(v); 188 CHECK_MESSAGE(!(ival%(ELEM+1)), ""); 189 ival /= (ELEM+1); 190 CHECK_MESSAGE(!outputCheck[ELEM-1][ival], ""); 191 outputCheck[ELEM-1][ival] = true; 192 } 193 else { 194 input_node_helper<ELEM-1,INT>::check_value(v); 195 } 196 } 197 198 static void remove_input_nodes(indexer_node_type& my_indexer, int nInputs) { 199 for(int i=0; i< nInputs; ++i) { 200 my_input_node_type *dp = reinterpret_cast<my_input_node_type *>(all_input_nodes[ELEM-1][i]); 201 tbb::flow::remove_edge(*dp, tbb::flow::input_port<ELEM-1>(my_indexer)); 202 delete dp; 203 } 204 input_node_helper<ELEM-1, INT>::remove_input_nodes(my_indexer, nInputs); 205 } 206 }; 207 208 template<typename INT> 209 class input_node_helper<1, INT> { 210 typedef INT indexer_node_type; 211 typedef typename indexer_node_type::output_type TT; 212 213 typedef typename std::tuple_element<0, typename INT::tuple_types>::type IT; 214 typedef typename tbb::flow::input_node<IT> my_input_node_type; 215 public: 216 static void print_remark() { 217 INFO("Parallel test of indexer_node< " << name_of<IT>::name()); 218 } 219 static void add_input_nodes(indexer_node_type &my_indexer, tbb::flow::graph &g, int nInputs) { 220 for(int i=0; i < nInputs; ++i) { 221 my_input_node_type *new_node = new my_input_node_type(g, my_input_body<IT>((IT)2, i, nInputs)); 222 tbb::flow::make_edge(*new_node, tbb::flow::input_port<0>(my_indexer)); 223 all_input_nodes[0][i] = (void *)new_node; 224 new_node->activate(); 225 } 226 } 227 static void check_value(TT &v) { 228 int ival = getval_helper<1,INT>::get_integer_val(v); 229 CHECK_MESSAGE(!(ival%2), ""); 230 ival /= 2; 231 CHECK_MESSAGE(!outputCheck[0][ival], ""); 232 outputCheck[0][ival] = true; 233 } 234 static void remove_input_nodes(indexer_node_type& my_indexer, int nInputs) { 235 for(int i=0; i < nInputs; ++i) { 236 my_input_node_type *dp = reinterpret_cast<my_input_node_type *>(all_input_nodes[0][i]); 237 tbb::flow::remove_edge(*dp, tbb::flow::input_port<0>(my_indexer)); 238 delete dp; 239 } 240 } 241 }; 242 243 template<typename IType> 244 class parallel_test { 245 public: 246 typedef typename IType::output_type TType; 247 typedef typename IType::tuple_types union_types; 248 static const int SIZE = std::tuple_size<union_types>::value; 249 static void test() { 250 TType v; 251 input_node_helper<SIZE,IType>::print_remark(); 252 INFO(" >\n"); 253 for(int i=0; i < MaxPorts; ++i) { 254 for(int j=0; j < MaxNInputs; ++j) { 255 all_input_nodes[i][j] = nullptr; 256 } 257 } 258 for(int nInputs = 1; nInputs <= MaxNInputs; ++nInputs) { 259 tbb::flow::graph g; 260 IType* my_indexer_ptr = new IType(g); //makeIndexer<IType>::create(); 261 IType my_indexer = *my_indexer_ptr; 262 tbb::flow::queue_node<TType> outq1(g); 263 tbb::flow::queue_node<TType> outq2(g); 264 265 tbb::flow::make_edge(my_indexer, outq1); 266 tbb::flow::make_edge(my_indexer, outq2); 267 268 input_node_helper<SIZE, IType>::add_input_nodes(my_indexer, g, nInputs); 269 270 g.wait_for_all(); 271 makeIndexer<IType>::destroy(my_indexer_ptr); 272 273 reset_outputCheck(SIZE, Count); 274 for(int i=0; i < Count*SIZE; ++i) { 275 CHECK_MESSAGE(outq1.try_get(v), ""); 276 input_node_helper<SIZE, IType>::check_value(v); 277 } 278 279 check_outputCheck(SIZE, Count); 280 reset_outputCheck(SIZE, Count); 281 282 for(int i=0; i < Count*SIZE; i++) { 283 CHECK_MESSAGE(outq2.try_get(v), ""); 284 input_node_helper<SIZE, IType>::check_value(v); 285 } 286 check_outputCheck(SIZE, Count); 287 288 CHECK_MESSAGE(!outq1.try_get(v), ""); 289 CHECK_MESSAGE(!outq2.try_get(v), ""); 290 291 input_node_helper<SIZE, IType>::remove_input_nodes(my_indexer, nInputs); 292 tbb::flow::remove_edge(my_indexer, outq1); 293 tbb::flow::remove_edge(my_indexer, outq2); 294 } 295 } 296 }; 297 298 std::vector<int> last_index_seen; 299 300 template<int ELEM, typename IType> 301 class serial_queue_helper { 302 public: 303 typedef typename IType::output_type OT; 304 typedef typename IType::tuple_types TT; 305 typedef typename std::tuple_element<ELEM-1,TT>::type IT; 306 static void print_remark() { 307 serial_queue_helper<ELEM-1,IType>::print_remark(); 308 INFO("," << name_of<IT>::name()); 309 } 310 static void fill_one_queue(int maxVal, IType &my_indexer) { 311 // fill queue to "left" of me 312 serial_queue_helper<ELEM-1,IType>::fill_one_queue(maxVal,my_indexer); 313 for(int i = 0; i < maxVal; ++i) { 314 CHECK_MESSAGE(tbb::flow::input_port<ELEM-1>(my_indexer).try_put((IT)(i*(ELEM+1))), ""); 315 } 316 } 317 static void put_one_queue_val(int myVal, IType &my_indexer) { 318 // put this val to my "left". 319 serial_queue_helper<ELEM-1,IType>::put_one_queue_val(myVal, my_indexer); 320 CHECK_MESSAGE(tbb::flow::input_port<ELEM-1>(my_indexer).try_put((IT)(myVal*(ELEM+1))), ""); 321 } 322 static void check_queue_value(OT &v) { 323 if(ELEM - 1 == v.tag()) { 324 // this assumes each or node input is queueing. 325 int rval = getval_helper<ELEM,IType>::get_integer_val(v); 326 CHECK_MESSAGE( rval == (last_index_seen[ELEM-1]+1)*(ELEM+1), ""); 327 last_index_seen[ELEM-1] = rval / (ELEM+1); 328 } 329 else { 330 serial_queue_helper<ELEM-1,IType>::check_queue_value(v); 331 } 332 } 333 }; 334 335 template<typename IType> 336 class serial_queue_helper<1, IType> { 337 public: 338 typedef typename IType::output_type OT; 339 typedef typename IType::tuple_types TT; 340 typedef typename std::tuple_element<0,TT>::type IT; 341 static void print_remark() { 342 INFO("Serial test of indexer_node< " << name_of<IT>::name()); 343 } 344 static void fill_one_queue(int maxVal, IType &my_indexer) { 345 for(int i = 0; i < maxVal; ++i) { 346 CHECK_MESSAGE(tbb::flow::input_port<0>(my_indexer).try_put((IT)(i*2)), ""); 347 } 348 } 349 static void put_one_queue_val(int myVal, IType &my_indexer) { 350 CHECK_MESSAGE(tbb::flow::input_port<0>(my_indexer).try_put((IT)(myVal*2)), ""); 351 } 352 static void check_queue_value(OT &v) { 353 CHECK_MESSAGE(v.tag() == 0, ""); // won't get here unless true 354 int rval = getval_helper<1,IType>::get_integer_val(v); 355 CHECK_MESSAGE( rval == (last_index_seen[0]+1)*2, ""); 356 last_index_seen[0] = rval / 2; 357 } 358 }; 359 360 template<typename IType, typename TType, int SIZE> 361 void test_one_serial( IType &my_indexer, tbb::flow::graph &g) { 362 last_index_seen.clear(); 363 for(int ii=0; ii < SIZE; ++ii) last_index_seen.push_back(-1); 364 365 typedef TType q3_input_type; 366 tbb::flow::queue_node< q3_input_type > q3(g); 367 q3_input_type v; 368 369 tbb::flow::make_edge(my_indexer, q3); 370 371 // fill each queue with its value one-at-a-time 372 for (int i = 0; i < Count; ++i ) { 373 serial_queue_helper<SIZE,IType>::put_one_queue_val(i,my_indexer); 374 } 375 376 g.wait_for_all(); 377 for (int i = 0; i < Count * SIZE; ++i ) { 378 g.wait_for_all(); 379 CHECK_MESSAGE( (q3.try_get( v )), "Error in try_get()"); 380 { 381 serial_queue_helper<SIZE,IType>::check_queue_value(v); 382 } 383 } 384 CHECK_MESSAGE( (!q3.try_get( v )), "extra values in output queue"); 385 for(int ii=0; ii < SIZE; ++ii) last_index_seen[ii] = -1; 386 387 // fill each queue completely before filling the next. 388 serial_queue_helper<SIZE, IType>::fill_one_queue(Count,my_indexer); 389 390 g.wait_for_all(); 391 for (int i = 0; i < Count*SIZE; ++i ) { 392 g.wait_for_all(); 393 CHECK_MESSAGE( (q3.try_get( v )), "Error in try_get()"); 394 { 395 serial_queue_helper<SIZE,IType>::check_queue_value(v); 396 } 397 } 398 CHECK_MESSAGE( (!q3.try_get( v )), "extra values in output queue"); 399 } 400 401 // 402 template<typename NodeType> 403 void test_input_ports_return_ref(NodeType& mip_node) { 404 typename NodeType::input_ports_type& input_ports1 = mip_node.input_ports(); 405 typename NodeType::input_ports_type& input_ports2 = mip_node.input_ports(); 406 CHECK_MESSAGE( (&input_ports1 == &input_ports2), "input_ports() should return reference"); 407 } 408 409 // Single predecessor at each port, single accepting successor 410 // * put to buffer before port0, then put to buffer before port1, ... 411 // * fill buffer before port0 then fill buffer before port1, ... 412 413 template<typename IType> 414 class serial_test { 415 typedef typename IType::output_type TType; // this is the union 416 typedef typename IType::tuple_types union_types; 417 static const int SIZE = std::tuple_size<union_types>::value; 418 public: 419 static void test() { 420 tbb::flow::graph g; 421 static const int ELEMS = 3; 422 IType* my_indexer = new IType(g); //makeIndexer<IType>::create(g); 423 424 test_input_ports_return_ref(*my_indexer); 425 426 serial_queue_helper<SIZE, IType>::print_remark(); INFO(" >\n"); 427 428 test_one_serial<IType,TType,SIZE>(*my_indexer, g); 429 430 std::vector<IType> indexer_vector(ELEMS,*my_indexer); 431 432 makeIndexer<IType>::destroy(my_indexer); 433 434 for(int e = 0; e < ELEMS; ++e) { 435 test_one_serial<IType,TType,SIZE>(indexer_vector[e], g); 436 } 437 } 438 439 }; // serial_test 440 441 template< 442 template<typename> class TestType, // serial_test or parallel_test 443 typename T0, typename T1=void, typename T2=void, typename T3=void, typename T4=void, 444 typename T5=void, typename T6=void, typename T7=void, typename T8=void, typename T9=void> // type of the inputs to the indexer_node 445 class generate_test { 446 public: 447 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> indexer_node_type; 448 static void do_test() { 449 TestType<indexer_node_type>::test(); 450 } 451 }; 452 453 //specializations for indexer node inputs 454 template< 455 template<typename> class TestType, 456 typename T0, typename T1, typename T2, typename T3, typename T4, 457 typename T5, typename T6, typename T7, typename T8> 458 class generate_test<TestType, T0, T1, T2, T3, T4, T5, T6, T7, T8> { 459 public: 460 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4, T5, T6, T7, T8> indexer_node_type; 461 static void do_test() { 462 TestType<indexer_node_type>::test(); 463 } 464 }; 465 466 template< 467 template<typename> class TestType, 468 typename T0, typename T1, typename T2, typename T3, typename T4, 469 typename T5, typename T6, typename T7> 470 class generate_test<TestType, T0, T1, T2, T3, T4, T5, T6, T7> { 471 public: 472 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4, T5, T6, T7> indexer_node_type; 473 static void do_test() { 474 TestType<indexer_node_type>::test(); 475 } 476 }; 477 478 template< 479 template<typename> class TestType, 480 typename T0, typename T1, typename T2, typename T3, typename T4, 481 typename T5, typename T6> 482 class generate_test<TestType, T0, T1, T2, T3, T4, T5, T6> { 483 public: 484 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4, T5, T6> indexer_node_type; 485 static void do_test() { 486 TestType<indexer_node_type>::test(); 487 } 488 }; 489 490 template< 491 template<typename> class TestType, 492 typename T0, typename T1, typename T2, typename T3, typename T4, 493 typename T5> 494 class generate_test<TestType, T0, T1, T2, T3, T4, T5> { 495 public: 496 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4, T5> indexer_node_type; 497 static void do_test() { 498 TestType<indexer_node_type>::test(); 499 } 500 }; 501 502 template< 503 template<typename> class TestType, 504 typename T0, typename T1, typename T2, typename T3, typename T4> 505 class generate_test<TestType, T0, T1, T2, T3, T4> { 506 public: 507 typedef tbb::flow::indexer_node<T0, T1, T2, T3, T4> indexer_node_type; 508 static void do_test() { 509 TestType<indexer_node_type>::test(); 510 } 511 }; 512 513 template< 514 template<typename> class TestType, 515 typename T0, typename T1, typename T2, typename T3> 516 class generate_test<TestType, T0, T1, T2, T3> { 517 public: 518 typedef tbb::flow::indexer_node<T0, T1, T2, T3> indexer_node_type; 519 static void do_test() { 520 TestType<indexer_node_type>::test(); 521 } 522 }; 523 524 template< 525 template<typename> class TestType, 526 typename T0, typename T1, typename T2> 527 class generate_test<TestType, T0, T1, T2> { 528 public: 529 typedef tbb::flow::indexer_node<T0, T1, T2> indexer_node_type; 530 static void do_test() { 531 TestType<indexer_node_type>::test(); 532 } 533 }; 534 535 template< 536 template<typename> class TestType, 537 typename T0, typename T1> 538 class generate_test<TestType, T0, T1> { 539 public: 540 typedef tbb::flow::indexer_node<T0, T1> indexer_node_type; 541 static void do_test() { 542 TestType<indexer_node_type>::test(); 543 } 544 }; 545 546 template< 547 template<typename> class TestType, 548 typename T0> 549 class generate_test<TestType, T0> { 550 public: 551 typedef tbb::flow::indexer_node<T0> indexer_node_type; 552 static void do_test() { 553 TestType<indexer_node_type>::test(); 554 } 555 }; 556 557 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 558 template<typename tagged_msg_t, typename input_t> 559 bool check_edge(tbb::flow::graph& g, 560 tbb::flow::broadcast_node<input_t>& start, 561 tbb::flow::buffer_node<tagged_msg_t>& buf, 562 input_t input_value) { 563 start.try_put(input_value); 564 g.wait_for_all(); 565 566 tagged_msg_t msg; 567 bool is_get_succeeded = buf.try_get(msg); 568 569 CHECK_MESSAGE( ((is_get_succeeded)), "There is no item in the buffer"); 570 CHECK_MESSAGE( ((tbb::flow::cast_to<input_t>(msg) == input_value)), "Wrong item value"); 571 return true; 572 } 573 574 template <typename... T> 575 void sink(T...) {} 576 577 template <typename indexer_output_t, typename Type, typename BN, std::size_t... Seq> 578 void check_edge(tbb::flow::graph& g, BN& bn, tbb::flow::buffer_node<indexer_output_t>& buf, Type, tbb::detail::index_sequence<Seq...>) { 579 sink(check_edge<indexer_output_t>(g, std::get<Seq>(bn), buf, typename std::tuple_element<Seq, Type>::type(Seq))...); 580 } 581 582 template <typename... Args, std::size_t... Seq> 583 void test_follows_impl(std::tuple<Args...> t, tbb::detail::index_sequence<Seq...> seq) { 584 using namespace tbb::flow; 585 using indexer_output_t = typename indexer_node<Args...>::output_type; 586 587 graph g; 588 auto bn = std::make_tuple(broadcast_node<Args>(g)...); 589 590 indexer_node<Args...> my_indexer(follows(std::get<Seq>(bn)...)); 591 592 buffer_node<indexer_output_t> buf(g); 593 make_edge(my_indexer, buf); 594 595 check_edge<indexer_output_t>(g, bn, buf, t, seq); 596 } 597 598 template <typename... Args> 599 void test_follows() { 600 test_follows_impl(std::tuple<Args...>(), tbb::detail::make_index_sequence<sizeof...(Args)>()); 601 } 602 603 void test_precedes() { 604 using namespace tbb::flow; 605 606 using indexer_output_t = indexer_node<int, float, double>::output_type; 607 608 graph g; 609 610 broadcast_node<int> start1(g); 611 broadcast_node<float> start2(g); 612 broadcast_node<double> start3(g); 613 614 buffer_node<indexer_output_t> buf1(g); 615 buffer_node<indexer_output_t> buf2(g); 616 buffer_node<indexer_output_t> buf3(g); 617 618 indexer_node<int, float, double> node(precedes(buf1, buf2, buf3)); 619 620 make_edge(start1, input_port<0>(node)); 621 make_edge(start2, input_port<1>(node)); 622 make_edge(start3, input_port<2>(node)); 623 624 check_edge<indexer_output_t, int>(g, start1, buf1, 1); 625 check_edge<indexer_output_t, float>(g, start2, buf2, 2.2f); 626 check_edge<indexer_output_t, double>(g, start3, buf3, 3.3); 627 } 628 629 void test_follows_and_precedes_api() { 630 test_follows<double>(); 631 test_follows<int, double>(); 632 test_follows<int, float, double>(); 633 test_follows<float, double, int, double>(); 634 test_follows<float, double, int, double, double>(); 635 test_follows<float, double, int, double, double, float>(); 636 test_follows<float, double, int, double, double, float, long>(); 637 test_follows<float, double, int, double, double, float, long, int>(); 638 test_follows<float, double, int, double, double, float, long, int, long>(); 639 test_follows<float, double, int, double, double, float, long, int, float, long>(); 640 test_precedes(); 641 } 642 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 643 644 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 645 void test_deduction_guides() { 646 using namespace tbb::flow; 647 graph g; 648 649 broadcast_node<int> b1(g); 650 broadcast_node<double> b2(g); 651 indexer_node<int, double> i0(g); 652 653 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 654 indexer_node i1(follows(b1, b2)); 655 static_assert(std::is_same_v<decltype(i1), indexer_node<int, double>>); 656 #endif 657 658 indexer_node i2(i0); 659 static_assert(std::is_same_v<decltype(i2), indexer_node<int, double>>); 660 } 661 662 #endif 663 664 //! Serial and parallel test on various tuple sizes 665 //! \brief \ref error_guessing 666 TEST_CASE("Serial and parallel test") { 667 INFO("Testing indexer_node, "); 668 669 for (int p = 0; p < 2; ++p) { 670 generate_test<serial_test, float>::do_test(); 671 #if MAX_TUPLE_TEST_SIZE >= 4 672 generate_test<serial_test, float, double, int, short>::do_test(); 673 #endif 674 #if MAX_TUPLE_TEST_SIZE >= 6 675 generate_test<serial_test, double, double, int, long, int, short>::do_test(); 676 #endif 677 #if MAX_TUPLE_TEST_SIZE >= 8 678 generate_test<serial_test, float, double, double, double, float, int, float, long>::do_test(); 679 #endif 680 #if MAX_TUPLE_TEST_SIZE >= 10 681 generate_test<serial_test, float, double, int, double, double, float, long, int, float, long>::do_test(); 682 #endif 683 generate_test<parallel_test, float, double>::do_test(); 684 #if MAX_TUPLE_TEST_SIZE >= 3 685 generate_test<parallel_test, float, int, long>::do_test(); 686 #endif 687 #if MAX_TUPLE_TEST_SIZE >= 5 688 generate_test<parallel_test, double, double, int, int, short>::do_test(); 689 #endif 690 #if MAX_TUPLE_TEST_SIZE >= 7 691 generate_test<parallel_test, float, int, double, float, long, float, long>::do_test(); 692 #endif 693 #if MAX_TUPLE_TEST_SIZE >= 9 694 generate_test<parallel_test, float, double, int, double, double, long, int, float, long>::do_test(); 695 #endif 696 } 697 } 698 699 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 700 //! Test follows and precedes API 701 //! \brief \ref error_guessing 702 TEST_CASE("Follows and precedes API") { 703 test_follows_and_precedes_api(); 704 } 705 #endif 706 707 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 708 //! Test deduction guides 709 //! \brief \ref requirement 710 TEST_CASE("Deduction guides") { 711 test_deduction_guides(); 712 } 713 #endif 714 715