151c0b2f7Stbbdev /*
2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation
351c0b2f7Stbbdev
451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev you may not use this file except in compliance with the License.
651c0b2f7Stbbdev You may obtain a copy of the License at
751c0b2f7Stbbdev
851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev
1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev See the License for the specific language governing permissions and
1451c0b2f7Stbbdev limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev
1751c0b2f7Stbbdev #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils.h"
1951c0b2f7Stbbdev #include "common/utils_report.h"
2051c0b2f7Stbbdev #include "common/range_based_for_support.h"
2151c0b2f7Stbbdev #include "common/config.h"
22*478de5b1Stbbdev #include "common/concepts_common.h"
2351c0b2f7Stbbdev
2451c0b2f7Stbbdev #include "tbb/blocked_range.h"
25*478de5b1Stbbdev #include "tbb/blocked_range2d.h"
26*478de5b1Stbbdev #include "tbb/blocked_range3d.h"
27*478de5b1Stbbdev #define TBB_PREVIEW_BLOCKED_RANGE_ND 1
28*478de5b1Stbbdev #include "tbb/blocked_rangeNd.h"
2951c0b2f7Stbbdev
3051c0b2f7Stbbdev //! \file test_blocked_range.cpp
3151c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range] specification
3251c0b2f7Stbbdev
3351c0b2f7Stbbdev #include <utility> //for std::pair
3451c0b2f7Stbbdev #include <functional>
35*478de5b1Stbbdev #include <vector>
3651c0b2f7Stbbdev
3751c0b2f7Stbbdev //! Testing blocked_range with range based for
3851c0b2f7Stbbdev //! \brief \ref interface
3951c0b2f7Stbbdev TEST_CASE("Range based for") {
4051c0b2f7Stbbdev using namespace range_based_for_support_tests;
4151c0b2f7Stbbdev
4251c0b2f7Stbbdev const std::size_t sequence_length = 100;
4351c0b2f7Stbbdev std::size_t int_array[sequence_length] = {0};
4451c0b2f7Stbbdev
4551c0b2f7Stbbdev for (std::size_t i = 0; i < sequence_length; ++i) {
4651c0b2f7Stbbdev int_array[i] = i + 1;
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev const tbb::blocked_range<std::size_t*> r(int_array, int_array + sequence_length, 1);
4951c0b2f7Stbbdev
5051c0b2f7Stbbdev CHECK_MESSAGE(range_based_for_accumulate<std::size_t>(r, std::plus<std::size_t>(), std::size_t(0))
5151c0b2f7Stbbdev == gauss_summ_of_int_sequence(sequence_length), "incorrect accumulated value generated via range based for ?");
5251c0b2f7Stbbdev }
5351c0b2f7Stbbdev
5451c0b2f7Stbbdev //! Proportional split does not overflow with blocked range
5551c0b2f7Stbbdev //! \brief \ref error_guessing \ref boundary
5651c0b2f7Stbbdev TEST_CASE("Proportional split overflow") {
5751c0b2f7Stbbdev using tbb::blocked_range;
5851c0b2f7Stbbdev using tbb::proportional_split;
5951c0b2f7Stbbdev
6051c0b2f7Stbbdev blocked_range<std::size_t> r1(0, std::size_t(-1) / 2);
6151c0b2f7Stbbdev std::size_t size = r1.size();
6251c0b2f7Stbbdev std::size_t begin = r1.begin();
6351c0b2f7Stbbdev std::size_t end = r1.end();
6451c0b2f7Stbbdev
6551c0b2f7Stbbdev proportional_split p(1, 3);
6651c0b2f7Stbbdev blocked_range<std::size_t> r2(r1, p);
6751c0b2f7Stbbdev
6851c0b2f7Stbbdev // overflow-free computation
6951c0b2f7Stbbdev std::size_t parts = p.left() + p.right();
7051c0b2f7Stbbdev std::size_t int_part = size / parts;
7151c0b2f7Stbbdev std::size_t fraction = size - int_part * parts; // fraction < parts
7251c0b2f7Stbbdev std::size_t right_idx = int_part * p.right() + fraction * p.right() / parts + 1;
7351c0b2f7Stbbdev std::size_t newRangeBegin = end - right_idx;
7451c0b2f7Stbbdev
7551c0b2f7Stbbdev // Division in 'right_idx' very likely is inexact also.
7651c0b2f7Stbbdev std::size_t tolerance = 1;
7751c0b2f7Stbbdev std::size_t diff = (r2.begin() < newRangeBegin) ? (newRangeBegin - r2.begin()) : (r2.begin() - newRangeBegin);
7851c0b2f7Stbbdev bool is_split_correct = diff <= tolerance;
7951c0b2f7Stbbdev bool test_passed = (r1.begin() == begin && r1.end() == r2.begin() && is_split_correct &&
8051c0b2f7Stbbdev r2.end() == end);
8151c0b2f7Stbbdev if (!test_passed) {
8251c0b2f7Stbbdev REPORT("Incorrect split of blocked range[%lu, %lu) into r1[%lu, %lu) and r2[%lu, %lu), "
8351c0b2f7Stbbdev "must be r1[%lu, %lu) and r2[%lu, %lu)\n", begin, end, r1.begin(), r1.end(), r2.begin(), r2.end(), begin, newRangeBegin, newRangeBegin, end);
8451c0b2f7Stbbdev CHECK(test_passed);
8551c0b2f7Stbbdev }
8651c0b2f7Stbbdev }
8751c0b2f7Stbbdev
88*478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
89*478de5b1Stbbdev
90*478de5b1Stbbdev template <bool ExpectSatisfies, typename... Types>
91*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range, Types> == ExpectSatisfies))
test_blocked_range_constraint()92*478de5b1Stbbdev void test_blocked_range_constraint() {}
93*478de5b1Stbbdev
94*478de5b1Stbbdev template <bool ExpectSatisfies, typename... Types>
95*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, Types, Types> == ExpectSatisfies))
test_blocked_range2d_constraint()96*478de5b1Stbbdev void test_blocked_range2d_constraint() {}
97*478de5b1Stbbdev
98*478de5b1Stbbdev template <typename... Types>
99*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, Types, test_concepts::Dummy> == false))
test_blocked_range2d_col_invalid_constraint()100*478de5b1Stbbdev void test_blocked_range2d_col_invalid_constraint() {}
101*478de5b1Stbbdev
102*478de5b1Stbbdev template <typename... Types>
103*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range2d, test_concepts::Dummy, Types> == false))
test_blocked_range2d_row_invalid_constraint()104*478de5b1Stbbdev void test_blocked_range2d_row_invalid_constraint() {}
105*478de5b1Stbbdev
106*478de5b1Stbbdev template <bool ExpectSatisfies, typename... Types>
107*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, Types, Types> == ExpectSatisfies))
test_blocked_range3d_constraint()108*478de5b1Stbbdev void test_blocked_range3d_constraint() {}
109*478de5b1Stbbdev
110*478de5b1Stbbdev template <typename... Types>
111*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, test_concepts::Dummy, Types, Types> == false))
test_blocked_range3d_page_invalid_constraint()112*478de5b1Stbbdev void test_blocked_range3d_page_invalid_constraint() {}
113*478de5b1Stbbdev
114*478de5b1Stbbdev template <typename... Types>
115*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, test_concepts::Dummy, Types> == false))
test_blocked_range3d_row_invalid_constraint()116*478de5b1Stbbdev void test_blocked_range3d_row_invalid_constraint() {}
117*478de5b1Stbbdev
118*478de5b1Stbbdev template <typename... Types>
119*478de5b1Stbbdev requires (... && (utils::well_formed_instantiation<tbb::blocked_range3d, Types, Types, test_concepts::Dummy> == false))
test_blocked_range3d_col_invalid_constraint()120*478de5b1Stbbdev void test_blocked_range3d_col_invalid_constraint() {}
121*478de5b1Stbbdev
122*478de5b1Stbbdev template <typename T>
123*478de5b1Stbbdev concept well_formed_blocked_range_Nd_instantiation_basic = requires {
124*478de5b1Stbbdev typename tbb::blocked_rangeNd<T, 1>;
125*478de5b1Stbbdev };
126*478de5b1Stbbdev
127*478de5b1Stbbdev template <typename... Types>
128*478de5b1Stbbdev concept well_formed_blocked_range_Nd_instantiation = ( ... && well_formed_blocked_range_Nd_instantiation_basic<Types> );
129*478de5b1Stbbdev
130*478de5b1Stbbdev //! \brief \ref error_guessing
131*478de5b1Stbbdev TEST_CASE("constraints for blocked_range value") {
132*478de5b1Stbbdev using namespace test_concepts::blocked_range_value;
133*478de5b1Stbbdev using const_iterator = typename std::vector<int>::const_iterator;
134*478de5b1Stbbdev
135*478de5b1Stbbdev test_blocked_range_constraint</*Expected = */true,
136*478de5b1Stbbdev Correct, char, int, std::size_t, const_iterator>();
137*478de5b1Stbbdev
138*478de5b1Stbbdev test_blocked_range_constraint</*Expected = */false,
139*478de5b1Stbbdev NonCopyable, NonCopyAssignable, NonDestructible,
140*478de5b1Stbbdev NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess,
141*478de5b1Stbbdev NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus,
142*478de5b1Stbbdev NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>();
143*478de5b1Stbbdev }
144*478de5b1Stbbdev
145*478de5b1Stbbdev //! \brief \ref error_guessing
146*478de5b1Stbbdev TEST_CASE("constraints for blocked_range2d value") {
147*478de5b1Stbbdev using namespace test_concepts::blocked_range_value;
148*478de5b1Stbbdev using const_iterator = typename std::vector<int>::const_iterator;
149*478de5b1Stbbdev
150*478de5b1Stbbdev test_blocked_range2d_constraint</*Expected = */true,
151*478de5b1Stbbdev Correct, char, int, std::size_t, const_iterator>();
152*478de5b1Stbbdev
153*478de5b1Stbbdev test_blocked_range2d_constraint</*Expected = */false,
154*478de5b1Stbbdev NonCopyable, NonCopyAssignable, NonDestructible,
155*478de5b1Stbbdev NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess,
156*478de5b1Stbbdev NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus,
157*478de5b1Stbbdev NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>();
158*478de5b1Stbbdev
159*478de5b1Stbbdev test_blocked_range2d_row_invalid_constraint<Correct, char, int, std::size_t, const_iterator>();
160*478de5b1Stbbdev test_blocked_range2d_col_invalid_constraint<Correct, char, int, std::size_t, const_iterator>();
161*478de5b1Stbbdev }
162*478de5b1Stbbdev
163*478de5b1Stbbdev //! \brief \ref error_guessing
164*478de5b1Stbbdev TEST_CASE("constraints for blocked_range3d value") {
165*478de5b1Stbbdev using namespace test_concepts::blocked_range_value;
166*478de5b1Stbbdev using const_iterator = typename std::vector<int>::const_iterator;
167*478de5b1Stbbdev
168*478de5b1Stbbdev test_blocked_range3d_constraint</*Expected = */true,
169*478de5b1Stbbdev Correct, char, int, std::size_t, const_iterator>();
170*478de5b1Stbbdev
171*478de5b1Stbbdev test_blocked_range3d_constraint</*Expected = */false,
172*478de5b1Stbbdev NonCopyable, NonCopyAssignable, NonDestructible,
173*478de5b1Stbbdev NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess,
174*478de5b1Stbbdev NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus,
175*478de5b1Stbbdev NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>();
176*478de5b1Stbbdev
177*478de5b1Stbbdev test_blocked_range3d_page_invalid_constraint<Correct, char, int, std::size_t, const_iterator>();
178*478de5b1Stbbdev test_blocked_range3d_row_invalid_constraint<Correct, char, int, std::size_t, const_iterator>();
179*478de5b1Stbbdev test_blocked_range3d_col_invalid_constraint<Correct, char, int, std::size_t, const_iterator>();
180*478de5b1Stbbdev }
181*478de5b1Stbbdev
182*478de5b1Stbbdev //! \brief \ref error_guessing
183*478de5b1Stbbdev TEST_CASE("constraints for blocked_rangeNd value") {
184*478de5b1Stbbdev using namespace test_concepts::blocked_range_value;
185*478de5b1Stbbdev using const_iterator = typename std::vector<int>::const_iterator;
186*478de5b1Stbbdev
187*478de5b1Stbbdev static_assert(well_formed_blocked_range_Nd_instantiation<Correct, char, int, std::size_t, const_iterator>);
188*478de5b1Stbbdev
189*478de5b1Stbbdev static_assert(!well_formed_blocked_range_Nd_instantiation<NonCopyable, NonCopyAssignable, NonDestructible,
190*478de5b1Stbbdev NoOperatorLess, OperatorLessNonConst, WrongReturnOperatorLess,
191*478de5b1Stbbdev NoOperatorMinus, OperatorMinusNonConst, WrongReturnOperatorMinus,
192*478de5b1Stbbdev NoOperatorPlus, OperatorPlusNonConst, WrongReturnOperatorPlus>);
193*478de5b1Stbbdev }
194*478de5b1Stbbdev
195*478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
196