151c0b2f7Stbbdev /*
2*04179683SPavel Kumbrasev     Copyright (c) 2005-2023 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 
1751c0b2f7Stbbdev #include "common/config.h"
1851c0b2f7Stbbdev 
1951c0b2f7Stbbdev #include "test_join_node.h"
2051c0b2f7Stbbdev 
21478de5b1Stbbdev #include "common/concepts_common.h"
22478de5b1Stbbdev 
2351c0b2f7Stbbdev //! \file test_join_node_key_matching.cpp
2451c0b2f7Stbbdev //! \brief Test for [flow_graph.join_node] specification
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
test_deduction_guides()2751c0b2f7Stbbdev void test_deduction_guides() {
2851c0b2f7Stbbdev     using namespace tbb::flow;
2951c0b2f7Stbbdev     using tuple_type = std::tuple<int, int, double>;
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev     graph g;
3251c0b2f7Stbbdev     auto body_int = [](const int&)->int { return 1; };
3351c0b2f7Stbbdev     auto body_double = [](const double&)->int { return 1; };
3451c0b2f7Stbbdev 
3551c0b2f7Stbbdev     join_node j1(g, body_int, body_int, body_double);
3651c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(j1), join_node<tuple_type, key_matching<int>>>);
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
3951c0b2f7Stbbdev     broadcast_node<int> b1(g), b2(g);
4051c0b2f7Stbbdev     broadcast_node<double> b3(g);
4151c0b2f7Stbbdev     broadcast_node<tuple_type> b4(g);
4251c0b2f7Stbbdev 
4351c0b2f7Stbbdev     join_node j2(follows(b1, b2, b3), body_int, body_int, body_double);
4451c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(j2), join_node<tuple_type, key_matching<int>>>);
4551c0b2f7Stbbdev 
4651c0b2f7Stbbdev     join_node j3(precedes(b4), body_int, body_int, body_double);
4751c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(j3), join_node<tuple_type, key_matching<int>>>);
4851c0b2f7Stbbdev #endif
4951c0b2f7Stbbdev 
5051c0b2f7Stbbdev     join_node j4(j1);
5151c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(j4), join_node<tuple_type, key_matching<int>>>);
5251c0b2f7Stbbdev }
5351c0b2f7Stbbdev #endif
5451c0b2f7Stbbdev 
5551c0b2f7Stbbdev //! Test serial key matching on special input types
5651c0b2f7Stbbdev //! \brief \ref error_guessing
5751c0b2f7Stbbdev TEST_CASE("Serial test on tuples") {
5851c0b2f7Stbbdev     INFO("key_matching\n");
5951c0b2f7Stbbdev     generate_test<serial_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int> >::do_test();
6051c0b2f7Stbbdev     generate_test<serial_test, std::tuple<MyKeyFirst<std::string, double>, MyKeySecond<std::string, float> >, tbb::flow::key_matching<std::string> >::do_test();
6151c0b2f7Stbbdev     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();
6251c0b2f7Stbbdev }
6351c0b2f7Stbbdev 
6451c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
6551c0b2f7Stbbdev //! Test deduction guides
6651c0b2f7Stbbdev //! \brief \ref requirement
6751c0b2f7Stbbdev TEST_CASE("Test deduction guides"){
6851c0b2f7Stbbdev     test_deduction_guides();
6951c0b2f7Stbbdev }
7051c0b2f7Stbbdev #endif
7151c0b2f7Stbbdev 
7251c0b2f7Stbbdev //! Test parallel key matching on special input types
7351c0b2f7Stbbdev //! \brief \ref error_guessing
7451c0b2f7Stbbdev TEST_CASE("Parallel test on tuples"){
7551c0b2f7Stbbdev     generate_test<parallel_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int> >::do_test();
7651c0b2f7Stbbdev     generate_test<parallel_test, std::tuple<MyKeyFirst<int, double>, MyKeySecond<int, float> >, tbb::flow::key_matching<int&> >::do_test();
7751c0b2f7Stbbdev     generate_test<parallel_test, std::tuple<MyKeyFirst<std::string, double>, MyKeySecond<std::string, float> >, tbb::flow::key_matching<std::string&> >::do_test();
7851c0b2f7Stbbdev }
7951c0b2f7Stbbdev 
80478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
81478de5b1Stbbdev template <std::size_t Count>
82478de5b1Stbbdev struct tuple_helper {
83478de5b1Stbbdev     using type = decltype(std::tuple_cat(std::declval<std::tuple<int>>(), std::declval<typename tuple_helper<Count - 1>::type>()));
84478de5b1Stbbdev };
85478de5b1Stbbdev 
86478de5b1Stbbdev template <>
87478de5b1Stbbdev struct tuple_helper<1> {
88478de5b1Stbbdev     using type = std::tuple<int>;
89478de5b1Stbbdev };
90478de5b1Stbbdev 
91478de5b1Stbbdev template <typename... Args>
92478de5b1Stbbdev concept can_initialize_join_node = requires(tbb::flow::graph& g, Args... args) {
93478de5b1Stbbdev     tbb::flow::join_node<typename tuple_helper<sizeof...(Args)>::type,
94478de5b1Stbbdev                          tbb::flow::key_matching<int>>(g, args...);
95478de5b1Stbbdev };
96478de5b1Stbbdev 
97478de5b1Stbbdev // Helper for the concepts which checks if key_matching join_node cannot be instantiated if
98478de5b1Stbbdev // one of its constructor arguments do not satisfy join_node_function_object concept
99478de5b1Stbbdev // This structure substitutes IncorrectT to the sequence of arguments on IncorrectArgIndex position
100478de5b1Stbbdev // The remaining arguments in the sequence are CorrectT
101478de5b1Stbbdev template <std::size_t ArgCount, std::size_t IncorrectArgIndex, typename CorrectT, typename IncorrectT, typename... Args>
102478de5b1Stbbdev struct multiple_arguments_initialization_helper {
103478de5b1Stbbdev     // Current index is not equal to IncorrectArgIndex - substitute CorrectT at the end of the arguments sequence and continue
104478de5b1Stbbdev     static constexpr bool value = multiple_arguments_initialization_helper<ArgCount - 1, IncorrectArgIndex - 1, CorrectT, IncorrectT, Args..., CorrectT>::value;
105478de5b1Stbbdev };
106478de5b1Stbbdev 
107478de5b1Stbbdev template <std::size_t ArgCount, typename CorrectT, typename IncorrectT, typename... Args>
108478de5b1Stbbdev struct multiple_arguments_initialization_helper<ArgCount, 0, CorrectT, IncorrectT, Args...> {
109478de5b1Stbbdev     // Current index is equal to IncorrectArgIndex - substitute IncorrectT at the end of the sequence and continue
110478de5b1Stbbdev     // No more incorrect indices would be added - continue with MAX_TUPLE_TEST_SIZE variable as current incorrect index
111478de5b1Stbbdev     static constexpr bool value = multiple_arguments_initialization_helper<ArgCount - 1, MAX_TUPLE_TEST_SIZE, CorrectT, IncorrectT, Args..., IncorrectT>::value;
112478de5b1Stbbdev };
113478de5b1Stbbdev 
114478de5b1Stbbdev template <std::size_t IncorrectArgIndex, typename CorrectT, typename IncorrectT, typename... Args>
115478de5b1Stbbdev struct multiple_arguments_initialization_helper<0, IncorrectArgIndex, CorrectT, IncorrectT, Args...> {
116478de5b1Stbbdev     // ArgCount is equal to 0 - no more arguments should be added
117478de5b1Stbbdev     // Check if join_node can be initialized with Args
118478de5b1Stbbdev     static constexpr bool value = can_initialize_join_node<Args...>;
119478de5b1Stbbdev };
120478de5b1Stbbdev 
121478de5b1Stbbdev // Helper which iterates over incorrect indices. value is true if initialization is successful for at least for one IncorrectArgIndex
122478de5b1Stbbdev template <std::size_t ArgCount, std::size_t CurrentIncorrectIndex, typename CorrectT, typename IncorrectT>
123478de5b1Stbbdev struct incorrect_arg_index_iteration_helper {
124478de5b1Stbbdev     // CurrentIncorrectIndex is not equal to max - check with current and continue
125478de5b1Stbbdev     static constexpr bool value = multiple_arguments_initialization_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT>::value ||
126478de5b1Stbbdev                                   incorrect_arg_index_iteration_helper<ArgCount, CurrentIncorrectIndex + 1, CorrectT, IncorrectT>::value;
127478de5b1Stbbdev };
128478de5b1Stbbdev 
129478de5b1Stbbdev template <std::size_t ArgCount, std::size_t CurrentIncorrectIndex, typename CorrectT, typename IncorrectT>
130478de5b1Stbbdev requires (ArgCount == CurrentIncorrectIndex + 1)
131478de5b1Stbbdev struct incorrect_arg_index_iteration_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT> {
132478de5b1Stbbdev     // CurrentIncorrectIndex is equal to max - check and stop
133478de5b1Stbbdev     static constexpr bool value = multiple_arguments_initialization_helper<ArgCount, CurrentIncorrectIndex, CorrectT, IncorrectT>::value;
134478de5b1Stbbdev };
135478de5b1Stbbdev 
136478de5b1Stbbdev // Helper which iterates over argument count. value is true if initialization (with all possible incorrect indices) is successful for at least one ArgCount
137478de5b1Stbbdev template <std::size_t CurrentArgCount, typename CorrectT, typename IncorrectT>
138478de5b1Stbbdev struct arg_count_iteration_helper {
139478de5b1Stbbdev     // CurrentArgCount is not equal to max - check and continue
140478de5b1Stbbdev     static constexpr bool value = incorrect_arg_index_iteration_helper<CurrentArgCount, /*StartIncorrectIndex = */0, CorrectT, IncorrectT>::value ||
141478de5b1Stbbdev                                   arg_count_iteration_helper<CurrentArgCount + 1, CorrectT, IncorrectT>::value;
142478de5b1Stbbdev };
143478de5b1Stbbdev 
144478de5b1Stbbdev template <typename CorrectT, typename IncorrectT>
145478de5b1Stbbdev struct arg_count_iteration_helper<MAX_TUPLE_TEST_SIZE, CorrectT, IncorrectT> {
146478de5b1Stbbdev     // CurrentArgCount is equal to max - check and stop
147478de5b1Stbbdev     static constexpr bool value = incorrect_arg_index_iteration_helper<MAX_TUPLE_TEST_SIZE, /*StartIncorrectIndex = */0, CorrectT, IncorrectT>::value;
148478de5b1Stbbdev };
149478de5b1Stbbdev 
150478de5b1Stbbdev template <typename CorrectT, typename IncorrectT>
151478de5b1Stbbdev concept can_initialize_join_node_with_incorrect_argument = arg_count_iteration_helper</*StartArgCount = */2, CorrectT, IncorrectT>::value;
152478de5b1Stbbdev 
153478de5b1Stbbdev template <std::size_t CurrentArgCount, typename CorrectT, typename... Args>
154478de5b1Stbbdev struct join_node_correct_initialization_helper {
155478de5b1Stbbdev     static constexpr bool value = join_node_correct_initialization_helper<CurrentArgCount - 1, CorrectT, Args..., CorrectT>::value;
156478de5b1Stbbdev };
157478de5b1Stbbdev 
158478de5b1Stbbdev template <typename CorrectT, typename... Args>
159478de5b1Stbbdev struct join_node_correct_initialization_helper<0, CorrectT, Args...> {
160478de5b1Stbbdev     static constexpr bool value = can_initialize_join_node<Args...>;
161478de5b1Stbbdev };
162478de5b1Stbbdev 
163478de5b1Stbbdev template <std::size_t CurrentArgCount, typename CorrectT>
164478de5b1Stbbdev struct arg_count_correct_initialization_helper {
165478de5b1Stbbdev     static constexpr bool value = join_node_correct_initialization_helper<CurrentArgCount, CorrectT>::value &&
166478de5b1Stbbdev                                   arg_count_correct_initialization_helper<CurrentArgCount + 1, CorrectT>::value;
167478de5b1Stbbdev };
168478de5b1Stbbdev 
169478de5b1Stbbdev template <typename CorrectT>
170478de5b1Stbbdev struct arg_count_correct_initialization_helper<MAX_TUPLE_TEST_SIZE, CorrectT> {
171478de5b1Stbbdev     static constexpr bool value = join_node_correct_initialization_helper<MAX_TUPLE_TEST_SIZE, CorrectT>::value;
172478de5b1Stbbdev };
173478de5b1Stbbdev 
174478de5b1Stbbdev template <typename CorrectT>
175478de5b1Stbbdev concept can_initialize_join_node_with_correct_argument = arg_count_correct_initialization_helper</*Start = */2, CorrectT>::value;
176478de5b1Stbbdev 
177478de5b1Stbbdev //! \brief \ref error_guessing
178478de5b1Stbbdev TEST_CASE("join_node constraints") {
179478de5b1Stbbdev     using namespace test_concepts::join_node_function_object;
180478de5b1Stbbdev     static_assert(can_initialize_join_node_with_correct_argument<Correct<int, int>>);
181478de5b1Stbbdev     static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NonCopyable<int, int>>);
182478de5b1Stbbdev     static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NonDestructible<int, int>>);
183478de5b1Stbbdev     static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, NoOperatorRoundBrackets<int, int>>);
184478de5b1Stbbdev     static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, WrongInputOperatorRoundBrackets<int, int>>);
185478de5b1Stbbdev     static_assert(!can_initialize_join_node_with_incorrect_argument<Correct<int, int>, WrongReturnOperatorRoundBrackets<int, int>>);
186478de5b1Stbbdev }
187478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
188