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 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