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))
test_blocked_range_constraint()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))
test_blocked_range2d_constraint()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))
test_blocked_range2d_col_invalid_constraint()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))
test_blocked_range2d_row_invalid_constraint()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))
test_blocked_range3d_constraint()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))
test_blocked_range3d_page_invalid_constraint()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))
test_blocked_range3d_row_invalid_constraint()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))
test_blocked_range3d_col_invalid_constraint()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