151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2020-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
2051c0b2f7Stbbdev 
2151c0b2f7Stbbdev #include "conformance_flowgraph.h"
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev //! \file conformance_composite_node.cpp
2451c0b2f7Stbbdev //! \brief Test for [flow_graph.composite_node] specification
2551c0b2f7Stbbdev 
26*de0109beSIlya Mishin class adder : public oneapi::tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int>> {
27*de0109beSIlya Mishin     oneapi::tbb::flow::join_node<std::tuple<int,int>, oneapi::tbb::flow::queueing> j;
28*de0109beSIlya Mishin     oneapi::tbb::flow::function_node<std::tuple<int,int>, int> f;
29*de0109beSIlya Mishin     oneapi::tbb::flow::queue_node<int> qn;
30*de0109beSIlya Mishin     using base_type = oneapi::tbb::flow::composite_node<std::tuple<int,int>, std::tuple<int>>;
3151c0b2f7Stbbdev 
3251c0b2f7Stbbdev     struct f_body {
operator ()adder::f_body33*de0109beSIlya Mishin         int operator()(const std::tuple<int,int> &t) {
34*de0109beSIlya Mishin             int sum = std::get<0>(t) + std::get<1>(t);
3551c0b2f7Stbbdev             return  sum;
3651c0b2f7Stbbdev         }
3751c0b2f7Stbbdev     };
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev public:
adder(oneapi::tbb::flow::graph & g)40*de0109beSIlya Mishin     adder(oneapi::tbb::flow::graph &g) : base_type(g), j(g), f(g, oneapi::tbb::flow::unlimited, f_body()), qn(g) {
4151c0b2f7Stbbdev         make_edge(j, f);
4251c0b2f7Stbbdev         make_edge(f, qn);
4351c0b2f7Stbbdev 
44*de0109beSIlya Mishin         base_type::input_ports_type input_tuple(oneapi::tbb::flow::input_port<0>(j), oneapi::tbb::flow::input_port<1>(j));
4551c0b2f7Stbbdev         base_type::output_ports_type output_tuple(qn);
4651c0b2f7Stbbdev         base_type::set_external_ports(input_tuple, output_tuple);
4751c0b2f7Stbbdev     }
4851c0b2f7Stbbdev };
4951c0b2f7Stbbdev 
50*de0109beSIlya Mishin template<int N, typename T1, typename T2>
51*de0109beSIlya Mishin struct compare {
compare_refscompare52*de0109beSIlya Mishin     static void compare_refs(T1 tuple1, T2 tuple2) {
53*de0109beSIlya Mishin     CHECK_MESSAGE(( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly");
54*de0109beSIlya Mishin     compare<N-1, T1, T2>::compare_refs(tuple1, tuple2);
5551c0b2f7Stbbdev     }
56*de0109beSIlya Mishin };
57*de0109beSIlya Mishin 
58*de0109beSIlya Mishin template<typename T1, typename T2>
59*de0109beSIlya Mishin struct compare<1, T1, T2> {
compare_refscompare60*de0109beSIlya Mishin     static void compare_refs(T1 tuple1, T2 tuple2) {
61*de0109beSIlya Mishin     CHECK_MESSAGE((&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set");
62*de0109beSIlya Mishin     }
63*de0109beSIlya Mishin };
6451c0b2f7Stbbdev 
6551c0b2f7Stbbdev //! Test inheritance relations
6651c0b2f7Stbbdev //! \brief \ref interface
6751c0b2f7Stbbdev TEST_CASE("composite_node superclasses"){
68*de0109beSIlya Mishin     CHECK_MESSAGE((std::is_base_of<oneapi::tbb::flow::graph_node, adder>::value), "composite_node should be derived from graph_node");
6951c0b2f7Stbbdev }
7051c0b2f7Stbbdev 
71*de0109beSIlya Mishin //! Test composite_node ports
7251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
73*de0109beSIlya Mishin TEST_CASE("composite_node ports"){
74*de0109beSIlya Mishin     oneapi::tbb::flow::graph g;
75*de0109beSIlya Mishin 
76*de0109beSIlya Mishin     using InputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, int, int, int, int,
77*de0109beSIlya Mishin                              int, int, int, int, int, int, int, int>;
78*de0109beSIlya Mishin 
79*de0109beSIlya Mishin     using OutputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, oneapi::tbb::flow::tagged_msg<size_t, int, float>,
80*de0109beSIlya Mishin                              int, int, int, int, int, int, int, int, int, int, int, int>;
81*de0109beSIlya Mishin 
82*de0109beSIlya Mishin     using EmptyTupleType= std::tuple<>;
83*de0109beSIlya Mishin 
84*de0109beSIlya Mishin     using input_output_type = oneapi::tbb::flow::composite_node<InputTupleType, OutputTupleType>;
85*de0109beSIlya Mishin     using input_only_type = oneapi::tbb::flow::composite_node<InputTupleType, EmptyTupleType>;
86*de0109beSIlya Mishin     using output_only_type = oneapi::tbb::flow::composite_node<EmptyTupleType, OutputTupleType>;
87*de0109beSIlya Mishin 
88*de0109beSIlya Mishin     const size_t NUM_INPUTS = std::tuple_size<InputTupleType>::value;
89*de0109beSIlya Mishin     const size_t NUM_OUTPUTS = std::tuple_size<OutputTupleType>::value;
90*de0109beSIlya Mishin 
91*de0109beSIlya Mishin     using body = conformance::dummy_functor<int>;
92*de0109beSIlya Mishin 
93*de0109beSIlya Mishin     //node types
94*de0109beSIlya Mishin     oneapi::tbb::flow::continue_node<tbb::flow::continue_msg> ct(g, body());
95*de0109beSIlya Mishin     oneapi::tbb::flow::split_node< std::tuple<int, int> > s(g);
96*de0109beSIlya Mishin     oneapi::tbb::flow::input_node<int> src(g, body());
97*de0109beSIlya Mishin     oneapi::tbb::flow::function_node<int, int> fxn(g, oneapi::tbb::flow::unlimited, body());
98*de0109beSIlya Mishin     oneapi::tbb::flow::multifunction_node<int, std::tuple<int, int> > m_fxn(g, oneapi::tbb::flow::unlimited, body());
99*de0109beSIlya Mishin     oneapi::tbb::flow::broadcast_node<int> bc(g);
100*de0109beSIlya Mishin     oneapi::tbb::flow::limiter_node<int> lim(g, 2);
101*de0109beSIlya Mishin     oneapi::tbb::flow::indexer_node<int, float> ind(g);
102*de0109beSIlya Mishin     oneapi::tbb::flow::join_node< std::tuple< int, int >, oneapi::tbb::flow::queueing > j(g);
103*de0109beSIlya Mishin     oneapi::tbb::flow::queue_node<int> q(g);
104*de0109beSIlya Mishin     oneapi::tbb::flow::buffer_node<int> bf(g);
105*de0109beSIlya Mishin     oneapi::tbb::flow::priority_queue_node<int> pq(g);
106*de0109beSIlya Mishin     oneapi::tbb::flow::write_once_node<int> wo(g);
107*de0109beSIlya Mishin     oneapi::tbb::flow::overwrite_node<int> ovw(g);
108*de0109beSIlya Mishin     oneapi::tbb::flow::sequencer_node<int> seq(g, conformance::sequencer_functor<int>());
109*de0109beSIlya Mishin 
110*de0109beSIlya Mishin     auto input_tuple = std::tie(ct, s, m_fxn, fxn, bc, oneapi::tbb::flow::input_port<0>(j), lim, q, oneapi::tbb::flow::input_port<0>(ind),
111*de0109beSIlya Mishin                                 pq, ovw, wo, bf, seq);
112*de0109beSIlya Mishin     auto output_tuple = std::tie(ct,j, ind, fxn, src, bc, oneapi::tbb::flow::output_port<0>(s), lim, oneapi::tbb::flow::output_port<0>(m_fxn),
113*de0109beSIlya Mishin                                  q, pq, ovw, wo, bf, seq);
114*de0109beSIlya Mishin 
115*de0109beSIlya Mishin     //composite_node with both input_ports and output_ports
116*de0109beSIlya Mishin     input_output_type a_node(g);
117*de0109beSIlya Mishin     a_node.set_external_ports(input_tuple, output_tuple);
118*de0109beSIlya Mishin 
119*de0109beSIlya Mishin     a_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
120*de0109beSIlya Mishin     a_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
121*de0109beSIlya Mishin 
122*de0109beSIlya Mishin     auto a_node_input_ports_ptr = a_node.input_ports();
123*de0109beSIlya Mishin     compare<NUM_INPUTS-1, decltype(a_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(a_node_input_ports_ptr, input_tuple);
124*de0109beSIlya Mishin     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(a_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
125*de0109beSIlya Mishin 
126*de0109beSIlya Mishin     auto a_node_output_ports_ptr = a_node.output_ports();
127*de0109beSIlya Mishin     compare<NUM_OUTPUTS-1, decltype(a_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(a_node_output_ports_ptr, output_tuple);
128*de0109beSIlya Mishin     CHECK_MESSAGE((NUM_OUTPUTS == std::tuple_size<decltype(a_node_output_ports_ptr)>::value), "not all declared output ports were bound to nodes");
129*de0109beSIlya Mishin 
130*de0109beSIlya Mishin     //composite_node with only input_ports
131*de0109beSIlya Mishin     input_only_type b_node(g);
132*de0109beSIlya Mishin     b_node.set_external_ports(input_tuple);
133*de0109beSIlya Mishin 
134*de0109beSIlya Mishin     b_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
135*de0109beSIlya Mishin     b_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
136*de0109beSIlya Mishin 
137*de0109beSIlya Mishin     auto b_node_input_ports_ptr = b_node.input_ports();
138*de0109beSIlya Mishin     compare<NUM_INPUTS-1, decltype(b_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(b_node_input_ports_ptr, input_tuple);
139*de0109beSIlya Mishin     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(b_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
140*de0109beSIlya Mishin 
141*de0109beSIlya Mishin     //composite_node with only output_ports
142*de0109beSIlya Mishin     output_only_type c_node(g);
143*de0109beSIlya Mishin     c_node.set_external_ports(output_tuple);
144*de0109beSIlya Mishin 
145*de0109beSIlya Mishin     // Reset is not suppose to do anything. Check that it can be called.
146*de0109beSIlya Mishin     g.reset();
147*de0109beSIlya Mishin 
148*de0109beSIlya Mishin     c_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
149*de0109beSIlya Mishin 
150*de0109beSIlya Mishin     c_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
151*de0109beSIlya Mishin 
152*de0109beSIlya Mishin     auto c_node_output_ports_ptr = c_node.output_ports();
153*de0109beSIlya Mishin     compare<NUM_OUTPUTS-1, decltype(c_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(c_node_output_ports_ptr, output_tuple);
154*de0109beSIlya Mishin     CHECK_MESSAGE(NUM_OUTPUTS == std::tuple_size<decltype(c_node_output_ports_ptr)>::value, "not all declared input ports were bound to nodes");
155*de0109beSIlya Mishin }
156*de0109beSIlya Mishin 
157*de0109beSIlya Mishin //! Test composite_node construction and message passing
158*de0109beSIlya Mishin //! \brief \ref interface \ref requirement
159*de0109beSIlya Mishin TEST_CASE("composite_node construction and message test"){
160*de0109beSIlya Mishin     using namespace oneapi::tbb::flow;
16151c0b2f7Stbbdev     graph g;
162*de0109beSIlya Mishin     split_node<std::tuple<int, int, int, int>> s(g);
16351c0b2f7Stbbdev     adder a0(g);
16451c0b2f7Stbbdev     adder a1(g);
16551c0b2f7Stbbdev     adder a2(g);
16651c0b2f7Stbbdev 
16751c0b2f7Stbbdev     make_edge(output_port<0>(s), input_port<0>(a0));
16851c0b2f7Stbbdev     make_edge(output_port<1>(s), input_port<1>(a0));
16951c0b2f7Stbbdev 
17051c0b2f7Stbbdev     make_edge(output_port<0>(a0),input_port<0>(a1));
17151c0b2f7Stbbdev     make_edge(output_port<2>(s), input_port<1>(a1));
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev     make_edge(output_port<0>(a1), input_port<0>(a2));
17451c0b2f7Stbbdev     make_edge(output_port<3>(s), input_port<1>(a2));
17551c0b2f7Stbbdev 
17651c0b2f7Stbbdev     s.try_put(std::make_tuple(1,3,5,7));
17751c0b2f7Stbbdev     g.wait_for_all();
17851c0b2f7Stbbdev 
17951c0b2f7Stbbdev     int tmp = -1;
18051c0b2f7Stbbdev     CHECK_MESSAGE((output_port<0>(a2).try_get(tmp) == true), "Composite node should produce a value");
18151c0b2f7Stbbdev     CHECK_MESSAGE((tmp == 1+3+5+7), "Composite node should produce correct sum");
18251c0b2f7Stbbdev }
183