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