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