1 /*
2     Copyright (c) 2005-2020 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 "tbb/blocked_range2d.h"
18 #include "harness_assert.h"
19 
20 // First test as much as we can without including other headers.
21 // Doing so should catch problems arising from failing to include headers.
22 
23 template<typename Tag>
24 class AbstractValueType {
AbstractValueType()25     AbstractValueType() {}
26     int value;
27 public:
28     template<typename OtherTag>
29     friend AbstractValueType<OtherTag> MakeAbstractValueType( int i );
30 
31     template<typename OtherTag>
32     friend int GetValueOf( const AbstractValueType<OtherTag>& v ) ;
33 };
34 
35 template<typename Tag>
MakeAbstractValueType(int i)36 AbstractValueType<Tag> MakeAbstractValueType( int i ) {
37     AbstractValueType<Tag> x;
38     x.value = i;
39     return x;
40 }
41 
42 template<typename Tag>
GetValueOf(const AbstractValueType<Tag> & v)43 int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
44 
45 template<typename Tag>
operator <(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)46 bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
47     return GetValueOf(u)<GetValueOf(v);
48 }
49 
50 template<typename Tag>
operator -(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)51 std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
52     return GetValueOf(u)-GetValueOf(v);
53 }
54 
55 template<typename Tag>
operator +(const AbstractValueType<Tag> & u,std::size_t offset)56 AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
57     return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
58 }
59 
60 struct RowTag {};
61 struct ColTag {};
62 
SerialTest()63 static void SerialTest() {
64     typedef AbstractValueType<RowTag> row_type;
65     typedef AbstractValueType<ColTag> col_type;
66     typedef tbb::blocked_range2d<row_type,col_type> range_type;
67     for( int row_x=-10; row_x<10; ++row_x ) {
68         for( int row_y=row_x; row_y<10; ++row_y ) {
69             row_type row_i = MakeAbstractValueType<RowTag>(row_x);
70             row_type row_j = MakeAbstractValueType<RowTag>(row_y);
71             for( int row_grain=1; row_grain<10; ++row_grain ) {
72                 for( int col_x=-10; col_x<10; ++col_x ) {
73                     for( int col_y=col_x; col_y<10; ++col_y ) {
74                         col_type col_i = MakeAbstractValueType<ColTag>(col_x);
75                         col_type col_j = MakeAbstractValueType<ColTag>(col_y);
76                         for( int col_grain=1; col_grain<10; ++col_grain ) {
77                             range_type r( row_i, row_j, row_grain, col_i, col_j, col_grain );
78                             AssertSameType( r.is_divisible(), true );
79                             AssertSameType( r.empty(), true );
80                             AssertSameType( static_cast<range_type::row_range_type::const_iterator*>(0), static_cast<row_type*>(0) );
81                             AssertSameType( static_cast<range_type::col_range_type::const_iterator*>(0), static_cast<col_type*>(0) );
82                             AssertSameType( r.rows(), tbb::blocked_range<row_type>( row_i, row_j, 1 ));
83                             AssertSameType( r.cols(), tbb::blocked_range<col_type>( col_i, col_j, 1 ));
84                             ASSERT( r.empty()==(row_x==row_y||col_x==col_y), NULL );
85                             ASSERT( r.is_divisible()==(row_y-row_x>row_grain||col_y-col_x>col_grain), NULL );
86                             if( r.is_divisible() ) {
87                                 range_type r2(r,tbb::split());
88                                 if( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().begin()) ) {
89                                     ASSERT( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()), NULL );
90                                     ASSERT( GetValueOf(r2.cols().begin())==GetValueOf(r.cols().end()), NULL );
91                                 } else {
92                                     ASSERT( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()), NULL );
93                                     ASSERT( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().end()), NULL );
94                                 }
95                             }
96                         }
97                     }
98                 }
99             }
100         }
101     }
102 }
103 
104 #include "tbb/parallel_for.h"
105 #include "harness.h"
106 
107 const int N = 1<<10;
108 
109 unsigned char Array[N][N];
110 
111 struct Striker {
112    // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
operator ()Striker113     void operator()( const tbb::blocked_range2d<int>& r ) const {
114         for( tbb::blocked_range<int>::const_iterator i=r.rows().begin(); i!=r.rows().end(); ++i )
115             for( tbb::blocked_range<int>::const_iterator j=r.cols().begin(); j!=r.cols().end(); ++j )
116                 ++Array[i][j];
117     }
118 };
119 
ParallelTest()120 void ParallelTest() {
121     for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) {
122         for( int j=0; j<N; j=j<3 ? j+1 : j*3 ) {
123             const tbb::blocked_range2d<int> r( 0, i, 7, 0, j, 5 );
124             tbb::parallel_for( r, Striker() );
125             for( int k=0; k<N; ++k ) {
126                 for( int l=0; l<N; ++l ) {
127                     ASSERT( Array[k][l]==(k<i && l<j), NULL );
128                     Array[k][l] = 0;
129                 }
130             }
131         }
132     }
133 }
134 
135 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
136 #include <vector>
TestDeductionGuides()137 void TestDeductionGuides() {
138     std::vector<const unsigned long *> v;
139     std::vector<double> v2;
140 
141     // check blocked_range2d(RowValue, RowValue, size_t, ColValue, ColValue, size_t)
142     tbb::blocked_range2d r1(v.begin(), v.end(), 2, v2.begin(), v2.end(), 2);
143     static_assert(std::is_same<decltype(r1), tbb::blocked_range2d<decltype(v)::iterator, decltype(v2)::iterator>>::value);
144 
145     // check blocked_range2d(blocked_range2d &)
146     tbb::blocked_range2d r2(r1);
147     static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
148 
149     // check blocked_range2d(blocked_range2d &&)
150     tbb::blocked_range2d r3(std::move(r1));
151     static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
152 }
153 #endif
154 
155 #include "tbb/task_scheduler_init.h"
156 
TestMain()157 int TestMain () {
158     SerialTest();
159     for( int p=MinThread; p<=MaxThread; ++p ) {
160         tbb::task_scheduler_init init(p);
161         ParallelTest();
162     }
163 
164     #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
165         TestDeductionGuides();
166     #endif
167     return Harness::Done;
168 }
169