1 /*
2     Copyright (c) 2020-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #if __INTEL_COMPILER && _MSC_VER
18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19 #endif
20 
21 #include "conformance_flowgraph.h"
22 
23 //! \file conformance_composite_node.cpp
24 //! \brief Test for [flow_graph.composite_node] specification
25 
26 class adder : public oneapi::tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int>> {
27     oneapi::tbb::flow::join_node<std::tuple<int,int>, oneapi::tbb::flow::queueing> j;
28     oneapi::tbb::flow::function_node<std::tuple<int,int>, int> f;
29     oneapi::tbb::flow::queue_node<int> qn;
30     using base_type = oneapi::tbb::flow::composite_node<std::tuple<int,int>, std::tuple<int>>;
31 
32     struct f_body {
operator ()adder::f_body33         int operator()(const std::tuple<int,int> &t) {
34             int sum = std::get<0>(t) + std::get<1>(t);
35             return  sum;
36         }
37     };
38 
39 public:
adder(oneapi::tbb::flow::graph & g)40     adder(oneapi::tbb::flow::graph &g) : base_type(g), j(g), f(g, oneapi::tbb::flow::unlimited, f_body()), qn(g) {
41         make_edge(j, f);
42         make_edge(f, qn);
43 
44         base_type::input_ports_type input_tuple(oneapi::tbb::flow::input_port<0>(j), oneapi::tbb::flow::input_port<1>(j));
45         base_type::output_ports_type output_tuple(qn);
46         base_type::set_external_ports(input_tuple, output_tuple);
47     }
48 };
49 
50 template<int N, typename T1, typename T2>
51 struct compare {
compare_refscompare52     static void compare_refs(T1 tuple1, T2 tuple2) {
53     CHECK_MESSAGE(( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly");
54     compare<N-1, T1, T2>::compare_refs(tuple1, tuple2);
55     }
56 };
57 
58 template<typename T1, typename T2>
59 struct compare<1, T1, T2> {
compare_refscompare60     static void compare_refs(T1 tuple1, T2 tuple2) {
61     CHECK_MESSAGE((&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set");
62     }
63 };
64 
65 //! Test inheritance relations
66 //! \brief \ref interface
67 TEST_CASE("composite_node superclasses"){
68     CHECK_MESSAGE((std::is_base_of<oneapi::tbb::flow::graph_node, adder>::value), "composite_node should be derived from graph_node");
69 }
70 
71 //! Test composite_node ports
72 //! \brief \ref interface \ref requirement
73 TEST_CASE("composite_node ports"){
74     oneapi::tbb::flow::graph g;
75 
76     using InputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, int, int, int, int,
77                              int, int, int, int, int, int, int, int>;
78 
79     using OutputTupleType = std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, oneapi::tbb::flow::tagged_msg<size_t, int, float>,
80                              int, int, int, int, int, int, int, int, int, int, int, int>;
81 
82     using EmptyTupleType= std::tuple<>;
83 
84     using input_output_type = oneapi::tbb::flow::composite_node<InputTupleType, OutputTupleType>;
85     using input_only_type = oneapi::tbb::flow::composite_node<InputTupleType, EmptyTupleType>;
86     using output_only_type = oneapi::tbb::flow::composite_node<EmptyTupleType, OutputTupleType>;
87 
88     const size_t NUM_INPUTS = std::tuple_size<InputTupleType>::value;
89     const size_t NUM_OUTPUTS = std::tuple_size<OutputTupleType>::value;
90 
91     using body = conformance::dummy_functor<int>;
92 
93     //node types
94     oneapi::tbb::flow::continue_node<tbb::flow::continue_msg> ct(g, body());
95     oneapi::tbb::flow::split_node< std::tuple<int, int> > s(g);
96     oneapi::tbb::flow::input_node<int> src(g, body());
97     oneapi::tbb::flow::function_node<int, int> fxn(g, oneapi::tbb::flow::unlimited, body());
98     oneapi::tbb::flow::multifunction_node<int, std::tuple<int, int> > m_fxn(g, oneapi::tbb::flow::unlimited, body());
99     oneapi::tbb::flow::broadcast_node<int> bc(g);
100     oneapi::tbb::flow::limiter_node<int> lim(g, 2);
101     oneapi::tbb::flow::indexer_node<int, float> ind(g);
102     oneapi::tbb::flow::join_node< std::tuple< int, int >, oneapi::tbb::flow::queueing > j(g);
103     oneapi::tbb::flow::queue_node<int> q(g);
104     oneapi::tbb::flow::buffer_node<int> bf(g);
105     oneapi::tbb::flow::priority_queue_node<int> pq(g);
106     oneapi::tbb::flow::write_once_node<int> wo(g);
107     oneapi::tbb::flow::overwrite_node<int> ovw(g);
108     oneapi::tbb::flow::sequencer_node<int> seq(g, conformance::sequencer_functor<int>());
109 
110     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                                 pq, ovw, wo, bf, seq);
112     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                                  q, pq, ovw, wo, bf, seq);
114 
115     //composite_node with both input_ports and output_ports
116     input_output_type a_node(g);
117     a_node.set_external_ports(input_tuple, output_tuple);
118 
119     a_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
120     a_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
121 
122     auto a_node_input_ports_ptr = a_node.input_ports();
123     compare<NUM_INPUTS-1, decltype(a_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(a_node_input_ports_ptr, input_tuple);
124     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(a_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
125 
126     auto a_node_output_ports_ptr = a_node.output_ports();
127     compare<NUM_OUTPUTS-1, decltype(a_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(a_node_output_ports_ptr, output_tuple);
128     CHECK_MESSAGE((NUM_OUTPUTS == std::tuple_size<decltype(a_node_output_ports_ptr)>::value), "not all declared output ports were bound to nodes");
129 
130     //composite_node with only input_ports
131     input_only_type b_node(g);
132     b_node.set_external_ports(input_tuple);
133 
134     b_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
135     b_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
136 
137     auto b_node_input_ports_ptr = b_node.input_ports();
138     compare<NUM_INPUTS-1, decltype(b_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(b_node_input_ports_ptr, input_tuple);
139     CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(b_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes");
140 
141     //composite_node with only output_ports
142     output_only_type c_node(g);
143     c_node.set_external_ports(output_tuple);
144 
145     // Reset is not suppose to do anything. Check that it can be called.
146     g.reset();
147 
148     c_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
149 
150     c_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq);
151 
152     auto c_node_output_ports_ptr = c_node.output_ports();
153     compare<NUM_OUTPUTS-1, decltype(c_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(c_node_output_ports_ptr, output_tuple);
154     CHECK_MESSAGE(NUM_OUTPUTS == std::tuple_size<decltype(c_node_output_ports_ptr)>::value, "not all declared input ports were bound to nodes");
155 }
156 
157 //! Test composite_node construction and message passing
158 //! \brief \ref interface \ref requirement
159 TEST_CASE("composite_node construction and message test"){
160     using namespace oneapi::tbb::flow;
161     graph g;
162     split_node<std::tuple<int, int, int, int>> s(g);
163     adder a0(g);
164     adder a1(g);
165     adder a2(g);
166 
167     make_edge(output_port<0>(s), input_port<0>(a0));
168     make_edge(output_port<1>(s), input_port<1>(a0));
169 
170     make_edge(output_port<0>(a0),input_port<0>(a1));
171     make_edge(output_port<2>(s), input_port<1>(a1));
172 
173     make_edge(output_port<0>(a1), input_port<0>(a2));
174     make_edge(output_port<3>(s), input_port<1>(a2));
175 
176     s.try_put(std::make_tuple(1,3,5,7));
177     g.wait_for_all();
178 
179     int tmp = -1;
180     CHECK_MESSAGE((output_port<0>(a2).try_get(tmp) == true), "Composite node should produce a value");
181     CHECK_MESSAGE((tmp == 1+3+5+7), "Composite node should produce correct sum");
182 }
183