xref: /oneTBB/test/tbb/test_composite_node.cpp (revision de0109be)
151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2005-2021 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 
17b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER
18b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19b15aabb3Stbbdev #endif
20b15aabb3Stbbdev 
2151c0b2f7Stbbdev #include "common/config.h"
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev #include "tbb/flow_graph.h"
2451c0b2f7Stbbdev 
2551c0b2f7Stbbdev #include "common/test.h"
2651c0b2f7Stbbdev #include "common/utils.h"
2751c0b2f7Stbbdev #include "common/graph_utils.h"
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev #include <tuple>
3051c0b2f7Stbbdev #include <cmath>
3151c0b2f7Stbbdev #include <vector>
3251c0b2f7Stbbdev 
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev //! \file test_composite_node.cpp
3551c0b2f7Stbbdev //! \brief Test for [flow_graph.composite_node] specification
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev struct passthru_body {
operator ()passthru_body3951c0b2f7Stbbdev     int operator()( int i ) {
4051c0b2f7Stbbdev         return i;
4151c0b2f7Stbbdev     }
4251c0b2f7Stbbdev };
4351c0b2f7Stbbdev 
4451c0b2f7Stbbdev class my_input_body{
4551c0b2f7Stbbdev     int start;
4651c0b2f7Stbbdev     int finish;
4751c0b2f7Stbbdev     int step;
4851c0b2f7Stbbdev public:
my_input_body(int f,int s)4951c0b2f7Stbbdev     my_input_body(int f, int s) : start(1), finish(f), step(s) {}
operator ()(tbb::flow_control & fc)5051c0b2f7Stbbdev     int operator()(tbb::flow_control& fc) {
5151c0b2f7Stbbdev        int a = start;
5251c0b2f7Stbbdev        if (start <= finish) {
5351c0b2f7Stbbdev            a = start;
5451c0b2f7Stbbdev            start+=step;
5551c0b2f7Stbbdev            return a;
5651c0b2f7Stbbdev        }
5751c0b2f7Stbbdev        else {
5851c0b2f7Stbbdev            fc.stop();
5951c0b2f7Stbbdev            return int();
6051c0b2f7Stbbdev        };
6151c0b2f7Stbbdev    }
6251c0b2f7Stbbdev };
6351c0b2f7Stbbdev 
6451c0b2f7Stbbdev struct m_fxn_body{
operator ()m_fxn_body6551c0b2f7Stbbdev     void operator()(int, tbb::flow::multifunction_node<int, std::tuple<int,int> >::output_ports_type ) {}
6651c0b2f7Stbbdev };
6751c0b2f7Stbbdev 
6851c0b2f7Stbbdev struct ct_body {
ct_bodyct_body6951c0b2f7Stbbdev ct_body(){}
operator ()ct_body7051c0b2f7Stbbdev     void operator()(tbb::flow::continue_msg){}
7151c0b2f7Stbbdev };
7251c0b2f7Stbbdev 
7351c0b2f7Stbbdev struct seq_body {
operator ()seq_body74*478de5b1Stbbdev std::size_t operator()(int i) { return i; }
7551c0b2f7Stbbdev };
7651c0b2f7Stbbdev 
7751c0b2f7Stbbdev template<int N, typename T1, typename T2>
7851c0b2f7Stbbdev struct compare {
compare_refscompare7951c0b2f7Stbbdev     static void compare_refs(T1 tuple1, T2 tuple2) {
8051c0b2f7Stbbdev     CHECK_MESSAGE( ( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly");
8151c0b2f7Stbbdev     compare<N-1, T1, T2>::compare_refs(tuple1, tuple2);
8251c0b2f7Stbbdev     }
8351c0b2f7Stbbdev };
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev template<typename T1, typename T2>
8651c0b2f7Stbbdev struct compare<1, T1, T2> {
compare_refscompare8751c0b2f7Stbbdev     static void compare_refs(T1 tuple1, T2 tuple2) {
8851c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set");
8951c0b2f7Stbbdev     }
9051c0b2f7Stbbdev };
9151c0b2f7Stbbdev 
9251c0b2f7Stbbdev struct tiny_node : public tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > {
9351c0b2f7Stbbdev     tbb::flow::function_node< int, int > f1;
9451c0b2f7Stbbdev     tbb::flow::function_node< int, int > f2;
9551c0b2f7Stbbdev     typedef tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > base_type;
9651c0b2f7Stbbdev 
9751c0b2f7Stbbdev public:
tiny_nodetiny_node9851c0b2f7Stbbdev     tiny_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), f1(g, tbb::flow::unlimited, passthru_body() ), f2(g, tbb::flow::unlimited, passthru_body() ) {
9951c0b2f7Stbbdev         tbb::flow::make_edge(f1, f2);
10051c0b2f7Stbbdev 
10151c0b2f7Stbbdev         std::tuple<tbb::flow::function_node< int, int >& > input_tuple(f1);
10251c0b2f7Stbbdev         std::tuple<tbb::flow::function_node< int, int >& > output_tuple(f2);
10351c0b2f7Stbbdev         base_type::set_external_ports(input_tuple, output_tuple);
10451c0b2f7Stbbdev 
10551c0b2f7Stbbdev         if(hidden)
10651c0b2f7Stbbdev             base_type::add_nodes(f1, f2);
10751c0b2f7Stbbdev         else
10851c0b2f7Stbbdev             base_type::add_visible_nodes(f1, f2);
10951c0b2f7Stbbdev 
11051c0b2f7Stbbdev     }
11151c0b2f7Stbbdev };
11251c0b2f7Stbbdev 
test_tiny(bool hidden=false)11351c0b2f7Stbbdev int test_tiny(bool hidden = false) {
11451c0b2f7Stbbdev     tbb::flow::graph g;
11551c0b2f7Stbbdev     tbb::flow::function_node< int, int > f0( g, tbb::flow::unlimited, passthru_body() );
11651c0b2f7Stbbdev     tiny_node t(g, hidden);
11751c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(t) == &t.f1), "f1 not bound to input port 0 in composite_node t");
11851c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(t) == &t.f2), "f2 not bound to output port 0 in composite_node t");
11951c0b2f7Stbbdev 
12051c0b2f7Stbbdev     tiny_node t1(g, hidden);
12151c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(t1.input_ports()) == &t1.f1), "f1 not bound to input port 0 in composite_node t1");
12251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(t1.output_ports()) == &t1.f2), "f2 not bound to output port 0 in composite_node t1");
12351c0b2f7Stbbdev 
12451c0b2f7Stbbdev     test_input_ports_return_ref(t1);
12551c0b2f7Stbbdev     test_output_ports_return_ref(t1);
12651c0b2f7Stbbdev 
12751c0b2f7Stbbdev     tiny_node t2(g, hidden);
12851c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(t2) == &t2.f1), "f1 not bound to input port 0 in composite_node t2");
12951c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(t2) == &t2.f2), "f2 not bound to output port 0 in composite_node t2");
13051c0b2f7Stbbdev 
13151c0b2f7Stbbdev     tbb::flow::function_node< int, int > f3( g, tbb::flow::unlimited, passthru_body() );
13251c0b2f7Stbbdev     tbb::flow::make_edge( f0, t );
13351c0b2f7Stbbdev     tbb::flow::make_edge( t, t1 );
13451c0b2f7Stbbdev     tbb::flow::make_edge( t1, t2 );
13551c0b2f7Stbbdev     tbb::flow::make_edge( t2 , f3 );
13651c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
13751c0b2f7Stbbdev     tbb::flow::make_edge(f3, q);
13851c0b2f7Stbbdev     f0.try_put(1);
13951c0b2f7Stbbdev     g.wait_for_all();
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev     int i, j =0;
14251c0b2f7Stbbdev     q.try_get(i);
14351c0b2f7Stbbdev     CHECK_MESSAGE( ( i == 1), "item did not go through graph");
14451c0b2f7Stbbdev     q.try_get(j);
14551c0b2f7Stbbdev     CHECK_MESSAGE( ( !j), "unexpected item in graph");
14651c0b2f7Stbbdev     g.wait_for_all();
14751c0b2f7Stbbdev 
14851c0b2f7Stbbdev     tbb::flow::remove_edge(f3, q);
14951c0b2f7Stbbdev     tbb::flow::remove_edge(t2, f3);
15051c0b2f7Stbbdev     tbb::flow::remove_edge(t1, t2);
15151c0b2f7Stbbdev 
15251c0b2f7Stbbdev     tbb::flow::make_edge( t1 , f3 );
15351c0b2f7Stbbdev     tbb::flow::make_edge(f3, q);
15451c0b2f7Stbbdev 
15551c0b2f7Stbbdev     f0.try_put(2);
15651c0b2f7Stbbdev     g.wait_for_all();
15751c0b2f7Stbbdev 
15851c0b2f7Stbbdev     q.try_get(i);
15951c0b2f7Stbbdev     CHECK_MESSAGE( ( i == 2), "item did not go through graph after removal of edge");
16051c0b2f7Stbbdev     q.try_get(j);
16151c0b2f7Stbbdev     CHECK_MESSAGE( ( !j), "unexpected item in graph after removal of edge");
16251c0b2f7Stbbdev 
16351c0b2f7Stbbdev     return 0;
16451c0b2f7Stbbdev }
16551c0b2f7Stbbdev 
16651c0b2f7Stbbdev class adder_node : public tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > {
16751c0b2f7Stbbdev public:
16851c0b2f7Stbbdev     tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j;
16951c0b2f7Stbbdev     tbb::flow::function_node< std::tuple< int, int >, int > f;
17051c0b2f7Stbbdev private:
17151c0b2f7Stbbdev     typedef tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > base_type;
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev     struct f_body {
operator ()adder_node::f_body17451c0b2f7Stbbdev         int operator()( const std::tuple< int, int > &t ) {
17551c0b2f7Stbbdev             return std::get<0>(t) + std::get<1>(t);
17651c0b2f7Stbbdev         }
17751c0b2f7Stbbdev     };
17851c0b2f7Stbbdev 
17951c0b2f7Stbbdev public:
adder_node(tbb::flow::graph & g,bool hidden=false)18051c0b2f7Stbbdev     adder_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), j(g), f(g, tbb::flow::unlimited, f_body() ) {
18151c0b2f7Stbbdev         tbb::flow::make_edge( j, f );
18251c0b2f7Stbbdev 
18351c0b2f7Stbbdev         base_type::set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j)), base_type::output_ports_type(f));
18451c0b2f7Stbbdev 
18551c0b2f7Stbbdev         if (hidden)
18651c0b2f7Stbbdev             base_type::add_nodes(j, f);
18751c0b2f7Stbbdev         else
18851c0b2f7Stbbdev             base_type::add_visible_nodes(j, f);
18951c0b2f7Stbbdev 
19051c0b2f7Stbbdev     }
19151c0b2f7Stbbdev };
19251c0b2f7Stbbdev 
operator ()square_body19351c0b2f7Stbbdev struct square_body { int operator()(int v) { return v*v; } };
operator ()cube_body19451c0b2f7Stbbdev struct cube_body { int operator()(int v) { return v*v*v; } };
adder_sum(int i)19551c0b2f7Stbbdev int adder_sum(int i) {
19651c0b2f7Stbbdev     return (int)(pow(3*pow(i,3) + pow(i, 2),2));
19751c0b2f7Stbbdev }
test_adder(bool hidden=false)19851c0b2f7Stbbdev int test_adder(bool hidden = false) {
19951c0b2f7Stbbdev     tbb::flow::graph g;
20051c0b2f7Stbbdev     tbb::flow::function_node<int,int> s(g, tbb::flow::unlimited, square_body());
20151c0b2f7Stbbdev     tbb::flow::function_node<int,int> c(g, tbb::flow::unlimited, cube_body());
20251c0b2f7Stbbdev     tbb::flow::function_node<int,int> p(g, tbb::flow::unlimited, passthru_body());
20351c0b2f7Stbbdev 
20451c0b2f7Stbbdev     adder_node a0(g, hidden);
20551c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(a0) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a0");
20651c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<1>(a0) == &tbb::flow::input_port<1>(a0.j)), "input_port 1 of j not bound to input port 1 in composite_node a0");
20751c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(a0) == &a0.f), "f not bound to output port 0 in composite_node a0");
20851c0b2f7Stbbdev 
20951c0b2f7Stbbdev     adder_node a1(g, hidden);
21051c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a0.input_ports()) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a1");
21151c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<1>(a0.input_ports()) == &tbb::flow::input_port<1>(a0.j)), "input_port1 of j not bound to input port 1 in composite_node a1");
21251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a0.output_ports()) == &a0.f), "f not bound to output port 0 in composite_node a1");
21351c0b2f7Stbbdev 
21451c0b2f7Stbbdev     adder_node a2(g, hidden);
21551c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(a2) == &tbb::flow::input_port<0>(a2.j)), "input_port 0 of j not bound to input port 0 in composite_node a2");
21651c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<1>(a2) == &tbb::flow::input_port<1>(a2.j)), "input_port 1 of j not bound to input port 1 in composite_node a2");
21751c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(a2) == &a2.f), "f not bound to output port 0 in composite_node a2");
21851c0b2f7Stbbdev 
21951c0b2f7Stbbdev     adder_node a3(g, hidden);
22051c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a3.input_ports()) == &tbb::flow::input_port<0>(a3.j)), "input_port 0 of j not bound to input port 0 in composite_node a3");
22151c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<1>(a3.input_ports()) == &tbb::flow::input_port<1>(a3.j)), "input_port1 of j not bound to input port 1 in composite_node a3");
22251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a3.output_ports()) == &a3.f), "f not bound to output port 0 in composite_node a3");
22351c0b2f7Stbbdev 
22451c0b2f7Stbbdev     tbb::flow::function_node<int,int> s2(g, tbb::flow::unlimited, square_body());
22551c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
22651c0b2f7Stbbdev 
22751c0b2f7Stbbdev     tbb::flow::make_edge( s, tbb::flow::input_port<0>(a0) );
22851c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<1>(a0) );
22951c0b2f7Stbbdev 
23051c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<0>(a1) );
23151c0b2f7Stbbdev     tbb::flow::make_edge( c, tbb::flow::input_port<1>(a1) );
23251c0b2f7Stbbdev 
23351c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a0), tbb::flow::input_port<0>(a2) );
23451c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a1), tbb::flow::input_port<1>(a2) );
23551c0b2f7Stbbdev 
23651c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(a2), s2 );
23751c0b2f7Stbbdev     tbb::flow::make_edge( s2, q );
23851c0b2f7Stbbdev 
23951c0b2f7Stbbdev     int sum_total=0;
24051c0b2f7Stbbdev     int result=0;
24151c0b2f7Stbbdev     for ( int i = 1; i < 4; ++i ) {
24251c0b2f7Stbbdev         s.try_put(i);
24351c0b2f7Stbbdev         c.try_put(i);
24451c0b2f7Stbbdev         sum_total += adder_sum(i);
24551c0b2f7Stbbdev         g.wait_for_all();
24651c0b2f7Stbbdev     }
24751c0b2f7Stbbdev 
24851c0b2f7Stbbdev     int j;
24951c0b2f7Stbbdev     for ( int i = 1; i < 4; ++i ) {
25051c0b2f7Stbbdev         q.try_get(j);
25151c0b2f7Stbbdev         result += j;
25251c0b2f7Stbbdev     }
25351c0b2f7Stbbdev     g.wait_for_all();
25451c0b2f7Stbbdev     CHECK_MESSAGE( (result == sum_total), "the sum from the graph does not match the calculated value");
25551c0b2f7Stbbdev 
25651c0b2f7Stbbdev     tbb::flow::remove_edge(s2, q);
25751c0b2f7Stbbdev     tbb::flow::remove_edge( a2, s2 );
25851c0b2f7Stbbdev     tbb::flow::make_edge( a0, a3 );
25951c0b2f7Stbbdev     tbb::flow::make_edge( a1, tbb::flow::input_port<1>(a3) );
26051c0b2f7Stbbdev     tbb::flow::make_edge( a3, s2 );
26151c0b2f7Stbbdev     tbb::flow::make_edge( s2, q );
26251c0b2f7Stbbdev 
26351c0b2f7Stbbdev     sum_total=0;
26451c0b2f7Stbbdev     result=0;
26551c0b2f7Stbbdev     for ( int i = 10; i < 20; ++i ) {
26651c0b2f7Stbbdev         s.try_put(i);
26751c0b2f7Stbbdev         c.try_put(i);
26851c0b2f7Stbbdev         sum_total += adder_sum(i);
26951c0b2f7Stbbdev         g.wait_for_all();
27051c0b2f7Stbbdev     }
27151c0b2f7Stbbdev 
27251c0b2f7Stbbdev     for ( int i = 10; i < 20; ++i ) {
27351c0b2f7Stbbdev         q.try_get(j);
27451c0b2f7Stbbdev         result += j;
27551c0b2f7Stbbdev     }
27651c0b2f7Stbbdev     g.wait_for_all();
27751c0b2f7Stbbdev     CHECK_MESSAGE( (result == sum_total), "the new sum after the replacement of the nodes does not match the calculated value");
27851c0b2f7Stbbdev 
27951c0b2f7Stbbdev     return 0;
28051c0b2f7Stbbdev }
28151c0b2f7Stbbdev 
28251c0b2f7Stbbdev /*
28351c0b2f7Stbbdev                                               outer composite node (outer_node)
28451c0b2f7Stbbdev                                      |-------------------------------------------------------------------|
28551c0b2f7Stbbdev                                      |                                                                   |
28651c0b2f7Stbbdev                                      |  |------------------|  |------------------|  |------------------| |
28751c0b2f7Stbbdev              |---------------------| |--| inner composite  | /| inner composite  | /| inner composite  | | |-------------------|
28851c0b2f7Stbbdev              |broadcast node(input)|/|  | node             |/ | node             |/ | node             |-+-| queue node(output)|
28951c0b2f7Stbbdev              |---------------------|\|  |(inner_node1)     |\ | (inner_node2)    |\ | (inner_node3)    | | |-------------------|
29051c0b2f7Stbbdev                                      |--|                  | \|                  | \|                  | |
29151c0b2f7Stbbdev                                      |  |------------------|  |------------------|  |------------------| |
29251c0b2f7Stbbdev                                      |                                                                   |
29351c0b2f7Stbbdev                                      |-------------------------------------------------------------------|
29451c0b2f7Stbbdev 
29551c0b2f7Stbbdev */
test_nested_adder(bool hidden=false)29651c0b2f7Stbbdev int test_nested_adder(bool hidden=false) {
29751c0b2f7Stbbdev     tbb::flow::graph g;
29851c0b2f7Stbbdev     tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > outer_node(g);
29951c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > base_type;
30051c0b2f7Stbbdev     tbb::flow::broadcast_node<int> input(g);
30151c0b2f7Stbbdev     tbb::flow::queue_node<int> output(g);
30251c0b2f7Stbbdev 
30351c0b2f7Stbbdev     adder_node inner_node1(g, hidden);
30451c0b2f7Stbbdev     adder_node inner_node2(g, hidden);
30551c0b2f7Stbbdev     adder_node inner_node3(g, hidden);
30651c0b2f7Stbbdev 
30751c0b2f7Stbbdev     outer_node.set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(inner_node1), tbb::flow::input_port<1>(inner_node1)), base_type::output_ports_type(tbb::flow::output_port<0>(inner_node3)));
30851c0b2f7Stbbdev 
30951c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<0>(outer_node) == &tbb::flow::input_port<0>(inner_node1)), "input port 0 of inner_node1 not bound to input port 0 in outer_node");
31051c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<1>(outer_node) == &tbb::flow::input_port<1>(inner_node1)), "input port 1 of inner_node1 not bound to input port 1 in outer_node");
31151c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<0>(outer_node) == &tbb::flow::output_port<0>(inner_node3)), "output port 0 of inner_node3 not bound to output port 0 in outer_node");
31251c0b2f7Stbbdev 
31351c0b2f7Stbbdev     tbb::flow::make_edge(input, tbb::flow::input_port<0>(outer_node)/*inner_node1*/);
31451c0b2f7Stbbdev     tbb::flow::make_edge(input, tbb::flow::input_port<1>(outer_node)/*inner_node1*/);
31551c0b2f7Stbbdev 
31651c0b2f7Stbbdev     tbb::flow::make_edge(inner_node1, tbb::flow::input_port<0>(inner_node2));
31751c0b2f7Stbbdev     tbb::flow::make_edge(inner_node1, tbb::flow::input_port<1>(inner_node2));
31851c0b2f7Stbbdev 
31951c0b2f7Stbbdev     tbb::flow::make_edge(inner_node2, tbb::flow::input_port<0>(inner_node3));
32051c0b2f7Stbbdev     tbb::flow::make_edge(inner_node2, tbb::flow::input_port<1>(inner_node3));
32151c0b2f7Stbbdev 
32251c0b2f7Stbbdev     tbb::flow::make_edge(outer_node/*inner_node3*/, output);
32351c0b2f7Stbbdev 
32451c0b2f7Stbbdev     if(hidden)
32551c0b2f7Stbbdev         outer_node.add_nodes(inner_node1, inner_node2, inner_node3);
32651c0b2f7Stbbdev     else
32751c0b2f7Stbbdev         outer_node.add_visible_nodes(inner_node1, inner_node2, inner_node3);
32851c0b2f7Stbbdev 
32951c0b2f7Stbbdev     int out;
33051c0b2f7Stbbdev     for (int i = 1; i < 200000; ++i) {
33151c0b2f7Stbbdev         input.try_put(i);
33251c0b2f7Stbbdev         g.wait_for_all();
33351c0b2f7Stbbdev         output.try_get(out);
33451c0b2f7Stbbdev         CHECK_MESSAGE( (tbb::flow::output_port<0>(outer_node).try_get(out) == output.try_get(out)), "output from outer_node does not match output from graph");
33551c0b2f7Stbbdev         CHECK_MESSAGE( (out == 8*i), "output from outer_node not correct");
33651c0b2f7Stbbdev     }
33751c0b2f7Stbbdev     g.wait_for_all();
33851c0b2f7Stbbdev 
33951c0b2f7Stbbdev     return 0;
34051c0b2f7Stbbdev }
34151c0b2f7Stbbdev 
34251c0b2f7Stbbdev template< typename T >
34351c0b2f7Stbbdev class prefix_node : public tbb::flow::composite_node< std::tuple< T, T, T, T, T >, std::tuple< T, T, T, T, T > > {
34451c0b2f7Stbbdev     typedef std::tuple< T, T, T, T, T > my_tuple_t;
34551c0b2f7Stbbdev public:
34651c0b2f7Stbbdev     tbb::flow::join_node< my_tuple_t, tbb::flow::queueing > j;
34751c0b2f7Stbbdev     tbb::flow::split_node< my_tuple_t > s;
34851c0b2f7Stbbdev private:
34951c0b2f7Stbbdev     tbb::flow::function_node< my_tuple_t, my_tuple_t > f;
35051c0b2f7Stbbdev     typedef tbb::flow::composite_node< my_tuple_t, my_tuple_t > base_type;
35151c0b2f7Stbbdev 
35251c0b2f7Stbbdev     struct f_body {
operator ()prefix_node::f_body35351c0b2f7Stbbdev         my_tuple_t operator()( const my_tuple_t &t ) {
35451c0b2f7Stbbdev             return my_tuple_t( std::get<0>(t),
35551c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t),
35651c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t),
35751c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t),
35851c0b2f7Stbbdev                                std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t) + std::get<4>(t) );
35951c0b2f7Stbbdev         }
36051c0b2f7Stbbdev     };
36151c0b2f7Stbbdev 
36251c0b2f7Stbbdev public:
prefix_node(tbb::flow::graph & g,bool hidden=false)36351c0b2f7Stbbdev     prefix_node(tbb::flow::graph &g, bool hidden = false ) : base_type(g), j(g), s(g), f(g, tbb::flow::serial, f_body() ) {
36451c0b2f7Stbbdev         tbb::flow::make_edge( j, f );
36551c0b2f7Stbbdev         tbb::flow::make_edge( f, s );
36651c0b2f7Stbbdev 
36751c0b2f7Stbbdev     typename base_type::input_ports_type input_tuple(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j), tbb::flow::input_port<2>(j), tbb::flow::input_port<3>(j), tbb::flow::input_port<4>(j));
36851c0b2f7Stbbdev 
36951c0b2f7Stbbdev     typename base_type::output_ports_type output_tuple(tbb::flow::output_port<0>(s), tbb::flow::output_port<1>(s), tbb::flow::output_port<2>(s), tbb::flow::output_port<3>(s), tbb::flow::output_port<4>(s));
37051c0b2f7Stbbdev 
37151c0b2f7Stbbdev     base_type::set_external_ports(input_tuple, output_tuple);
37251c0b2f7Stbbdev 
37351c0b2f7Stbbdev         if(hidden)
37451c0b2f7Stbbdev             base_type::add_nodes(j,s,f);
37551c0b2f7Stbbdev         else
37651c0b2f7Stbbdev             base_type::add_visible_nodes(j,s,f);
37751c0b2f7Stbbdev 
37851c0b2f7Stbbdev     }
37951c0b2f7Stbbdev };
38051c0b2f7Stbbdev 
test_prefix(bool hidden=false)38151c0b2f7Stbbdev int test_prefix(bool hidden = false) {
38251c0b2f7Stbbdev     tbb::flow::graph g;
38351c0b2f7Stbbdev     prefix_node<double> p(g, hidden);
38451c0b2f7Stbbdev 
38551c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(p.input_ports()) == &tbb::flow::input_port<0>(p.j)), "input port 0 of j is not bound to input port 0 of composite node p");
38651c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<1>(p.j) == &tbb::flow::input_port<1>(p.j)), "input port 1 of j is not bound to input port 1 of composite node p");
38751c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<2>(p.input_ports()) == &tbb::flow::input_port<2>(p.j)), "input port 2 of j is not bound to input port 2 of composite node p");
38851c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::input_port<3>(p.j) == &tbb::flow::input_port<3>(p.j)), "input port 3 of j is not bound to input port 3 of composite node p");
38951c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<4>(p.input_ports()) == &tbb::flow::input_port<4>(p.j)), "input port 4 of j is not bound to input port 4 of composite node p");
39051c0b2f7Stbbdev 
39151c0b2f7Stbbdev 
39251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(p.output_ports()) == &tbb::flow::output_port<0>(p.s)), "output port 0 of s is not bound to output port 0 of composite node p");
39351c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<1>(p.s) == &tbb::flow::output_port<1>(p.s)), "output port 1 of s is not bound to output port 1 of composite node p");
39451c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<2>(p.output_ports()) == &tbb::flow::output_port<2>(p.s)), "output port 2 of s is not bound to output port 2 of composite node p");
39551c0b2f7Stbbdev     CHECK_MESSAGE( (&tbb::flow::output_port<3>(p.s) == &tbb::flow::output_port<3>(p.s)), "output port 3 of s is not bound to output port 3 of composite node p");
39651c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<4>(p.output_ports()) == &tbb::flow::output_port<4>(p.s)), "output port 4 of s is not bound to output port 4 of composite node p");
39751c0b2f7Stbbdev 
39851c0b2f7Stbbdev     std::vector< tbb::flow::queue_node<double> > v( 5, tbb::flow::queue_node<double>(g) );
39951c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<0>(p), v[0] );
40051c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<1>(p), v[1] );
40151c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<2>(p), v[2] );
40251c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<3>(p), v[3] );
40351c0b2f7Stbbdev     tbb::flow::make_edge( tbb::flow::output_port<4>(p), v[4] );
40451c0b2f7Stbbdev 
40551c0b2f7Stbbdev     for(  double offset = 1; offset < 10000; offset *= 10 ) {
40651c0b2f7Stbbdev         tbb::flow::input_port<0>(p).try_put( offset );
40751c0b2f7Stbbdev         tbb::flow::input_port<1>(p).try_put( offset + 1 );
40851c0b2f7Stbbdev         tbb::flow::input_port<2>(p).try_put( offset + 2 );
40951c0b2f7Stbbdev         tbb::flow::input_port<3>(p).try_put( offset + 3 );
41051c0b2f7Stbbdev         tbb::flow::input_port<4>(p).try_put( offset + 4 );
41151c0b2f7Stbbdev     }
41251c0b2f7Stbbdev     g.wait_for_all();
41351c0b2f7Stbbdev 
41451c0b2f7Stbbdev     double x;
41551c0b2f7Stbbdev     while ( v[0].try_get(x) ) {
41651c0b2f7Stbbdev         g.wait_for_all();
41751c0b2f7Stbbdev         for ( int i = 1; i < 5; ++i ) {
41851c0b2f7Stbbdev             v[i].try_get(x);
41951c0b2f7Stbbdev             g.wait_for_all();
42051c0b2f7Stbbdev         }
42151c0b2f7Stbbdev     }
42251c0b2f7Stbbdev     return 0;
42351c0b2f7Stbbdev }
42451c0b2f7Stbbdev 
42551c0b2f7Stbbdev struct input_only_output_only_seq {
operator ()input_only_output_only_seq426*478de5b1Stbbdev     std::size_t operator()(int i) {
427*478de5b1Stbbdev         CHECK(i > 0);
428*478de5b1Stbbdev         return std::size_t((i + 3) / 4 - 1);
429*478de5b1Stbbdev     }
43051c0b2f7Stbbdev };
43151c0b2f7Stbbdev 
input_only_output_only_composite(bool hidden)43251c0b2f7Stbbdev void input_only_output_only_composite(bool hidden) {
43351c0b2f7Stbbdev     tbb::flow::graph g;
43451c0b2f7Stbbdev 
43551c0b2f7Stbbdev     tbb::flow::composite_node<std::tuple<int>, std::tuple<int> > input_output(g);
43651c0b2f7Stbbdev 
43751c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<int>, std::tuple<> > input_only_composite;
43851c0b2f7Stbbdev     typedef tbb::flow::composite_node<std::tuple<>, std::tuple<int> > output_only_composite;
43951c0b2f7Stbbdev 
44051c0b2f7Stbbdev     typedef tbb::flow::input_node<int> src_type;
44151c0b2f7Stbbdev     typedef tbb::flow::queue_node<int> q_type;
44251c0b2f7Stbbdev     typedef tbb::flow::function_node<int, int> f_type;
44351c0b2f7Stbbdev     typedef tbb::flow::sequencer_node<int> sequencer_type;
44451c0b2f7Stbbdev 
44551c0b2f7Stbbdev     int num = 0;
44651c0b2f7Stbbdev     int finish=1000;
44751c0b2f7Stbbdev     int step = 4;
44851c0b2f7Stbbdev 
44951c0b2f7Stbbdev     input_only_composite a_in(g);
45051c0b2f7Stbbdev     output_only_composite a_out(g);
45151c0b2f7Stbbdev 
45251c0b2f7Stbbdev     src_type src(g, my_input_body(finish, step));
45351c0b2f7Stbbdev     q_type que(g);
45451c0b2f7Stbbdev     f_type f(g, 1, passthru_body());
45551c0b2f7Stbbdev 
45651c0b2f7Stbbdev     // Sequencer_node is needed, because serial function_node guarantees only serial body execution,
45751c0b2f7Stbbdev     // not a sequential order of messages dispatch
45851c0b2f7Stbbdev     sequencer_type seq(g, input_only_output_only_seq());
45951c0b2f7Stbbdev 
46051c0b2f7Stbbdev     std::tuple<f_type& > input_tuple(f);
46151c0b2f7Stbbdev     a_in.set_external_ports(input_tuple);
46251c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a_in.input_ports()) == &f), "f not bound to input port 0 in composite_node a_in");
46351c0b2f7Stbbdev 
46451c0b2f7Stbbdev     std::tuple<src_type&> output_tuple(src);
46551c0b2f7Stbbdev     a_out.set_external_ports(output_tuple);
46651c0b2f7Stbbdev     CHECK_MESSAGE( (&std::get<0>(a_out.output_ports()) == &src), "src not bound to output port 0 in composite_node a_out");
46751c0b2f7Stbbdev 
46851c0b2f7Stbbdev     if(hidden) {
46951c0b2f7Stbbdev         a_in.add_nodes(f, seq, que);
47051c0b2f7Stbbdev         a_out.add_nodes(src);
47151c0b2f7Stbbdev     } else {
47251c0b2f7Stbbdev         a_in.add_visible_nodes(f, seq, que);
47351c0b2f7Stbbdev         a_out.add_visible_nodes(src);
47451c0b2f7Stbbdev     }
47551c0b2f7Stbbdev 
47651c0b2f7Stbbdev     tbb::flow::make_edge(a_out, a_in);
47751c0b2f7Stbbdev     tbb::flow::make_edge(f, seq);
47851c0b2f7Stbbdev     tbb::flow::make_edge(seq, que);
47951c0b2f7Stbbdev     src.activate();
48051c0b2f7Stbbdev     g.wait_for_all();
48151c0b2f7Stbbdev 
48251c0b2f7Stbbdev     for(int i = 1; i<finish/step; ++i) {
48351c0b2f7Stbbdev         que.try_get(num);
48451c0b2f7Stbbdev         CHECK_MESSAGE( (num == 4*i - 3), "number does not match position in sequence");
48551c0b2f7Stbbdev     }
48651c0b2f7Stbbdev     g.wait_for_all();
48751c0b2f7Stbbdev }
48851c0b2f7Stbbdev 
48951c0b2f7Stbbdev //! Test single node inside composite nodes
49051c0b2f7Stbbdev //! \brief \ref error_guessing
49151c0b2f7Stbbdev TEST_CASE("Tiny tests"){
49251c0b2f7Stbbdev     test_tiny(false);
49351c0b2f7Stbbdev     test_tiny(true);
49451c0b2f7Stbbdev }
49551c0b2f7Stbbdev 
49651c0b2f7Stbbdev //! Test basic adders in composite node
49751c0b2f7Stbbdev //! \brief \ref error_guessing
49851c0b2f7Stbbdev TEST_CASE("Adder tests"){
49951c0b2f7Stbbdev     test_adder(false);
50051c0b2f7Stbbdev     test_adder(true);
50151c0b2f7Stbbdev }
50251c0b2f7Stbbdev 
50351c0b2f7Stbbdev //! Test nested adders in composite node
50451c0b2f7Stbbdev //! \brief \ref error_guessing
50551c0b2f7Stbbdev TEST_CASE("Nested adder tests"){
50651c0b2f7Stbbdev     test_nested_adder(true);
50751c0b2f7Stbbdev     test_nested_adder(false);
50851c0b2f7Stbbdev }
50951c0b2f7Stbbdev 
51051c0b2f7Stbbdev //! Test returning a subset of inputs
51151c0b2f7Stbbdev //! \brief \ref error_guessing
51251c0b2f7Stbbdev TEST_CASE("Prefix test"){
51351c0b2f7Stbbdev     test_prefix(false);
51451c0b2f7Stbbdev     test_prefix(true);
51551c0b2f7Stbbdev }
51651c0b2f7Stbbdev 
51751c0b2f7Stbbdev //! Test input-only composite node
51851c0b2f7Stbbdev //! \brief \ref error_guessing \ref boundary
51951c0b2f7Stbbdev TEST_CASE("Input-only composite"){
52051c0b2f7Stbbdev     input_only_output_only_composite(true);
52151c0b2f7Stbbdev     input_only_output_only_composite(false);
52251c0b2f7Stbbdev }
52351c0b2f7Stbbdev 
524