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