151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov Copyright (c) 2005-2022 Intel Corporation
351c0b2f7Stbbdev
451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev you may not use this file except in compliance with the License.
651c0b2f7Stbbdev You may obtain a copy of the License at
751c0b2f7Stbbdev
851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev
1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev See the License for the specific language governing permissions and
1451c0b2f7Stbbdev limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev
1751c0b2f7Stbbdev #include "common/config.h"
1851c0b2f7Stbbdev
1951c0b2f7Stbbdev #include "tbb/flow_graph.h"
2051c0b2f7Stbbdev
2151c0b2f7Stbbdev #include "common/test.h"
2251c0b2f7Stbbdev #include "common/utils.h"
2351c0b2f7Stbbdev #include "common/utils_assert.h"
2451c0b2f7Stbbdev #include "common/graph_utils.h"
2551c0b2f7Stbbdev
2651c0b2f7Stbbdev
2751c0b2f7Stbbdev //! \file test_split_node.cpp
2851c0b2f7Stbbdev //! \brief Test for [flow_graph.split_node] specification
2951c0b2f7Stbbdev
3051c0b2f7Stbbdev
3151c0b2f7Stbbdev #if defined(_MSC_VER) && _MSC_VER < 1600
3251c0b2f7Stbbdev #pragma warning (disable : 4503) //disabling the "decorated name length exceeded" warning for VS2008 and earlier
3351c0b2f7Stbbdev #endif
3451c0b2f7Stbbdev
3551c0b2f7Stbbdev //
3651c0b2f7Stbbdev // Tests
3751c0b2f7Stbbdev //
3851c0b2f7Stbbdev
3951c0b2f7Stbbdev const int Count = 300;
4051c0b2f7Stbbdev const int MaxPorts = 10;
4151c0b2f7Stbbdev const int MaxNInputs = 5; // max # of input_nodes to register for each split_node input in parallel test
4251c0b2f7Stbbdev
4351c0b2f7Stbbdev std::vector<bool> flags; // for checking output
4451c0b2f7Stbbdev
4551c0b2f7Stbbdev template<typename T>
4651c0b2f7Stbbdev class name_of {
4751c0b2f7Stbbdev public:
name()4851c0b2f7Stbbdev static const char* name() { return "Unknown"; }
4951c0b2f7Stbbdev };
5051c0b2f7Stbbdev template<>
5151c0b2f7Stbbdev class name_of<int> {
5251c0b2f7Stbbdev public:
name()5351c0b2f7Stbbdev static const char* name() { return "int"; }
5451c0b2f7Stbbdev };
5551c0b2f7Stbbdev template<>
5651c0b2f7Stbbdev class name_of<float> {
5751c0b2f7Stbbdev public:
name()5851c0b2f7Stbbdev static const char* name() { return "float"; }
5951c0b2f7Stbbdev };
6051c0b2f7Stbbdev template<>
6151c0b2f7Stbbdev class name_of<double> {
6251c0b2f7Stbbdev public:
name()6351c0b2f7Stbbdev static const char* name() { return "double"; }
6451c0b2f7Stbbdev };
6551c0b2f7Stbbdev template<>
6651c0b2f7Stbbdev class name_of<long> {
6751c0b2f7Stbbdev public:
name()6851c0b2f7Stbbdev static const char* name() { return "long"; }
6951c0b2f7Stbbdev };
7051c0b2f7Stbbdev template<>
7151c0b2f7Stbbdev class name_of<short> {
7251c0b2f7Stbbdev public:
name()7351c0b2f7Stbbdev static const char* name() { return "short"; }
7451c0b2f7Stbbdev };
7551c0b2f7Stbbdev
7651c0b2f7Stbbdev // T must be arithmetic, and shouldn't wrap around for reasonable sizes of Count (which is now 150, and maxPorts is 10,
7751c0b2f7Stbbdev // so the max number generated right now is 1500 or so.) Input will generate a series of TT with value
7851c0b2f7Stbbdev // (init_val + (i-1)*addend) * my_mult, where i is the i-th invocation of the body. We are attaching addend
7951c0b2f7Stbbdev // input nodes to a join_port, and each will generate part of the numerical series the port is expecting
8051c0b2f7Stbbdev // to receive. If there is only one input node, the series order will be maintained; if more than one,
8151c0b2f7Stbbdev // this is not guaranteed.
8251c0b2f7Stbbdev
8351c0b2f7Stbbdev template<int N>
8451c0b2f7Stbbdev struct tuple_helper {
8551c0b2f7Stbbdev template<typename TupleType>
set_elementtuple_helper8651c0b2f7Stbbdev static void set_element( TupleType &t, int i) {
8751c0b2f7Stbbdev std::get<N-1>(t) = (typename std::tuple_element<N-1,TupleType>::type)(i * (N+1));
8851c0b2f7Stbbdev tuple_helper<N-1>::set_element(t, i);
8951c0b2f7Stbbdev }
9051c0b2f7Stbbdev };
9151c0b2f7Stbbdev
9251c0b2f7Stbbdev template<>
9351c0b2f7Stbbdev struct tuple_helper<1> {
9451c0b2f7Stbbdev template<typename TupleType>
set_elementtuple_helper9551c0b2f7Stbbdev static void set_element(TupleType &t, int i) {
9651c0b2f7Stbbdev std::get<0>(t) = (typename std::tuple_element<0,TupleType>::type)(i * 2);
9751c0b2f7Stbbdev }
9851c0b2f7Stbbdev };
9951c0b2f7Stbbdev
10051c0b2f7Stbbdev // if we start N input_bodys they will all have the addend N, and my_count should be initialized to 0 .. N-1.
10151c0b2f7Stbbdev // the output tuples should have all the sequence, but the order will in general vary.
10251c0b2f7Stbbdev template<typename TupleType>
10351c0b2f7Stbbdev class my_input_body {
10451c0b2f7Stbbdev typedef TupleType TT;
10551c0b2f7Stbbdev static const int N = std::tuple_size<TT>::value;
10651c0b2f7Stbbdev int my_count;
10751c0b2f7Stbbdev int addend;
10851c0b2f7Stbbdev public:
my_input_body(int init_val,int addto)10951c0b2f7Stbbdev my_input_body(int init_val, int addto) : my_count(init_val), addend(addto) { }
operator ()(tbb::flow_control & fc)11051c0b2f7Stbbdev TT operator()( tbb::flow_control &fc) {
11151c0b2f7Stbbdev if(my_count >= Count){
11251c0b2f7Stbbdev fc.stop();
11351c0b2f7Stbbdev return TT();
11451c0b2f7Stbbdev }
11551c0b2f7Stbbdev TT v;
11651c0b2f7Stbbdev tuple_helper<N>::set_element(v, my_count);
11751c0b2f7Stbbdev my_count += addend;
11851c0b2f7Stbbdev return v;
11951c0b2f7Stbbdev }
12051c0b2f7Stbbdev };
12151c0b2f7Stbbdev
12251c0b2f7Stbbdev // allocator for split_node.
12351c0b2f7Stbbdev
12451c0b2f7Stbbdev template<int N, typename SType>
12551c0b2f7Stbbdev class makeSplit {
12651c0b2f7Stbbdev public:
create(tbb::flow::graph & g)12751c0b2f7Stbbdev static SType *create(tbb::flow::graph& g) {
12851c0b2f7Stbbdev SType *temp = new SType(g);
12951c0b2f7Stbbdev return temp;
13051c0b2f7Stbbdev }
destroy(SType * p)13151c0b2f7Stbbdev static void destroy(SType *p) { delete p; }
13251c0b2f7Stbbdev };
13351c0b2f7Stbbdev
13451c0b2f7Stbbdev // holder for sink_node pointers for eventual deletion
13551c0b2f7Stbbdev
13651c0b2f7Stbbdev static void* all_sink_nodes[MaxPorts];
13751c0b2f7Stbbdev
13851c0b2f7Stbbdev
13951c0b2f7Stbbdev template<int ELEM, typename SType>
14051c0b2f7Stbbdev class sink_node_helper {
14151c0b2f7Stbbdev public:
14251c0b2f7Stbbdev typedef typename SType::input_type TT;
14351c0b2f7Stbbdev typedef typename std::tuple_element<ELEM-1,TT>::type IT;
14451c0b2f7Stbbdev typedef typename tbb::flow::queue_node<IT> my_sink_node_type;
print_parallel_remark()14551c0b2f7Stbbdev static void print_parallel_remark() {
14651c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::print_parallel_remark();
14751c0b2f7Stbbdev INFO(", " << name_of<IT>::name());
14851c0b2f7Stbbdev }
print_serial_remark()14951c0b2f7Stbbdev static void print_serial_remark() {
15051c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::print_serial_remark();
15151c0b2f7Stbbdev INFO(", " << name_of<IT>::name());
15251c0b2f7Stbbdev }
add_sink_nodes(SType & my_split,tbb::flow::graph & g)15351c0b2f7Stbbdev static void add_sink_nodes(SType &my_split, tbb::flow::graph &g) {
15451c0b2f7Stbbdev my_sink_node_type *new_node = new my_sink_node_type(g);
15551c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<ELEM-1>(my_split) , *new_node);
15651c0b2f7Stbbdev all_sink_nodes[ELEM-1] = (void *)new_node;
15751c0b2f7Stbbdev sink_node_helper<ELEM-1, SType>::add_sink_nodes(my_split, g);
15851c0b2f7Stbbdev }
15951c0b2f7Stbbdev
check_sink_values()16051c0b2f7Stbbdev static void check_sink_values() {
16151c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[ELEM-1]);
16251c0b2f7Stbbdev for(int i = 0; i < Count; ++i) {
16351c0b2f7Stbbdev IT v{};
16451c0b2f7Stbbdev CHECK_MESSAGE(dp->try_get(v), "");
16551c0b2f7Stbbdev flags[((int)v) / (ELEM+1)] = true;
16651c0b2f7Stbbdev }
16751c0b2f7Stbbdev for(int i = 0; i < Count; ++i) {
16851c0b2f7Stbbdev CHECK_MESSAGE(flags[i], "");
16951c0b2f7Stbbdev flags[i] = false; // reset for next test
17051c0b2f7Stbbdev }
17151c0b2f7Stbbdev sink_node_helper<ELEM-1,SType>::check_sink_values();
17251c0b2f7Stbbdev }
remove_sink_nodes(SType & my_split)17351c0b2f7Stbbdev static void remove_sink_nodes(SType& my_split) {
17451c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[ELEM-1]);
17551c0b2f7Stbbdev tbb::flow::remove_edge( tbb::flow::output_port<ELEM-1>(my_split) , *dp);
17651c0b2f7Stbbdev delete dp;
17751c0b2f7Stbbdev sink_node_helper<ELEM-1, SType>::remove_sink_nodes(my_split);
17851c0b2f7Stbbdev }
17951c0b2f7Stbbdev };
18051c0b2f7Stbbdev
18151c0b2f7Stbbdev template<typename SType>
18251c0b2f7Stbbdev class sink_node_helper<1, SType> {
18351c0b2f7Stbbdev typedef typename SType::input_type TT;
18451c0b2f7Stbbdev typedef typename std::tuple_element<0,TT>::type IT;
18551c0b2f7Stbbdev typedef typename tbb::flow::queue_node<IT> my_sink_node_type;
18651c0b2f7Stbbdev public:
print_parallel_remark()18751c0b2f7Stbbdev static void print_parallel_remark() {
18851c0b2f7Stbbdev INFO("Parallel test of split_node< " << name_of<IT>::name());
18951c0b2f7Stbbdev }
print_serial_remark()19051c0b2f7Stbbdev static void print_serial_remark() {
19151c0b2f7Stbbdev INFO("Serial test of split_node< " << name_of<IT>::name());
19251c0b2f7Stbbdev }
add_sink_nodes(SType & my_split,tbb::flow::graph & g)19351c0b2f7Stbbdev static void add_sink_nodes(SType &my_split, tbb::flow::graph &g) {
19451c0b2f7Stbbdev my_sink_node_type *new_node = new my_sink_node_type(g);
19551c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(my_split) , *new_node);
19651c0b2f7Stbbdev all_sink_nodes[0] = (void *)new_node;
19751c0b2f7Stbbdev }
check_sink_values()19851c0b2f7Stbbdev static void check_sink_values() {
19951c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[0]);
20051c0b2f7Stbbdev for(int i = 0; i < Count; ++i) {
20151c0b2f7Stbbdev IT v{};
20251c0b2f7Stbbdev CHECK_MESSAGE(dp->try_get(v), "");
20351c0b2f7Stbbdev flags[((int)v) / 2] = true;
20451c0b2f7Stbbdev }
20551c0b2f7Stbbdev for(int i = 0; i < Count; ++i) {
20651c0b2f7Stbbdev CHECK_MESSAGE(flags[i], "");
20751c0b2f7Stbbdev flags[i] = false; // reset for next test
20851c0b2f7Stbbdev }
20951c0b2f7Stbbdev }
remove_sink_nodes(SType & my_split)21051c0b2f7Stbbdev static void remove_sink_nodes(SType& my_split) {
21151c0b2f7Stbbdev my_sink_node_type *dp = reinterpret_cast<my_sink_node_type *>(all_sink_nodes[0]);
21251c0b2f7Stbbdev tbb::flow::remove_edge( tbb::flow::output_port<0>(my_split) , *dp);
21351c0b2f7Stbbdev delete dp;
21451c0b2f7Stbbdev }
21551c0b2f7Stbbdev };
21651c0b2f7Stbbdev
21751c0b2f7Stbbdev // parallel_test: create input_nodes that feed tuples into the split node
21851c0b2f7Stbbdev // and queue_nodes that receive the output.
21951c0b2f7Stbbdev template<typename SType>
22051c0b2f7Stbbdev class parallel_test {
22151c0b2f7Stbbdev public:
22251c0b2f7Stbbdev typedef typename SType::input_type TType;
22351c0b2f7Stbbdev typedef tbb::flow::input_node<TType> input_type;
22451c0b2f7Stbbdev static const int N = std::tuple_size<TType>::value;
22551c0b2f7Stbbdev
test()22651c0b2f7Stbbdev static void test() {
22751c0b2f7Stbbdev input_type* all_input_nodes[MaxNInputs];
22851c0b2f7Stbbdev sink_node_helper<N,SType>::print_parallel_remark();
22951c0b2f7Stbbdev INFO(" >\n");
23051c0b2f7Stbbdev for(int i=0; i < MaxPorts; ++i) {
23157f524caSIlya Isaev all_sink_nodes[i] = nullptr;
23251c0b2f7Stbbdev }
23351c0b2f7Stbbdev // try test for # inputs 1 .. MaxNInputs
23451c0b2f7Stbbdev for(int nInputs = 1; nInputs <= MaxNInputs; ++nInputs) {
23551c0b2f7Stbbdev tbb::flow::graph g;
23651c0b2f7Stbbdev SType* my_split = makeSplit<N,SType>::create(g);
23751c0b2f7Stbbdev
23851c0b2f7Stbbdev // add sinks first so when inputs start spitting out values they are there to catch them
23951c0b2f7Stbbdev sink_node_helper<N, SType>::add_sink_nodes((*my_split), g);
24051c0b2f7Stbbdev
24151c0b2f7Stbbdev // now create nInputs input_nodes, each spitting out i, i+nInputs, i+2*nInputs ...
24251c0b2f7Stbbdev // each element of the tuple is i*(n+1), where n is the tuple element index (1-N)
24351c0b2f7Stbbdev for(int i = 0; i < nInputs; ++i) {
24451c0b2f7Stbbdev // create input node
24551c0b2f7Stbbdev input_type *s = new input_type(g, my_input_body<TType>(i, nInputs) );
24651c0b2f7Stbbdev tbb::flow::make_edge(*s, *my_split);
24751c0b2f7Stbbdev all_input_nodes[i] = s;
24851c0b2f7Stbbdev s->activate();
24951c0b2f7Stbbdev }
25051c0b2f7Stbbdev
25151c0b2f7Stbbdev g.wait_for_all();
25251c0b2f7Stbbdev
25351c0b2f7Stbbdev // check that we got Count values in each output queue, and all the index values
25451c0b2f7Stbbdev // are there.
25551c0b2f7Stbbdev sink_node_helper<N, SType>::check_sink_values();
25651c0b2f7Stbbdev
25751c0b2f7Stbbdev sink_node_helper<N, SType>::remove_sink_nodes(*my_split);
25851c0b2f7Stbbdev for(int i = 0; i < nInputs; ++i) {
25951c0b2f7Stbbdev delete all_input_nodes[i];
26051c0b2f7Stbbdev }
26151c0b2f7Stbbdev makeSplit<N,SType>::destroy(my_split);
26251c0b2f7Stbbdev }
26351c0b2f7Stbbdev }
26451c0b2f7Stbbdev };
26551c0b2f7Stbbdev
26651c0b2f7Stbbdev //
26751c0b2f7Stbbdev // Single predecessor, single accepting successor at each port
26851c0b2f7Stbbdev
26951c0b2f7Stbbdev template<typename SType>
test_one_serial(SType & my_split,tbb::flow::graph & g)27051c0b2f7Stbbdev void test_one_serial( SType &my_split, tbb::flow::graph &g) {
27151c0b2f7Stbbdev typedef typename SType::input_type TType;
27251c0b2f7Stbbdev static const int TUPLE_SIZE = std::tuple_size<TType>::value;
27351c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::add_sink_nodes(my_split,g);
27451c0b2f7Stbbdev typedef TType q3_input_type;
27551c0b2f7Stbbdev tbb::flow::queue_node< q3_input_type > q3(g);
27651c0b2f7Stbbdev
27751c0b2f7Stbbdev tbb::flow::make_edge( q3, my_split );
27851c0b2f7Stbbdev
27951c0b2f7Stbbdev // fill the queue with its value one-at-a-time
28051c0b2f7Stbbdev flags.clear();
28151c0b2f7Stbbdev for (int i = 0; i < Count; ++i ) {
28251c0b2f7Stbbdev TType v;
28351c0b2f7Stbbdev tuple_helper<TUPLE_SIZE>::set_element(v, i);
28451c0b2f7Stbbdev CHECK_MESSAGE(my_split.try_put(v), "");
28551c0b2f7Stbbdev flags.push_back(false);
28651c0b2f7Stbbdev }
28751c0b2f7Stbbdev
28851c0b2f7Stbbdev g.wait_for_all();
28951c0b2f7Stbbdev
29051c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE,SType>::check_sink_values();
29151c0b2f7Stbbdev
29251c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::remove_sink_nodes(my_split);
29351c0b2f7Stbbdev
29451c0b2f7Stbbdev }
29551c0b2f7Stbbdev
29651c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
test_follows_and_precedes_api()29751c0b2f7Stbbdev void test_follows_and_precedes_api() {
29851c0b2f7Stbbdev using namespace tbb::flow;
29951c0b2f7Stbbdev using msg_t = std::tuple<int, float, double>;
30051c0b2f7Stbbdev
30151c0b2f7Stbbdev graph g;
30251c0b2f7Stbbdev
30351c0b2f7Stbbdev function_node<msg_t, msg_t> f1(g, unlimited, [](msg_t msg) { return msg; } );
30451c0b2f7Stbbdev auto f2(f1);
30551c0b2f7Stbbdev auto f3(f1);
30651c0b2f7Stbbdev
30751c0b2f7Stbbdev std::atomic<int> body_calls;
30851c0b2f7Stbbdev body_calls = 0;
30951c0b2f7Stbbdev
31051c0b2f7Stbbdev function_node<int, int> f4(g, unlimited, [&](int val) { ++body_calls; return val; } );
31151c0b2f7Stbbdev function_node<float, float> f5(g, unlimited, [&](float val) { ++body_calls; return val; } );
31251c0b2f7Stbbdev function_node<double, double> f6(g, unlimited, [&](double val) { ++body_calls; return val; } );
31351c0b2f7Stbbdev
31451c0b2f7Stbbdev split_node<msg_t> following_node(follows(f1, f2, f3));
31551c0b2f7Stbbdev make_edge(output_port<0>(following_node), f4);
31651c0b2f7Stbbdev make_edge(output_port<1>(following_node), f5);
31751c0b2f7Stbbdev make_edge(output_port<2>(following_node), f6);
31851c0b2f7Stbbdev
31951c0b2f7Stbbdev split_node<msg_t> preceding_node(precedes(f4, f5, f6));
32051c0b2f7Stbbdev make_edge(f1, preceding_node);
32151c0b2f7Stbbdev make_edge(f2, preceding_node);
32251c0b2f7Stbbdev make_edge(f3, preceding_node);
32351c0b2f7Stbbdev
32451c0b2f7Stbbdev msg_t msg(1, 2.2f, 3.3);
32551c0b2f7Stbbdev f1.try_put(msg);
32651c0b2f7Stbbdev f2.try_put(msg);
32751c0b2f7Stbbdev f3.try_put(msg);
32851c0b2f7Stbbdev
32951c0b2f7Stbbdev g.wait_for_all();
33051c0b2f7Stbbdev
33151c0b2f7Stbbdev // <number of try puts> * <number of splits by a input node> * <number of input nodes>
33251c0b2f7Stbbdev CHECK_MESSAGE( ((body_calls == 3*3*2)), "Not exact edge quantity was made");
33351c0b2f7Stbbdev }
33451c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
33551c0b2f7Stbbdev
33651c0b2f7Stbbdev template<typename SType>
33751c0b2f7Stbbdev class serial_test {
33851c0b2f7Stbbdev typedef typename SType::input_type TType;
33951c0b2f7Stbbdev static const int TUPLE_SIZE = std::tuple_size<TType>::value;
34051c0b2f7Stbbdev static const int ELEMS = 3;
34151c0b2f7Stbbdev public:
test()34251c0b2f7Stbbdev static void test() {
34351c0b2f7Stbbdev tbb::flow::graph g;
34451c0b2f7Stbbdev flags.reserve(Count);
34551c0b2f7Stbbdev SType* my_split = makeSplit<TUPLE_SIZE,SType>::create(g);
34651c0b2f7Stbbdev sink_node_helper<TUPLE_SIZE, SType>::print_serial_remark(); INFO(" >\n");
34751c0b2f7Stbbdev
34851c0b2f7Stbbdev test_output_ports_return_ref(*my_split);
34951c0b2f7Stbbdev
35051c0b2f7Stbbdev test_one_serial<SType>(*my_split, g);
35151c0b2f7Stbbdev // build the vector with copy construction from the used split node.
35251c0b2f7Stbbdev std::vector<SType>split_vector(ELEMS, *my_split);
35351c0b2f7Stbbdev // destroy the tired old split_node in case we're accidentally reusing pieces of it.
35451c0b2f7Stbbdev makeSplit<TUPLE_SIZE,SType>::destroy(my_split);
35551c0b2f7Stbbdev
35651c0b2f7Stbbdev
35751c0b2f7Stbbdev for(int e = 0; e < ELEMS; ++e) { // exercise each of the vector elements
35851c0b2f7Stbbdev test_one_serial<SType>(split_vector[e], g);
35951c0b2f7Stbbdev }
36051c0b2f7Stbbdev }
36151c0b2f7Stbbdev
36251c0b2f7Stbbdev }; // serial_test
36351c0b2f7Stbbdev
36451c0b2f7Stbbdev template<
36551c0b2f7Stbbdev template<typename> class TestType, // serial_test or parallel_test
36651c0b2f7Stbbdev typename TupleType > // type of the input of the split
36751c0b2f7Stbbdev struct generate_test {
36851c0b2f7Stbbdev typedef tbb::flow::split_node<TupleType> split_node_type;
do_testgenerate_test36951c0b2f7Stbbdev static void do_test() {
37051c0b2f7Stbbdev TestType<split_node_type>::test();
37151c0b2f7Stbbdev }
37251c0b2f7Stbbdev }; // generate_test
37351c0b2f7Stbbdev
37451c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
37551c0b2f7Stbbdev
test_deduction_guides()37651c0b2f7Stbbdev void test_deduction_guides() {
37751c0b2f7Stbbdev using namespace tbb::flow;
37851c0b2f7Stbbdev using tuple_type = std::tuple<int, int>;
37951c0b2f7Stbbdev
38051c0b2f7Stbbdev graph g;
38151c0b2f7Stbbdev split_node<tuple_type> s0(g);
38251c0b2f7Stbbdev
38351c0b2f7Stbbdev split_node s1(s0);
38451c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s1), split_node<tuple_type>>);
38551c0b2f7Stbbdev
38651c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
38751c0b2f7Stbbdev broadcast_node<tuple_type> b1(g), b2(g);
38851c0b2f7Stbbdev broadcast_node<int> b3(g), b4(g);
38951c0b2f7Stbbdev
39051c0b2f7Stbbdev split_node s2(follows(b1, b2));
39151c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s2), split_node<tuple_type>>);
39251c0b2f7Stbbdev
39351c0b2f7Stbbdev split_node s3(precedes(b3, b4));
39451c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s3), split_node<tuple_type>>);
39551c0b2f7Stbbdev #endif
39651c0b2f7Stbbdev }
39751c0b2f7Stbbdev
39851c0b2f7Stbbdev #endif
39951c0b2f7Stbbdev
40051c0b2f7Stbbdev //! Test output ports and message passing with different input tuples
40151c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
40251c0b2f7Stbbdev TEST_CASE("Tuple tests"){
40351c0b2f7Stbbdev for (int p = 0; p < 2; ++p) {
40451c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double> >::do_test();
40551c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 4
40651c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, int, long> >::do_test();
40751c0b2f7Stbbdev #endif
40851c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 6
40951c0b2f7Stbbdev generate_test<serial_test, std::tuple<double, double, int, long, int, short> >::do_test();
41051c0b2f7Stbbdev #endif
41151c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 8
41251c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, double, double, float, int, float, long> >::do_test();
41351c0b2f7Stbbdev #endif
41451c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 10
41551c0b2f7Stbbdev generate_test<serial_test, std::tuple<float, double, int, double, double, float, long, int, float, long> >::do_test();
41651c0b2f7Stbbdev #endif
41751c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, double> >::do_test();
41851c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 3
41951c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, int, long> >::do_test();
42051c0b2f7Stbbdev #endif
42151c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 5
42251c0b2f7Stbbdev generate_test<parallel_test, std::tuple<double, double, int, int, short> >::do_test();
42351c0b2f7Stbbdev #endif
42451c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 7
42551c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, int, double, float, long, float, long> >::do_test();
42651c0b2f7Stbbdev #endif
42751c0b2f7Stbbdev #if MAX_TUPLE_TEST_SIZE >= 9
42851c0b2f7Stbbdev generate_test<parallel_test, std::tuple<float, double, int, double, double, long, int, float, long> >::do_test();
42951c0b2f7Stbbdev #endif
43051c0b2f7Stbbdev }
43151c0b2f7Stbbdev }
43251c0b2f7Stbbdev
43351c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
43451c0b2f7Stbbdev //! Test decution guides
43551c0b2f7Stbbdev //! \brief \ref requirement
43651c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){
43751c0b2f7Stbbdev test_follows_and_precedes_api();
43851c0b2f7Stbbdev }
43951c0b2f7Stbbdev #endif
44051c0b2f7Stbbdev
44151c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
44251c0b2f7Stbbdev //! Test decution guides
44351c0b2f7Stbbdev //! \brief \ref requirement
44451c0b2f7Stbbdev TEST_CASE("Deduction guides"){
44551c0b2f7Stbbdev test_deduction_guides();
44651c0b2f7Stbbdev }
44751c0b2f7Stbbdev #endif
44851c0b2f7Stbbdev
449