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/test.h" 18 #include "common/utils.h" 19 #include "common/utils_report.h" 20 #include "common/range_based_for_support.h" 21 #include "common/config.h" 22 #include "common/concepts_common.h" 23 24 #include "tbb/blocked_range.h" 25 #include "tbb/blocked_range2d.h" 26 #include "tbb/blocked_range3d.h" 27 #define TBB_PREVIEW_BLOCKED_RANGE_ND 1 28 #include "tbb/blocked_rangeNd.h" 29 30 //! \file test_blocked_range.cpp 31 //! \brief Test for [algorithms.blocked_range] specification 32 33 #include <utility> //for std::pair 34 #include <functional> 35 #include <vector> 36 37 //! Testing blocked_range with range based for 38 //! \brief \ref interface 39 TEST_CASE("Range based for") { 40 using namespace range_based_for_support_tests; 41 42 const std::size_t sequence_length = 100; 43 std::size_t int_array[sequence_length] = {0}; 44 45 for (std::size_t i = 0; i < sequence_length; ++i) { 46 int_array[i] = i + 1; 47 } 48 const tbb::blocked_range<std::size_t*> r(int_array, int_array + sequence_length, 1); 49 50 CHECK_MESSAGE(range_based_for_accumulate<std::size_t>(r, std::plus<std::size_t>(), std::size_t(0)) 51 == gauss_summ_of_int_sequence(sequence_length), "incorrect accumulated value generated via range based for ?"); 52 } 53 54 //! Proportional split does not overflow with blocked range 55 //! \brief \ref error_guessing \ref boundary 56 TEST_CASE("Proportional split overflow") { 57 using tbb::blocked_range; 58 using tbb::proportional_split; 59 60 blocked_range<std::size_t> r1(0, std::size_t(-1) / 2); 61 std::size_t size = r1.size(); 62 std::size_t begin = r1.begin(); 63 std::size_t end = r1.end(); 64 65 proportional_split p(1, 3); 66 blocked_range<std::size_t> r2(r1, p); 67 68 // overflow-free computation 69 std::size_t parts = p.left() + p.right(); 70 std::size_t int_part = size / parts; 71 std::size_t fraction = size - int_part * parts; // fraction < parts 72 std::size_t right_idx = int_part * p.right() + fraction * p.right() / parts + 1; 73 std::size_t newRangeBegin = end - right_idx; 74 75 // Division in 'right_idx' very likely is inexact also. 76 std::size_t tolerance = 1; 77 std::size_t diff = (r2.begin() < newRangeBegin) ? (newRangeBegin - r2.begin()) : (r2.begin() - newRangeBegin); 78 bool is_split_correct = diff <= tolerance; 79 bool test_passed = (r1.begin() == begin && r1.end() == r2.begin() && is_split_correct && 80 r2.end() == end); 81 if (!test_passed) { 82 REPORT("Incorrect split of blocked range[%lu, %lu) into r1[%lu, %lu) and r2[%lu, %lu), " 83 "must be r1[%lu, %lu) and r2[%lu, %lu)\n", begin, end, r1.begin(), r1.end(), r2.begin(), r2.end(), begin, newRangeBegin, newRangeBegin, end); 84 CHECK(test_passed); 85 } 86 } 87 88 #if __TBB_CPP20_CONCEPTS_PRESENT 89 90 template <bool ExpectSatisfies, typename... Types> 91 requires (... && (utils::well_formed_instantiation<tbb::blocked_range, Types> == ExpectSatisfies)) 92 void test_blocked_range_constraint() {} 93 94 template <bool ExpectSatisfies, typename... Types> 95 requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, Types, Types> == ExpectSatisfies)) 96 void test_blocked_range2d_constraint() {} 97 98 template <typename... Types> 99 requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, Types, test_concepts::Dummy> == false)) 100 void test_blocked_range2d_col_invalid_constraint() {} 101 102 template <typename... Types> 103 requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, test_concepts::Dummy, Types> == false)) 104 void test_blocked_range2d_row_invalid_constraint() {} 105 106 template <bool ExpectSatisfies, typename... Types> 107 requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, Types, Types> == ExpectSatisfies)) 108 void test_blocked_range3d_constraint() {} 109 110 template <typename... Types> 111 requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, test_concepts::Dummy, Types, Types> == false)) 112 void test_blocked_range3d_page_invalid_constraint() {} 113 114 template <typename... Types> 115 requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, test_concepts::Dummy, Types> == false)) 116 void test_blocked_range3d_row_invalid_constraint() {} 117 118 template <typename... Types> 119 requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, Types, test_concepts::Dummy> == false)) 120 void test_blocked_range3d_col_invalid_constraint() {} 121 122 template <typename T> 123 concept well_formed_blocked_range_Nd_instantiation_basic = requires { 124 typename tbb::blocked_rangeNd<T, 1>; 125 }; 126 127 template <typename... Types> 128 concept well_formed_blocked_range_Nd_instantiation = ( ... && well_formed_blocked_range_Nd_instantiation_basic<Types> ); 129 130 //! \brief \ref error_guessing 131 TEST_CASE("constraints for blocked_range value") { 132 using namespace test_concepts::blocked_range_value; 133 using const_iterator = typename std::vector<int>::const_iterator; 134 135 test_blocked_range_constraint</*Expected = */true, 136 Correct, char, int, std::size_t, const_iterator>(); 137 138 test_blocked_range_constraint</*Expected = */false, 139 NonCopyable, NonCopyAssignable, NonDestructible, 140 NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess, 141 NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus, 142 NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>(); 143 } 144 145 //! \brief \ref error_guessing 146 TEST_CASE("constraints for blocked_range2d value") { 147 using namespace test_concepts::blocked_range_value; 148 using const_iterator = typename std::vector<int>::const_iterator; 149 150 test_blocked_range2d_constraint</*Expected = */true, 151 Correct, char, int, std::size_t, const_iterator>(); 152 153 test_blocked_range2d_constraint</*Expected = */false, 154 NonCopyable, NonCopyAssignable, NonDestructible, 155 NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess, 156 NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus, 157 NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>(); 158 159 test_blocked_range2d_row_invalid_constraint<Correct, char, int, std::size_t, const_iterator>(); 160 test_blocked_range2d_col_invalid_constraint<Correct, char, int, std::size_t, const_iterator>(); 161 } 162 163 //! \brief \ref error_guessing 164 TEST_CASE("constraints for blocked_range3d value") { 165 using namespace test_concepts::blocked_range_value; 166 using const_iterator = typename std::vector<int>::const_iterator; 167 168 test_blocked_range3d_constraint</*Expected = */true, 169 Correct, char, int, std::size_t, const_iterator>(); 170 171 test_blocked_range3d_constraint</*Expected = */false, 172 NonCopyable, NonCopyAssignable, NonDestructible, 173 NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess, 174 NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus, 175 NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>(); 176 177 test_blocked_range3d_page_invalid_constraint<Correct, char, int, std::size_t, const_iterator>(); 178 test_blocked_range3d_row_invalid_constraint<Correct, char, int, std::size_t, const_iterator>(); 179 test_blocked_range3d_col_invalid_constraint<Correct, char, int, std::size_t, const_iterator>(); 180 } 181 182 //! \brief \ref error_guessing 183 TEST_CASE("constraints for blocked_rangeNd value") { 184 using namespace test_concepts::blocked_range_value; 185 using const_iterator = typename std::vector<int>::const_iterator; 186 187 static_assert(well_formed_blocked_range_Nd_instantiation<Correct, char, int, std::size_t, const_iterator>); 188 189 static_assert(!well_formed_blocked_range_Nd_instantiation<NonCopyable, NonCopyAssignable, NonDestructible, 190 NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess, 191 NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus, 192 NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>); 193 } 194 195 #endif // __TBB_CPP20_CONCEPTS_PRESENT 196