1/*
2 Copyright (c) 2005-2019 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
23template<typename Tag>
24class AbstractValueType {
25 AbstractValueType() {}
26 int value;
27public:
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
35template<typename Tag>
36AbstractValueType<Tag> MakeAbstractValueType( int i ) {
37 AbstractValueType<Tag> x;
38 x.value = i;
39 return x;
40}
41
42template<typename Tag>
43int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
44
45template<typename Tag>
46bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
47 return GetValueOf(u)<GetValueOf(v);
48}
49
50template<typename Tag>
51std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
52 return GetValueOf(u)-GetValueOf(v);
53}
54
55template<typename Tag>
56AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
57 return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
58}
59
60struct RowTag {};
61struct ColTag {};
62
63static 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
107const int N = 1<<10;
108
109unsigned char Array[N][N];
110
111struct Striker {
112 // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
113 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
120void 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>
137void 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
157int 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