1 /*
2 Copyright (c) 2005-2023 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 #include "common/config.h"
18
19 #include "test_join_node.h"
20
21 #include "common/concepts_common.h"
22
23 //! \file test_join_node_key_matching.cpp
24 //! \brief Test for [flow_graph.join_node] specification
25
26 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
test_deduction_guides()27 void test_deduction_guides() {
28 using namespace tbb::flow;
29 using tuple_type = std::tuple<int, int, double>;
30
31 graph g;
32 auto body_int = [](const int&)->int { return 1; };
33 auto body_double = [](const double&)->int { return 1; };
34
35 join_node j1(g, body_int, body_int, body_double);
36 static_assert(std::is_same_v<decltype(j1), join_node<tuple_type, key_matching<int>>>);
37
38 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
39 broadcast_node<int> b1(g), b2(g);
40 broadcast_node<double> b3(g);
41 broadcast_node<tuple_type> b4(g);
42
43 join_node j2(follows(b1, b2, b3), body_int, body_int, body_double);
44 static_assert(std::is_same_v<decltype(j2), join_node<tuple_type, key_matching<int>>>);
45
46 join_node j3(precedes(b4), body_int, body_int, body_double);
47 static_assert(std::is_same_v<decltype(j3), join_node<tuple_type, key_matching<int>>>);
48 #endif
49
50 join_node j4(j1);
51 static_assert(std::is_same_v<decltype(j4), join_node<tuple_type, key_matching<int>>>);
52 }
53 #endif
54
55 //! Test serial key matching on special input types
56 //! \brief \ref error_guessing
57 TEST_CASE("Serial test on tuples") {
58 INFO("key_matching\n");
59 generate_test<serial_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int> >::do_test();
60 generate_test<serial_test, std::tuple<MyKeyFirst<std::string, double>, MyKeySecond<std::string, float> >, tbb::flow::key_matching<std::string> >::do_test();
61 generate_test<serial_test, std::tuple<MyKeyFirst<std::string, double>, MyKeySecond<std::string, float>, MyKeyWithBrokenMessageKey<std::string, int> >, tbb::flow::key_matching<std::string&> >::do_test();
62 }
63
64 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
65 //! Test deduction guides
66 //! \brief \ref requirement
67 TEST_CASE("Test deduction guides"){
68 test_deduction_guides();
69 }
70 #endif
71
72 //! Test parallel key matching on special input types
73 //! \brief \ref error_guessing
74 TEST_CASE("Parallel test on tuples"){
75 generate_test<parallel_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int> >::do_test();
76 generate_test<parallel_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int&> >::do_test();
77 generate_test<parallel_test, std::tuple<MyKeyFirst<std::string, double>, MyKeySecond<std::string, float> >, tbb::flow::key_matching<std::string&> >::do_test();
78 }
79
80 #if __TBB_CPP20_CONCEPTS_PRESENT
81 template <std::size_t Count>
82 struct tuple_helper {
83 using type = decltype(std::tuple_cat(std::declval<std::tuple<int>>(), std::declval<typename tuple_helper<Count - 1>::type>()));
84 };
85
86 template <>
87 struct tuple_helper<1> {
88 using type = std::tuple<int>;
89 };
90
91 template <typename... Args>
92 concept can_initialize_join_node = requires(tbb::flow::graph& g, Args... args) {
93 tbb::flow::join_node<typename tuple_helper<sizeof...(Args)>::type,
94 tbb::flow::key_matching<int>>(g, args...);
95 };
96
97 // Helper for the concepts which checks if key_matching join_node cannot be instantiated if
98 // one of its constructor arguments do not satisfy join_node_function_object concept
99 // This structure substitutes IncorrectT to the sequence of arguments on IncorrectArgIndex position
100 // The remaining arguments in the sequence are CorrectT
101 template <std::size_t ArgCount, std::size_t IncorrectArgIndex, typename CorrectT, typename IncorrectT, typename... Args>
102 struct multiple_arguments_initialization_helper {
103 // Current index is not equal to IncorrectArgIndex - substitute CorrectT at the end of the arguments sequence and continue
104 static constexpr bool value = multiple_arguments_initialization_helper<ArgCount - 1, IncorrectArgIndex - 1, CorrectT, IncorrectT, Args..., CorrectT>::value;
105 };
106
107 template <std::size_t ArgCount, typename CorrectT, typename IncorrectT, typename... Args>
108 struct multiple_arguments_initialization_helper<ArgCount, 0, CorrectT, IncorrectT, Args...> {
109 // Current index is equal to IncorrectArgIndex - substitute IncorrectT at the end of the sequence and continue
110 // No more incorrect indices would be added - continue with MAX_TUPLE_TEST_SIZE variable as current incorrect index
111 static constexpr bool value = multiple_arguments_initialization_helper<ArgCount - 1, MAX_TUPLE_TEST_SIZE, CorrectT, IncorrectT, Args..., IncorrectT>::value;
112 };
113
114 template <std::size_t IncorrectArgIndex, typename CorrectT, typename IncorrectT, typename... Args>
115 struct multiple_arguments_initialization_helper<0, IncorrectArgIndex, CorrectT, IncorrectT, Args...> {
116 // ArgCount is equal to 0 - no more arguments should be added
117 // Check if join_node can be initialized with Args
118 static constexpr bool value = can_initialize_join_node<Args...>;
119 };
120
121 // Helper which iterates over incorrect indices. value is true if initialization is successful for at least for one IncorrectArgIndex
122 template <std::size_t ArgCount, std::size_t CurrentIncorrectIndex, typename CorrectT, typename IncorrectT>
123 struct incorrect_arg_index_iteration_helper {
124 // CurrentIncorrectIndex is not equal to max - check with current and continue
125 static constexpr bool value = multiple_arguments_initialization_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT>::value ||
126 incorrect_arg_index_iteration_helper<ArgCount, CurrentIncorrectIndex + 1, CorrectT, IncorrectT>::value;
127 };
128
129 template <std::size_t ArgCount, std::size_t CurrentIncorrectIndex, typename CorrectT, typename IncorrectT>
130 requires (ArgCount == CurrentIncorrectIndex + 1)
131 struct incorrect_arg_index_iteration_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT> {
132 // CurrentIncorrectIndex is equal to max - check and stop
133 static constexpr bool value = multiple_arguments_initialization_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT>::value;
134 };
135
136 // Helper which iterates over argument count. value is true if initialization (with all possible incorrect indices) is successful for at least one ArgCount
137 template <std::size_t CurrentArgCount, typename CorrectT, typename IncorrectT>
138 struct arg_count_iteration_helper {
139 // CurrentArgCount is not equal to max - check and continue
140 static constexpr bool value = incorrect_arg_index_iteration_helper<CurrentArgCount, /*StartIncorrectIndex = */0, CorrectT, IncorrectT>::value ||
141 arg_count_iteration_helper<CurrentArgCount + 1, CorrectT, IncorrectT>::value;
142 };
143
144 template <typename CorrectT, typename IncorrectT>
145 struct arg_count_iteration_helper<MAX_TUPLE_TEST_SIZE, CorrectT, IncorrectT> {
146 // CurrentArgCount is equal to max - check and stop
147 static constexpr bool value = incorrect_arg_index_iteration_helper<MAX_TUPLE_TEST_SIZE, /*StartIncorrectIndex = */0, CorrectT, IncorrectT>::value;
148 };
149
150 template <typename CorrectT, typename IncorrectT>
151 concept can_initialize_join_node_with_incorrect_argument = arg_count_iteration_helper</*StartArgCount = */2, CorrectT, IncorrectT>::value;
152
153 template <std::size_t CurrentArgCount, typename CorrectT, typename... Args>
154 struct join_node_correct_initialization_helper {
155 static constexpr bool value = join_node_correct_initialization_helper<CurrentArgCount - 1, CorrectT, Args..., CorrectT>::value;
156 };
157
158 template <typename CorrectT, typename... Args>
159 struct join_node_correct_initialization_helper<0, CorrectT, Args...> {
160 static constexpr bool value = can_initialize_join_node<Args...>;
161 };
162
163 template <std::size_t CurrentArgCount, typename CorrectT>
164 struct arg_count_correct_initialization_helper {
165 static constexpr bool value = join_node_correct_initialization_helper<CurrentArgCount, CorrectT>::value &&
166 arg_count_correct_initialization_helper<CurrentArgCount + 1, CorrectT>::value;
167 };
168
169 template <typename CorrectT>
170 struct arg_count_correct_initialization_helper<MAX_TUPLE_TEST_SIZE, CorrectT> {
171 static constexpr bool value = join_node_correct_initialization_helper<MAX_TUPLE_TEST_SIZE, CorrectT>::value;
172 };
173
174 template <typename CorrectT>
175 concept can_initialize_join_node_with_correct_argument = arg_count_correct_initialization_helper</*Start = */2, CorrectT>::value;
176
177 //! \brief \ref error_guessing
178 TEST_CASE("join_node constraints") {
179 using namespace test_concepts::join_node_function_object;
180 static_assert(can_initialize_join_node_with_correct_argument<Correct<int, int>>);
181 static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NonCopyable<int, int>>);
182 static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NonDestructible<int, int>>);
183 static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NoOperatorRoundBrackets<int, int>>);
184 static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, WrongInputOperatorRoundBrackets<int, int>>);
185 static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, WrongReturnOperatorRoundBrackets<int, int>>);
186 }
187 #endif // __TBB_CPP20_CONCEPTS_PRESENT
188