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_range.h"
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/global_control.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #include <vector>
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev //! \file conformance_blocked_range.cpp
2951c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range] specification
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev class AbstractValueType {
AbstractValueType()3251c0b2f7Stbbdev     AbstractValueType() {}
3351c0b2f7Stbbdev     int value;
3451c0b2f7Stbbdev public:
3551c0b2f7Stbbdev     friend AbstractValueType MakeAbstractValueType( int i );
GetValueOf(const AbstractValueType & v)3651c0b2f7Stbbdev     friend int GetValueOf( const AbstractValueType& v ) {return v.value;}
3751c0b2f7Stbbdev };
3851c0b2f7Stbbdev 
MakeAbstractValueType(int i)3951c0b2f7Stbbdev AbstractValueType MakeAbstractValueType( int i ) {
4051c0b2f7Stbbdev     AbstractValueType x;
4151c0b2f7Stbbdev     x.value = i;
4251c0b2f7Stbbdev     return x;
4351c0b2f7Stbbdev }
4451c0b2f7Stbbdev 
operator -(const AbstractValueType & u,const AbstractValueType & v)4551c0b2f7Stbbdev std::size_t operator-( const AbstractValueType& u, const AbstractValueType& v ) {
4651c0b2f7Stbbdev     return GetValueOf(u) - GetValueOf(v);
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev 
operator <(const AbstractValueType & u,const AbstractValueType & v)4951c0b2f7Stbbdev bool operator<( const AbstractValueType& u, const AbstractValueType& v ) {
5051c0b2f7Stbbdev     return GetValueOf(u) < GetValueOf(v);
5151c0b2f7Stbbdev }
5251c0b2f7Stbbdev 
operator +(const AbstractValueType & u,std::size_t offset)5351c0b2f7Stbbdev AbstractValueType operator+( const AbstractValueType& u, std::size_t offset ) {
5451c0b2f7Stbbdev     return MakeAbstractValueType(GetValueOf(u) + int(offset));
5551c0b2f7Stbbdev }
5651c0b2f7Stbbdev 
SerialTest()5751c0b2f7Stbbdev static void SerialTest() {
5851c0b2f7Stbbdev     for( int x=-10; x<10; ++x ) {
5951c0b2f7Stbbdev         for( int y=-10; y<10; ++y ) {
6051c0b2f7Stbbdev             AbstractValueType i = MakeAbstractValueType(x);
6151c0b2f7Stbbdev             AbstractValueType j = MakeAbstractValueType(y);
6251c0b2f7Stbbdev             for( std::size_t k=1; k<10; ++k ) {
6349e08aacStbbdev                 typedef oneapi::tbb::blocked_range<AbstractValueType> range_type;
6451c0b2f7Stbbdev                 range_type r( i, j, k );
6551c0b2f7Stbbdev                 utils::AssertSameType( r.empty(), true );
6651c0b2f7Stbbdev                 utils::AssertSameType( range_type::size_type(), std::size_t() );
6757f524caSIlya Isaev                 utils::AssertSameType( static_cast<range_type::const_iterator*>(nullptr), static_cast<AbstractValueType*>(nullptr) );
6851c0b2f7Stbbdev                 utils::AssertSameType( r.begin(), MakeAbstractValueType(0) );
6951c0b2f7Stbbdev                 utils::AssertSameType( r.end(), MakeAbstractValueType(0) );
7051c0b2f7Stbbdev                 CHECK( r.empty()==(y<=x));
7151c0b2f7Stbbdev                 CHECK( r.grainsize()==k);
7251c0b2f7Stbbdev                 if( x<=y ) {
7351c0b2f7Stbbdev                     utils::AssertSameType( r.is_divisible(), true );
7451c0b2f7Stbbdev                     CHECK( r.is_divisible()==(std::size_t(y-x)>k) );
7551c0b2f7Stbbdev                     CHECK( r.size()==std::size_t(y-x) );
7651c0b2f7Stbbdev                     if( r.is_divisible() ) {
7749e08aacStbbdev                         oneapi::tbb::blocked_range<AbstractValueType> r2(r,oneapi::tbb::split());
7851c0b2f7Stbbdev                         CHECK( GetValueOf(r.begin())==x );
7951c0b2f7Stbbdev                         CHECK( GetValueOf(r.end())==GetValueOf(r2.begin()) );
8051c0b2f7Stbbdev                         CHECK( GetValueOf(r2.end())==y );
8151c0b2f7Stbbdev                         CHECK( r.grainsize()==k );
8251c0b2f7Stbbdev                         CHECK( r2.grainsize()==k );
8351c0b2f7Stbbdev                     }
8451c0b2f7Stbbdev                 }
8551c0b2f7Stbbdev             }
8651c0b2f7Stbbdev         }
8751c0b2f7Stbbdev     }
8851c0b2f7Stbbdev }
8951c0b2f7Stbbdev 
9051c0b2f7Stbbdev const int N = 1<<22;
9151c0b2f7Stbbdev unsigned char Array[N];
9251c0b2f7Stbbdev 
9351c0b2f7Stbbdev struct Striker {
operator ()Striker9449e08aacStbbdev     void operator()( const oneapi::tbb::blocked_range<int>& r ) const {
9549e08aacStbbdev         for( oneapi::tbb::blocked_range<int>::const_iterator i=r.begin(); i!=r.end(); ++i )
9651c0b2f7Stbbdev             ++Array[i];
9751c0b2f7Stbbdev     }
9851c0b2f7Stbbdev };
9951c0b2f7Stbbdev 
ParallelTest()10051c0b2f7Stbbdev void ParallelTest() {
10151c0b2f7Stbbdev     for (int i=0; i<N; i=i<3 ? i+1 : i*3) {
10249e08aacStbbdev         const oneapi::tbb::blocked_range<int> r( 0, i, 10 );
10349e08aacStbbdev         oneapi::tbb::parallel_for( r, Striker() );
10451c0b2f7Stbbdev         for (int k=0; k<N; ++k) {
10551c0b2f7Stbbdev             if (Array[k] != (k<i)) CHECK(false);
10651c0b2f7Stbbdev             Array[k] = 0;
10751c0b2f7Stbbdev         }
10851c0b2f7Stbbdev     }
10951c0b2f7Stbbdev }
11051c0b2f7Stbbdev 
11151c0b2f7Stbbdev //! Testing blocked_range interface
11251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
11351c0b2f7Stbbdev TEST_CASE("Basic serial") {
11451c0b2f7Stbbdev     SerialTest();
11551c0b2f7Stbbdev }
11651c0b2f7Stbbdev 
11751c0b2f7Stbbdev //! Testing blocked_range interface with parallel_for
11851c0b2f7Stbbdev //! \brief \ref requirement
11951c0b2f7Stbbdev TEST_CASE("Basic parallel") {
12051c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() ) {
12149e08aacStbbdev         oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
12251c0b2f7Stbbdev         ParallelTest();
12351c0b2f7Stbbdev     }
12451c0b2f7Stbbdev }
12551c0b2f7Stbbdev 
12651c0b2f7Stbbdev //! Testing blocked_range with proportional splitting
12751c0b2f7Stbbdev //! \brief \ref interface \ref requirement
12851c0b2f7Stbbdev TEST_CASE("blocked_range proportional splitting") {
12949e08aacStbbdev     oneapi::tbb::blocked_range<int> original(0, 100);
13049e08aacStbbdev     oneapi::tbb::blocked_range<int> first(original);
13149e08aacStbbdev     oneapi::tbb::proportional_split ps(3, 1);
13249e08aacStbbdev     oneapi::tbb::blocked_range<int> second(first, ps);
13351c0b2f7Stbbdev 
13451c0b2f7Stbbdev     // Test proportional_split -> split conversion
13549e08aacStbbdev     oneapi::tbb::blocked_range<int> copy(original);
13649e08aacStbbdev     oneapi::tbb::split s = oneapi::tbb::split(ps);
13749e08aacStbbdev     oneapi::tbb::blocked_range<int> splitted_copy(copy, s);
13851c0b2f7Stbbdev     CHECK(copy.size() == original.size() / 2);
13951c0b2f7Stbbdev     CHECK(splitted_copy.size() == copy.size());
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev 
14255f9b178SIvan Kochin     int expected_first_end = static_cast<int>(
14355f9b178SIvan Kochin         original.begin() + ps.left() * (original.end() - original.begin()) / (ps.left() + ps.right())
14455f9b178SIvan Kochin     );
14551c0b2f7Stbbdev     utils::check_range_bounds_after_splitting(original, first, second, expected_first_end);
14651c0b2f7Stbbdev }
14751c0b2f7Stbbdev 
14851c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
14951c0b2f7Stbbdev //! Testing blocked_range deduction guides
15051c0b2f7Stbbdev //! \brief \ref interface
15151c0b2f7Stbbdev TEST_CASE("Deduction guides") {
15251c0b2f7Stbbdev     std::vector<const int *> v;
15351c0b2f7Stbbdev 
15451c0b2f7Stbbdev     // check blocked_range(Value, Value, size_t)
15549e08aacStbbdev     oneapi::tbb::blocked_range r1(v.begin(), v.end());
15649e08aacStbbdev     static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range<decltype(v)::iterator>>::value);
15751c0b2f7Stbbdev 
15851c0b2f7Stbbdev     // check blocked_range(blocked_range &)
15949e08aacStbbdev     oneapi::tbb::blocked_range r2(r1);
16051c0b2f7Stbbdev     static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
16151c0b2f7Stbbdev 
16251c0b2f7Stbbdev     // check blocked_range(blocked_range &&)
16349e08aacStbbdev     oneapi::tbb::blocked_range r3(std::move(r1));
16451c0b2f7Stbbdev     static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
16551c0b2f7Stbbdev }
16651c0b2f7Stbbdev #endif
16751c0b2f7Stbbdev 
168