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