151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov     Copyright (c) 2005-2022 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_assert.h"
2051c0b2f7Stbbdev #include "common/utils_concurrency_limit.h"
2151c0b2f7Stbbdev 
2249e08aacStbbdev #include "oneapi/tbb/blocked_range2d.h"
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/global_control.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev //! \file conformance_blocked_range2d.cpp
2751c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range2d] specification
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev template<typename Tag>
3051c0b2f7Stbbdev class AbstractValueType {
AbstractValueType()3151c0b2f7Stbbdev     AbstractValueType() {}
3251c0b2f7Stbbdev     int value;
3351c0b2f7Stbbdev public:
3451c0b2f7Stbbdev     template<typename OtherTag>
3551c0b2f7Stbbdev     friend AbstractValueType<OtherTag> MakeAbstractValueType( int i );
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev     template<typename OtherTag>
3851c0b2f7Stbbdev     friend int GetValueOf( const AbstractValueType<OtherTag>& v ) ;
3951c0b2f7Stbbdev };
4051c0b2f7Stbbdev 
4151c0b2f7Stbbdev template<typename Tag>
MakeAbstractValueType(int i)4251c0b2f7Stbbdev AbstractValueType<Tag> MakeAbstractValueType( int i ) {
4351c0b2f7Stbbdev     AbstractValueType<Tag> x;
4451c0b2f7Stbbdev     x.value = i;
4551c0b2f7Stbbdev     return x;
4651c0b2f7Stbbdev }
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev template<typename Tag>
GetValueOf(const AbstractValueType<Tag> & v)4951c0b2f7Stbbdev int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
5051c0b2f7Stbbdev 
5151c0b2f7Stbbdev template<typename Tag>
operator <(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5251c0b2f7Stbbdev bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
5351c0b2f7Stbbdev     return GetValueOf(u)<GetValueOf(v);
5451c0b2f7Stbbdev }
5551c0b2f7Stbbdev 
5651c0b2f7Stbbdev template<typename Tag>
operator -(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5751c0b2f7Stbbdev std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
5851c0b2f7Stbbdev     return GetValueOf(u)-GetValueOf(v);
5951c0b2f7Stbbdev }
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev template<typename Tag>
operator +(const AbstractValueType<Tag> & u,std::size_t offset)6251c0b2f7Stbbdev AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
6351c0b2f7Stbbdev     return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
6451c0b2f7Stbbdev }
6551c0b2f7Stbbdev 
6651c0b2f7Stbbdev struct RowTag {};
6751c0b2f7Stbbdev struct ColTag {};
6851c0b2f7Stbbdev 
SerialTest()6951c0b2f7Stbbdev static void SerialTest() {
7051c0b2f7Stbbdev     typedef AbstractValueType<RowTag> row_type;
7151c0b2f7Stbbdev     typedef AbstractValueType<ColTag> col_type;
7249e08aacStbbdev     typedef oneapi::tbb::blocked_range2d<row_type,col_type> range_type;
7351c0b2f7Stbbdev     for( int row_x=-10; row_x<10; ++row_x ) {
7451c0b2f7Stbbdev         for( int row_y=row_x; row_y<10; ++row_y ) {
7551c0b2f7Stbbdev             row_type row_i = MakeAbstractValueType<RowTag>(row_x);
7651c0b2f7Stbbdev             row_type row_j = MakeAbstractValueType<RowTag>(row_y);
7751c0b2f7Stbbdev             for( int row_grain=1; row_grain<10; ++row_grain ) {
7851c0b2f7Stbbdev                 for( int col_x=-10; col_x<10; ++col_x ) {
7951c0b2f7Stbbdev                     for( int col_y=col_x; col_y<10; ++col_y ) {
8051c0b2f7Stbbdev                         col_type col_i = MakeAbstractValueType<ColTag>(col_x);
8151c0b2f7Stbbdev                         col_type col_j = MakeAbstractValueType<ColTag>(col_y);
8251c0b2f7Stbbdev                         for( int col_grain=1; col_grain<10; ++col_grain ) {
8351c0b2f7Stbbdev                             range_type r( row_i, row_j, row_grain, col_i, col_j, col_grain );
8451c0b2f7Stbbdev                             utils::AssertSameType( r.is_divisible(), true );
8551c0b2f7Stbbdev                             utils::AssertSameType( r.empty(), true );
8657f524caSIlya Isaev                             utils::AssertSameType( static_cast<range_type::row_range_type::const_iterator*>(nullptr), static_cast<row_type*>(nullptr) );
8757f524caSIlya Isaev                             utils::AssertSameType( static_cast<range_type::col_range_type::const_iterator*>(nullptr), static_cast<col_type*>(nullptr) );
8849e08aacStbbdev                             utils::AssertSameType( r.rows(), oneapi::tbb::blocked_range<row_type>( row_i, row_j, 1 ));
8949e08aacStbbdev                             utils::AssertSameType( r.cols(), oneapi::tbb::blocked_range<col_type>( col_i, col_j, 1 ));
9051c0b2f7Stbbdev                             REQUIRE( r.empty()==(row_x==row_y||col_x==col_y) );
9151c0b2f7Stbbdev                             REQUIRE( r.is_divisible()==(row_y-row_x>row_grain||col_y-col_x>col_grain) );
9251c0b2f7Stbbdev                             if( r.is_divisible() ) {
9349e08aacStbbdev                                 range_type r2(r,oneapi::tbb::split());
9451c0b2f7Stbbdev                                 if( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().begin()) ) {
9551c0b2f7Stbbdev                                     REQUIRE( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()) );
9651c0b2f7Stbbdev                                     REQUIRE( GetValueOf(r2.cols().begin())==GetValueOf(r.cols().end()) );
9751c0b2f7Stbbdev                                 } else {
9851c0b2f7Stbbdev                                     REQUIRE( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()) );
9951c0b2f7Stbbdev                                     REQUIRE( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().end()) );
10051c0b2f7Stbbdev                                 }
10151c0b2f7Stbbdev                             }
10251c0b2f7Stbbdev                         }
10351c0b2f7Stbbdev                     }
10451c0b2f7Stbbdev                 }
10551c0b2f7Stbbdev             }
10651c0b2f7Stbbdev         }
10751c0b2f7Stbbdev     }
10851c0b2f7Stbbdev }
10951c0b2f7Stbbdev 
11051c0b2f7Stbbdev const int N = 1<<10;
11151c0b2f7Stbbdev 
11251c0b2f7Stbbdev unsigned char Array[N][N];
11351c0b2f7Stbbdev 
11451c0b2f7Stbbdev struct Striker {
11551c0b2f7Stbbdev    // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
operator ()Striker11649e08aacStbbdev     void operator()( const oneapi::tbb::blocked_range2d<int>& r ) const {
11749e08aacStbbdev         for( oneapi::tbb::blocked_range<int>::const_iterator i=r.rows().begin(); i!=r.rows().end(); ++i )
11849e08aacStbbdev             for( oneapi::tbb::blocked_range<int>::const_iterator j=r.cols().begin(); j!=r.cols().end(); ++j )
11951c0b2f7Stbbdev                 ++Array[i][j];
12051c0b2f7Stbbdev     }
12151c0b2f7Stbbdev };
12251c0b2f7Stbbdev 
ParallelTest()12351c0b2f7Stbbdev void ParallelTest() {
12451c0b2f7Stbbdev     for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) {
12551c0b2f7Stbbdev         for( int j=0; j<N; j=j<3 ? j+1 : j*3 ) {
12649e08aacStbbdev             const oneapi::tbb::blocked_range2d<int> r( 0, i, 7, 0, j, 5 );
12749e08aacStbbdev             oneapi::tbb::parallel_for( r, Striker() );
12851c0b2f7Stbbdev             for( int k=0; k<N; ++k ) {
12951c0b2f7Stbbdev                 for( int l=0; l<N; ++l ) {
13051c0b2f7Stbbdev                     if( Array[k][l] != (k<i && l<j) ) REQUIRE(false);
13151c0b2f7Stbbdev                     Array[k][l] = 0;
13251c0b2f7Stbbdev                 }
13351c0b2f7Stbbdev             }
13451c0b2f7Stbbdev         }
13551c0b2f7Stbbdev     }
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev 
13851c0b2f7Stbbdev //! Testing blocked_range2d interface
13951c0b2f7Stbbdev //! \brief \ref interface \ref requirement
14051c0b2f7Stbbdev TEST_CASE("Serial test") {
14151c0b2f7Stbbdev     SerialTest();
14251c0b2f7Stbbdev }
14351c0b2f7Stbbdev 
14451c0b2f7Stbbdev //! Testing blocked_range2d interface with parallel_for
14551c0b2f7Stbbdev //! \brief \ref requirement
14651c0b2f7Stbbdev TEST_CASE("Parallel test") {
14751c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() ) {
14849e08aacStbbdev         oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
14951c0b2f7Stbbdev         ParallelTest();
15051c0b2f7Stbbdev     }
15151c0b2f7Stbbdev }
15251c0b2f7Stbbdev 
15351c0b2f7Stbbdev //! Testing blocked_range2d with proportional splitting
15451c0b2f7Stbbdev //! \brief \ref interface \ref requirement
15551c0b2f7Stbbdev TEST_CASE("blocked_range2d proportional splitting") {
15649e08aacStbbdev     oneapi::tbb::blocked_range2d<int> original(0, 100, 0, 100);
15749e08aacStbbdev     oneapi::tbb::blocked_range2d<int> first(original);
15849e08aacStbbdev     oneapi::tbb::proportional_split ps(3, 1);
15949e08aacStbbdev     oneapi::tbb::blocked_range2d<int> second(first, ps);
16051c0b2f7Stbbdev 
16155f9b178SIvan Kochin     int expected_first_end = static_cast<int>(
16255f9b178SIvan Kochin         original.rows().begin() + ps.left() * (original.rows().end() - original.rows().begin()) / (ps.left() + ps.right())
16355f9b178SIvan Kochin     );
16451c0b2f7Stbbdev     if (first.rows().size() == second.rows().size()) {
16551c0b2f7Stbbdev         // Splitting was made by cols
16651c0b2f7Stbbdev         utils::check_range_bounds_after_splitting(original.cols(), first.cols(), second.cols(), expected_first_end);
16751c0b2f7Stbbdev     } else {
16851c0b2f7Stbbdev         // Splitting was made by rows
16951c0b2f7Stbbdev         utils::check_range_bounds_after_splitting(original.rows(), first.rows(), second.rows(), expected_first_end);
17051c0b2f7Stbbdev     }
17151c0b2f7Stbbdev }
17251c0b2f7Stbbdev 
17351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
17451c0b2f7Stbbdev //! Testing blocked_range2d deduction guides
17551c0b2f7Stbbdev //! \brief \ref interface
17651c0b2f7Stbbdev TEST_CASE("Deduction guides") {
17751c0b2f7Stbbdev     std::vector<const unsigned long *> v;
17851c0b2f7Stbbdev     std::vector<double> v2;
17951c0b2f7Stbbdev 
18051c0b2f7Stbbdev     // check blocked_range2d(RowValue, RowValue, size_t, ColValue, ColValue, size_t)
18149e08aacStbbdev     oneapi::tbb::blocked_range2d r1(v.begin(), v.end(), 2, v2.begin(), v2.end(), 2);
18249e08aacStbbdev     static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range2d<decltype(v)::iterator, decltype(v2)::iterator>>::value);
18351c0b2f7Stbbdev 
18451c0b2f7Stbbdev     // check blocked_range2d(blocked_range2d &)
18549e08aacStbbdev     oneapi::tbb::blocked_range2d r2(r1);
18651c0b2f7Stbbdev     static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
18751c0b2f7Stbbdev 
18851c0b2f7Stbbdev     // check blocked_range2d(blocked_range2d &&)
18949e08aacStbbdev     oneapi::tbb::blocked_range2d r3(std::move(r1));
19051c0b2f7Stbbdev     static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
19151c0b2f7Stbbdev }
19251c0b2f7Stbbdev #endif
19351c0b2f7Stbbdev 
194