151c0b2f7Stbbdev /*
2*c4a799dfSJhaShweta1     Copyright (c) 2005-2023 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/state_trackable.h"
2151c0b2f7Stbbdev #include "common/container_move_support.h"
2251c0b2f7Stbbdev #include "common/custom_allocators.h"
2351c0b2f7Stbbdev #include "common/initializer_list_support.h"
2451c0b2f7Stbbdev #include "common/containers_common.h"
25b15aabb3Stbbdev #define __TBB_TEST_CPP20_COMPARISONS __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONCEPTS_PRESENT
26b15aabb3Stbbdev #include "common/test_comparisons.h"
2749e08aacStbbdev #include "oneapi/tbb/concurrent_vector.h"
2849e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2949e08aacStbbdev #include "oneapi/tbb/tick_count.h"
3049e08aacStbbdev #include "oneapi/tbb/global_control.h"
3151c0b2f7Stbbdev #include <initializer_list>
3251c0b2f7Stbbdev #include <numeric>
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev //! \file conformance_concurrent_vector.cpp
3551c0b2f7Stbbdev //! \brief Test for [containers.concurrent_vector] specification
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev const size_t N = 8192;
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev template<typename Vector, typename Iterator>
CheckConstIterator(const Vector & u,int i,const Iterator & cp)4051c0b2f7Stbbdev void CheckConstIterator( const Vector& u, int i, const Iterator& cp ) {
4151c0b2f7Stbbdev     typename Vector::const_reference pref = *cp;
4251c0b2f7Stbbdev     CHECK((pref.bar()==i));
4351c0b2f7Stbbdev     typename Vector::difference_type delta = cp-u.begin();
4451c0b2f7Stbbdev     REQUIRE( delta==i );
4551c0b2f7Stbbdev     CHECK((u[i].bar()==i));
4651c0b2f7Stbbdev     REQUIRE( u.begin()[i].bar()==i );
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev 
4951c0b2f7Stbbdev template<typename Iterator1, typename Iterator2, typename V>
CheckIteratorComparison(V & u)5051c0b2f7Stbbdev void CheckIteratorComparison( V& u ) {
5151c0b2f7Stbbdev     V u2 = u;
5251c0b2f7Stbbdev     Iterator1 i = u.begin();
5351c0b2f7Stbbdev 
5451c0b2f7Stbbdev     for( int i_count=0; i_count<100; ++i_count ) {
5551c0b2f7Stbbdev         Iterator2 j = u.begin();
5651c0b2f7Stbbdev         Iterator2 i2 = u2.begin();
5751c0b2f7Stbbdev         for( int j_count=0; j_count<100; ++j_count ) {
5851c0b2f7Stbbdev             REQUIRE( ((i==j)==(i_count==j_count)) );
5951c0b2f7Stbbdev             REQUIRE( ((i!=j)==(i_count!=j_count)) );
6051c0b2f7Stbbdev             REQUIRE( ((i-j)==(i_count-j_count)) );
6151c0b2f7Stbbdev             REQUIRE( ((i<j)==(i_count<j_count)) );
6251c0b2f7Stbbdev             REQUIRE( ((i>j)==(i_count>j_count)) );
6351c0b2f7Stbbdev             REQUIRE( ((i<=j)==(i_count<=j_count)) );
6451c0b2f7Stbbdev             REQUIRE( ((i>=j)==(i_count>=j_count)) );
6551c0b2f7Stbbdev             REQUIRE( (!(i==i2)) );
6651c0b2f7Stbbdev             REQUIRE( i!=i2 );
6751c0b2f7Stbbdev             ++j;
6851c0b2f7Stbbdev             ++i2;
6951c0b2f7Stbbdev         }
7051c0b2f7Stbbdev         ++i;
7151c0b2f7Stbbdev     }
7251c0b2f7Stbbdev }
7351c0b2f7Stbbdev 
7451c0b2f7Stbbdev template<typename Iterator1, typename Iterator2>
TestIteratorAssignment(Iterator2 j)7551c0b2f7Stbbdev void TestIteratorAssignment( Iterator2 j ) {
7651c0b2f7Stbbdev     Iterator1 i(j);
7751c0b2f7Stbbdev     REQUIRE( i==j );
7851c0b2f7Stbbdev     REQUIRE( !(i!=j) );
7951c0b2f7Stbbdev     Iterator1 k;
8051c0b2f7Stbbdev     k = j;
8151c0b2f7Stbbdev     REQUIRE( k==j );
8251c0b2f7Stbbdev     REQUIRE( !(k!=j) );
8351c0b2f7Stbbdev }
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev template<typename Range1, typename Range2>
TestRangeAssignment(Range2 r2)8651c0b2f7Stbbdev void TestRangeAssignment( Range2 r2 ) {
8751c0b2f7Stbbdev     Range1 r1(r2); r1 = r2;
8851c0b2f7Stbbdev }
8951c0b2f7Stbbdev 
9051c0b2f7Stbbdev template<typename T>
TestSequentialFor()9151c0b2f7Stbbdev void TestSequentialFor() {
9249e08aacStbbdev     using V = oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign>;
9351c0b2f7Stbbdev     V v(N);
9451c0b2f7Stbbdev     REQUIRE(v.grow_by(0) == v.grow_by(0, move_support_tests::FooWithAssign()));
9551c0b2f7Stbbdev 
9651c0b2f7Stbbdev     // Check iterator
9751c0b2f7Stbbdev     typename V::iterator p = v.begin();
9851c0b2f7Stbbdev     REQUIRE( !(*p).is_const() );
9951c0b2f7Stbbdev     REQUIRE( !p->is_const() );
10051c0b2f7Stbbdev     for( int i=0; std::size_t(i)<v.size(); ++i, ++p ) {
10151c0b2f7Stbbdev         CHECK( ((*p).state==move_support_tests::Foo::DefaultInitialized) );
10251c0b2f7Stbbdev         typename V::reference pref = *p;
10351c0b2f7Stbbdev         pref.bar() = i;
10451c0b2f7Stbbdev         typename V::difference_type delta = p-v.begin();
10551c0b2f7Stbbdev         REQUIRE( delta==i );
10651c0b2f7Stbbdev         REQUIRE_MESSAGE( (-delta<=0), "difference type not signed?" );
10751c0b2f7Stbbdev     }
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev     // Check const_iterator going forwards
11051c0b2f7Stbbdev     const V& u = v;
11151c0b2f7Stbbdev     typename V::const_iterator cp = u.begin();
11251c0b2f7Stbbdev     REQUIRE( cp == v.cbegin() );
11351c0b2f7Stbbdev     REQUIRE( (*cp).is_const() );
11451c0b2f7Stbbdev     REQUIRE( (cp->is_const()) );
11551c0b2f7Stbbdev     REQUIRE( (*cp == v.front()) );
11651c0b2f7Stbbdev     for( int i=0; std::size_t(i)<u.size(); ++i ) {
11751c0b2f7Stbbdev         CheckConstIterator(u,i,cp);
11851c0b2f7Stbbdev         V::const_iterator &cpr = ++cp;
11951c0b2f7Stbbdev         REQUIRE_MESSAGE( (&cpr == &cp), "pre-increment not returning a reference?");
12051c0b2f7Stbbdev     }
12151c0b2f7Stbbdev 
12251c0b2f7Stbbdev     // Now go backwards
12351c0b2f7Stbbdev     cp = u.end();
12451c0b2f7Stbbdev     REQUIRE( cp == v.cend() );
12551c0b2f7Stbbdev     for( int i=int(u.size()); i>0; ) {
12651c0b2f7Stbbdev         --i;
12751c0b2f7Stbbdev         V::const_iterator &cpr = --cp;
12851c0b2f7Stbbdev         REQUIRE_MESSAGE( &cpr == &cp, "pre-decrement not returning a reference?");
12951c0b2f7Stbbdev         if( i>0 ) {
13051c0b2f7Stbbdev             typename V::const_iterator cp_old = cp--;
13151c0b2f7Stbbdev             intptr_t here = (*cp_old).bar();
13251c0b2f7Stbbdev             REQUIRE( here==u[i].bar() );
13351c0b2f7Stbbdev             typename V::const_iterator cp_new = cp++;
13451c0b2f7Stbbdev             intptr_t prev = (*cp_new).bar();
13551c0b2f7Stbbdev             REQUIRE( prev==u[i-1].bar() );
13651c0b2f7Stbbdev         }
13751c0b2f7Stbbdev         CheckConstIterator(u,i,cp);
13851c0b2f7Stbbdev     }
13951c0b2f7Stbbdev 
14051c0b2f7Stbbdev     // Now go forwards and backwards
14151c0b2f7Stbbdev     std::ptrdiff_t k = 0;
14251c0b2f7Stbbdev     cp = u.begin();
14351c0b2f7Stbbdev     for( std::size_t i=0; i<u.size(); ++i ) {
14451c0b2f7Stbbdev         CheckConstIterator(u,int(k),cp);
14551c0b2f7Stbbdev         typename V::difference_type delta = i*3 % u.size();
14651c0b2f7Stbbdev         if( 0<=k+delta && std::size_t(k+delta)<u.size() ) {
14751c0b2f7Stbbdev             V::const_iterator &cpr = (cp += delta);
14851c0b2f7Stbbdev             REQUIRE_MESSAGE( (&cpr == &cp), "+= not returning a reference?");
14951c0b2f7Stbbdev             k += delta;
15051c0b2f7Stbbdev         }
15151c0b2f7Stbbdev         delta = i*7 % u.size();
15251c0b2f7Stbbdev         if( 0<=k-delta && std::size_t(k-delta)<u.size() ) {
15351c0b2f7Stbbdev             if( i&1 ) {
15451c0b2f7Stbbdev                 V::const_iterator &cpr = (cp -= delta);
15551c0b2f7Stbbdev                 REQUIRE_MESSAGE( (&cpr == &cp), "-= not returning a reference?");
15651c0b2f7Stbbdev             } else
15751c0b2f7Stbbdev                 cp = cp - delta;        // Test operator-
15851c0b2f7Stbbdev             k -= delta;
15951c0b2f7Stbbdev         }
16051c0b2f7Stbbdev     }
16151c0b2f7Stbbdev 
16251c0b2f7Stbbdev     for( int i=0; std::size_t(i)<u.size(); i=(i<50?i+1:i*3) )
16351c0b2f7Stbbdev         for( int j=-i; std::size_t(i+j)<u.size(); j=(j<50?j+1:j*5) ) {
16451c0b2f7Stbbdev             REQUIRE( ((u.begin()+i)[j].bar()==i+j) );
16551c0b2f7Stbbdev             REQUIRE( ((v.begin()+i)[j].bar()==i+j) );
16651c0b2f7Stbbdev             REQUIRE( ((v.cbegin()+i)[j].bar()==i+j) );
16751c0b2f7Stbbdev             REQUIRE( ((i+u.begin())[j].bar()==i+j) );
16851c0b2f7Stbbdev             REQUIRE( ((i+v.begin())[j].bar()==i+j) );
16951c0b2f7Stbbdev             REQUIRE(((i+v.cbegin())[j].bar()==i+j) );
17051c0b2f7Stbbdev         }
17151c0b2f7Stbbdev 
17251c0b2f7Stbbdev     CheckIteratorComparison<typename V::iterator, typename V::iterator>(v);
17351c0b2f7Stbbdev     CheckIteratorComparison<typename V::iterator, typename V::const_iterator>(v);
17451c0b2f7Stbbdev     CheckIteratorComparison<typename V::const_iterator, typename V::iterator>(v);
17551c0b2f7Stbbdev     CheckIteratorComparison<typename V::const_iterator, typename V::const_iterator>(v);
17651c0b2f7Stbbdev 
17751c0b2f7Stbbdev     TestIteratorAssignment<typename V::const_iterator>( u.begin() );
17851c0b2f7Stbbdev     TestIteratorAssignment<typename V::const_iterator>( v.begin() );
17951c0b2f7Stbbdev     TestIteratorAssignment<typename V::const_iterator>( v.cbegin() );
18051c0b2f7Stbbdev     TestIteratorAssignment<typename V::iterator>( v.begin() );
18151c0b2f7Stbbdev     // doesn't compile as expected: TestIteratorAssignment<typename V::iterator>( u.begin() );
18251c0b2f7Stbbdev 
18351c0b2f7Stbbdev     TestRangeAssignment<typename V::const_range_type>( u.range() );
18451c0b2f7Stbbdev     TestRangeAssignment<typename V::const_range_type>( v.range() );
18551c0b2f7Stbbdev     TestRangeAssignment<typename V::range_type>( v.range() );
18651c0b2f7Stbbdev     // doesn't compile as expected: TestRangeAssignment<typename V::range_type>( u.range() );
18751c0b2f7Stbbdev 
18851c0b2f7Stbbdev     // Check reverse_iterator
18951c0b2f7Stbbdev     typename V::reverse_iterator rp = v.rbegin();
19051c0b2f7Stbbdev     for( std::size_t i=v.size(); i>0; --i, ++rp ) {
19151c0b2f7Stbbdev         typename V::reference pref = *rp;
19251c0b2f7Stbbdev         REQUIRE( (std::size_t(pref.bar())==i-1) );
19351c0b2f7Stbbdev         REQUIRE( (rp!=v.rend()) );
19451c0b2f7Stbbdev     }
19551c0b2f7Stbbdev     REQUIRE( rp==v.rend() );
19651c0b2f7Stbbdev 
19751c0b2f7Stbbdev     // Check const_reverse_iterator
19851c0b2f7Stbbdev     typename V::const_reverse_iterator crp = u.rbegin();
19951c0b2f7Stbbdev     REQUIRE( crp == v.crbegin() );
20051c0b2f7Stbbdev     REQUIRE( *crp == v.back() );
20151c0b2f7Stbbdev     for(std::size_t i = v.size(); i>0; --i, ++crp) {
20251c0b2f7Stbbdev         typename V::const_reference cpref = *crp;
20351c0b2f7Stbbdev         REQUIRE( (std::size_t(cpref.bar())==i-1) );
20451c0b2f7Stbbdev         REQUIRE( crp!=u.rend() );
20551c0b2f7Stbbdev     }
20651c0b2f7Stbbdev     REQUIRE( crp == u.rend() );
20751c0b2f7Stbbdev     REQUIRE( crp == v.crend() );
20851c0b2f7Stbbdev 
20951c0b2f7Stbbdev     TestIteratorAssignment<typename V::const_reverse_iterator>( u.rbegin() );
21051c0b2f7Stbbdev     TestIteratorAssignment<typename V::reverse_iterator>( v.rbegin() );
21151c0b2f7Stbbdev 
21251c0b2f7Stbbdev     {
21349e08aacStbbdev         oneapi::tbb::concurrent_vector<int> v1, v2(1ul, 100);
21451c0b2f7Stbbdev         v1.assign(1, 100);
21551c0b2f7Stbbdev         REQUIRE(v1 == v2);
21651c0b2f7Stbbdev         REQUIRE_MESSAGE((v1.size() == 1 && v1[0] == 100), "used integral iterators");
21751c0b2f7Stbbdev     }
21851c0b2f7Stbbdev }
21951c0b2f7Stbbdev 
NextSize(int & s)22051c0b2f7Stbbdev inline void NextSize( int& s ) {
22151c0b2f7Stbbdev     if( s<=32 ) ++s;
22251c0b2f7Stbbdev     else s += s/10;
22351c0b2f7Stbbdev }
22451c0b2f7Stbbdev 
22551c0b2f7Stbbdev 
22651c0b2f7Stbbdev template<typename T, std::size_t N>
end(T (& array)[N])22751c0b2f7Stbbdev inline T* end( T(& array)[N]) {
22851c0b2f7Stbbdev     return array + utils::array_length(array) ;
22951c0b2f7Stbbdev }
23051c0b2f7Stbbdev 
23151c0b2f7Stbbdev template<typename vector_t>
CheckVector(const vector_t & cv,std::size_t expected_size,std::size_t)23251c0b2f7Stbbdev static void CheckVector( const vector_t& cv, std::size_t expected_size, std::size_t /*old_size*/ ) {
23351c0b2f7Stbbdev     REQUIRE( cv.capacity()>=expected_size );
23451c0b2f7Stbbdev     REQUIRE( cv.size()==expected_size );
23551c0b2f7Stbbdev     REQUIRE( cv.empty()==(expected_size==0) );
23651c0b2f7Stbbdev     for( int j=0; j<int(expected_size); ++j ) {
23751c0b2f7Stbbdev         CHECK((cv[j].bar()==~j));
23851c0b2f7Stbbdev     }
23951c0b2f7Stbbdev }
24051c0b2f7Stbbdev 
TestResizeAndCopy()24151c0b2f7Stbbdev void TestResizeAndCopy() {
24251c0b2f7Stbbdev     using allocator_t = StaticSharedCountingAllocator<std::allocator<move_support_tests::Foo>>;
24349e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::Foo, allocator_t>;
24451c0b2f7Stbbdev     allocator_t::init_counters();
24551c0b2f7Stbbdev     for( int old_size=0; old_size<=0; NextSize( old_size ) ) {
24651c0b2f7Stbbdev         for( int new_size=0; new_size<=8; NextSize( new_size ) ) {
24751c0b2f7Stbbdev             std::size_t count = move_support_tests::foo_count;
24851c0b2f7Stbbdev 
24951c0b2f7Stbbdev             vector_t v;
25051c0b2f7Stbbdev             REQUIRE( count==move_support_tests::foo_count );
25151c0b2f7Stbbdev             v.assign(old_size/2, move_support_tests::Foo() );
25251c0b2f7Stbbdev             REQUIRE( ((count+old_size/2) == move_support_tests::foo_count) );
25351c0b2f7Stbbdev             for( int j=0; j<old_size/2; ++j ){
25451c0b2f7Stbbdev                 REQUIRE( v[j].state == move_support_tests::Foo::CopyInitialized);
25551c0b2f7Stbbdev             }
25651c0b2f7Stbbdev 
25751c0b2f7Stbbdev             v.assign(move_support_tests::FooIterator(0), move_support_tests::FooIterator(old_size));
25851c0b2f7Stbbdev             v.resize(new_size, move_support_tests::Foo(33) );
25951c0b2f7Stbbdev             REQUIRE(count+new_size==move_support_tests::foo_count);
26051c0b2f7Stbbdev             for( int j=0; j<new_size; ++j ) {
26151c0b2f7Stbbdev                 int expected = j<old_size ? j : 33;
26251c0b2f7Stbbdev                 CHECK((v[j].bar()==expected));
26351c0b2f7Stbbdev             }
26451c0b2f7Stbbdev             REQUIRE( v.size()==std::size_t(new_size) );
26551c0b2f7Stbbdev             for( int j=0; j<new_size; ++j ) {
26651c0b2f7Stbbdev                 v[j].bar() = ~j;
26751c0b2f7Stbbdev             }
26851c0b2f7Stbbdev 
26951c0b2f7Stbbdev             const vector_t& cv = v;
27051c0b2f7Stbbdev             // Try copy constructor
27151c0b2f7Stbbdev             vector_t copy_of_v(cv);
27251c0b2f7Stbbdev             CheckVector(cv,new_size,old_size);
27351c0b2f7Stbbdev 
27451c0b2f7Stbbdev             REQUIRE( !(v != copy_of_v) );
27551c0b2f7Stbbdev             v.clear();
27651c0b2f7Stbbdev 
27751c0b2f7Stbbdev             REQUIRE( v.empty() );
27851c0b2f7Stbbdev             swap(v, copy_of_v);
27951c0b2f7Stbbdev             REQUIRE( copy_of_v.empty() );
28051c0b2f7Stbbdev             CheckVector(v,new_size,old_size);
28151c0b2f7Stbbdev         }
28251c0b2f7Stbbdev     }
28351c0b2f7Stbbdev     REQUIRE( allocator_t::items_constructed == allocator_t::items_destroyed );
28451c0b2f7Stbbdev     REQUIRE( allocator_t::items_allocated == allocator_t::items_freed );
28551c0b2f7Stbbdev     REQUIRE( allocator_t::allocations == allocator_t::frees );
28651c0b2f7Stbbdev }
28751c0b2f7Stbbdev 
28851c0b2f7Stbbdev 
TestCopyAssignment()28951c0b2f7Stbbdev void TestCopyAssignment() {
29051c0b2f7Stbbdev     using allocator_t = StaticCountingAllocator<std::allocator<move_support_tests::FooWithAssign>>;
29149e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t>;
29251c0b2f7Stbbdev     StaticCountingAllocator<std::allocator<move_support_tests::FooWithAssign>> init_alloc;
29351c0b2f7Stbbdev     for( int dst_size=1; dst_size<=128; NextSize( dst_size ) ) {
29451c0b2f7Stbbdev         for( int src_size=2; src_size<=128; NextSize( src_size ) ) {
29551c0b2f7Stbbdev             vector_t u(move_support_tests::FooIterator(0), move_support_tests::FooIterator(src_size), init_alloc);
29651c0b2f7Stbbdev             for( int i=0; i<src_size; ++i )
29751c0b2f7Stbbdev                 REQUIRE( u[i].bar()==i );
29851c0b2f7Stbbdev             vector_t v(dst_size, move_support_tests::FooWithAssign(), init_alloc);
29951c0b2f7Stbbdev             for( int i=0; i<dst_size; ++i ) {
30051c0b2f7Stbbdev                 REQUIRE( v[i].state==move_support_tests::Foo::CopyInitialized );
30151c0b2f7Stbbdev                 v[i].bar() = ~i;
30251c0b2f7Stbbdev             }
30351c0b2f7Stbbdev             REQUIRE( v != u );
30451c0b2f7Stbbdev             v.swap(u);
30551c0b2f7Stbbdev             CheckVector(u, dst_size, src_size);
30651c0b2f7Stbbdev             u.swap(v);
30751c0b2f7Stbbdev             // using assignment
30851c0b2f7Stbbdev             v = u;
30951c0b2f7Stbbdev             REQUIRE( v == u );
31051c0b2f7Stbbdev             u.clear();
31151c0b2f7Stbbdev             REQUIRE( u.size()==0 );
31251c0b2f7Stbbdev             REQUIRE( v.size()==std::size_t(src_size) );
31351c0b2f7Stbbdev             for( int i=0; i<src_size; ++i ){
31451c0b2f7Stbbdev                 REQUIRE( v[i].bar()==i );
31551c0b2f7Stbbdev             }
31651c0b2f7Stbbdev             u.shrink_to_fit(); // deallocate unused memory
31751c0b2f7Stbbdev         }
31851c0b2f7Stbbdev     }
31951c0b2f7Stbbdev     REQUIRE( allocator_t::items_allocated == allocator_t::items_freed );
32051c0b2f7Stbbdev     REQUIRE( allocator_t::allocations == allocator_t::frees );
32151c0b2f7Stbbdev }
32251c0b2f7Stbbdev 
32351c0b2f7Stbbdev template<typename Vector, typename T>
TestGrowToAtLeastWithSourceParameter(T const & src)32451c0b2f7Stbbdev void TestGrowToAtLeastWithSourceParameter(T const& src){
32551c0b2f7Stbbdev     static const std::size_t vector_size = 10;
32651c0b2f7Stbbdev     Vector v1(vector_size,src);
32751c0b2f7Stbbdev     Vector v2;
32851c0b2f7Stbbdev     v2.grow_to_at_least(vector_size,src);
32951c0b2f7Stbbdev     REQUIRE_MESSAGE(v1==v2,"grow_to_at_least(vector_size,src) did not properly initialize new elements ?");
33051c0b2f7Stbbdev }
33151c0b2f7Stbbdev 
TestCapacity()33251c0b2f7Stbbdev void TestCapacity() {
33349e08aacStbbdev     using allocator_t = StaticCountingAllocator<std::allocator<move_support_tests::Foo> /*TODO: oneapi::tbb::cache_aligned_allocator*/>;
33449e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::Foo, allocator_t>;
33551c0b2f7Stbbdev     allocator_t::init_counters();
33651c0b2f7Stbbdev     for( std::size_t old_size=0; old_size<=11000; old_size=(old_size<5 ? old_size+1 : 3*old_size) ) {
33751c0b2f7Stbbdev         for( std::size_t new_size=0; new_size<=11000; new_size=(new_size<5 ? new_size+1 : 3*new_size) ) {
33851c0b2f7Stbbdev             std::size_t count = move_support_tests::foo_count;
33951c0b2f7Stbbdev             {
34051c0b2f7Stbbdev                 vector_t v; v.reserve(old_size);
34151c0b2f7Stbbdev                 REQUIRE( v.capacity()>=old_size );
34251c0b2f7Stbbdev                 v.reserve( new_size );
34351c0b2f7Stbbdev                 REQUIRE( v.capacity()>=old_size );
34451c0b2f7Stbbdev                 REQUIRE( v.capacity()>=new_size );
34551c0b2f7Stbbdev                 REQUIRE( v.empty() );
34651c0b2f7Stbbdev                 std::size_t fill_size = 2*new_size;
34751c0b2f7Stbbdev                 for (std::size_t i=0; i<fill_size; ++i) {
34851c0b2f7Stbbdev                     REQUIRE( std::size_t(move_support_tests::foo_count)==count+i );
34951c0b2f7Stbbdev                     std::size_t j = v.grow_by(1) - v.begin();
35051c0b2f7Stbbdev                     REQUIRE( j==i );
35151c0b2f7Stbbdev                     v[j].bar() = int(~j);
35251c0b2f7Stbbdev                 }
35351c0b2f7Stbbdev                 vector_t copy_of_v(v); // should allocate first segment with same size as for shrink_to_fit()
35449e08aacStbbdev                 if(oneapi::tbb::detail::log2(/*reserved size*/old_size|1) > oneapi::tbb::detail::log2(fill_size|1) ){
35551c0b2f7Stbbdev                    REQUIRE( v.capacity() != copy_of_v.capacity() );
35651c0b2f7Stbbdev                 }
35751c0b2f7Stbbdev                 v.shrink_to_fit();
35851c0b2f7Stbbdev                 REQUIRE( v.capacity() == copy_of_v.capacity() );
35951c0b2f7Stbbdev                 CheckVector(v, new_size*2, old_size); // check vector correctness
36051c0b2f7Stbbdev                 REQUIRE( v==copy_of_v ); // TODO: check also segments layout equality
36151c0b2f7Stbbdev             }
36251c0b2f7Stbbdev             REQUIRE( move_support_tests::foo_count==count );
36351c0b2f7Stbbdev         }
36451c0b2f7Stbbdev     }
36551c0b2f7Stbbdev     REQUIRE( allocator_t::items_allocated == allocator_t::items_freed );
36651c0b2f7Stbbdev     REQUIRE( allocator_t::allocations == allocator_t::frees );
36751c0b2f7Stbbdev }
36851c0b2f7Stbbdev 
36951c0b2f7Stbbdev template<typename c_vector>
get_early_size(c_vector & v)37051c0b2f7Stbbdev std::size_t get_early_size(c_vector & v){
37151c0b2f7Stbbdev       return v.grow_by(0) - v.begin();
37251c0b2f7Stbbdev }
37351c0b2f7Stbbdev 
verify_c_vector_size(std::size_t size,std::size_t capacity,std::size_t early_size)37451c0b2f7Stbbdev void verify_c_vector_size(std::size_t size, std::size_t capacity, std::size_t early_size){
37551c0b2f7Stbbdev     REQUIRE( size <= capacity );
37651c0b2f7Stbbdev     REQUIRE( early_size >= size );
37751c0b2f7Stbbdev }
37851c0b2f7Stbbdev 
37951c0b2f7Stbbdev template<typename c_vector_t>
verify_c_vector_size(c_vector_t & c_v)38051c0b2f7Stbbdev void verify_c_vector_size(c_vector_t & c_v){
38151c0b2f7Stbbdev     verify_c_vector_size(c_v.size(), c_v.capacity(), get_early_size(c_v));
38251c0b2f7Stbbdev }
38351c0b2f7Stbbdev 
38451c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
TestExceptions()38551c0b2f7Stbbdev void TestExceptions() {
38651c0b2f7Stbbdev     using allocator_t = StaticSharedCountingAllocator<std::allocator<move_support_tests::FooWithAssign>>;
38749e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t>;
38851c0b2f7Stbbdev 
38951c0b2f7Stbbdev     enum methods {
39051c0b2f7Stbbdev         zero_method = 0,
39151c0b2f7Stbbdev         ctor_copy, ctor_size, assign_nt, assign_ir, reserve, compact,
39251c0b2f7Stbbdev         all_methods
39351c0b2f7Stbbdev     };
39451c0b2f7Stbbdev     REQUIRE( !move_support_tests::foo_count );
39551c0b2f7Stbbdev 
39651c0b2f7Stbbdev     try {
39751c0b2f7Stbbdev         vector_t src(move_support_tests::FooIterator(0), move_support_tests::FooIterator(N)); // original data
39851c0b2f7Stbbdev 
39951c0b2f7Stbbdev         for(int t = 0; t < 2; ++t) // exception type
40051c0b2f7Stbbdev         for(int m = zero_method+1; m < all_methods; ++m)
40151c0b2f7Stbbdev         {
40251c0b2f7Stbbdev             move_support_tests::track_foo_count<__LINE__> check_all_foo_destroyed_on_exit{};
40351c0b2f7Stbbdev             move_support_tests::track_allocator_memory<allocator_t> verify_no_leak_at_exit{};
40451c0b2f7Stbbdev             allocator_t::init_counters();
40551c0b2f7Stbbdev             if(t) move_support_tests::max_foo_count = move_support_tests::foo_count + N/4;
40651c0b2f7Stbbdev             else allocator_t::set_limits(N/4);
40751c0b2f7Stbbdev             vector_t victim;
40851c0b2f7Stbbdev             try {
40951c0b2f7Stbbdev                 switch(m) {
41051c0b2f7Stbbdev                 case ctor_copy: {
41151c0b2f7Stbbdev                         vector_t acopy(src);
41251c0b2f7Stbbdev                     } break; // auto destruction after exception is checked by ~Foo
41351c0b2f7Stbbdev                 case ctor_size: {
41451c0b2f7Stbbdev                         vector_t sized(N);
41551c0b2f7Stbbdev                     } break; // auto destruction after exception is checked by ~Foo
41651c0b2f7Stbbdev                 // Do not test assignment constructor due to reusing of same methods as below
41751c0b2f7Stbbdev                 case assign_nt: {
41851c0b2f7Stbbdev                         victim.assign(N, move_support_tests::FooWithAssign());
41951c0b2f7Stbbdev                     } break;
42051c0b2f7Stbbdev                 case assign_ir: {
42151c0b2f7Stbbdev                         victim.assign(move_support_tests::FooIterator(0), move_support_tests::FooIterator(N));
42251c0b2f7Stbbdev                     } break;
42351c0b2f7Stbbdev                 case reserve: {
42451c0b2f7Stbbdev                         try {
42551c0b2f7Stbbdev                             victim.reserve(victim.max_size()+1);
42651c0b2f7Stbbdev                         } catch(std::length_error &) {
42751c0b2f7Stbbdev                         } catch(...) {
42851c0b2f7Stbbdev                             INFO("ERROR: unrecognized exception - known compiler issue\n");
42951c0b2f7Stbbdev                         }
43051c0b2f7Stbbdev                         victim.reserve(N);
43151c0b2f7Stbbdev                     } break;
43251c0b2f7Stbbdev                 case compact: {
43351c0b2f7Stbbdev                         if(t) move_support_tests::max_foo_count = 0; else allocator_t::set_limits(); // reset limits
43451c0b2f7Stbbdev                         victim.reserve(2);
43551c0b2f7Stbbdev                         victim = src; // fragmented assignment
43651c0b2f7Stbbdev                         if(t) {
43751c0b2f7Stbbdev                             move_support_tests::max_foo_count = move_support_tests::foo_count + 10;
43851c0b2f7Stbbdev                         }
43951c0b2f7Stbbdev                         else {
44051c0b2f7Stbbdev                             allocator_t::set_limits(1); // block any allocation
44151c0b2f7Stbbdev                         }
44251c0b2f7Stbbdev                         victim.shrink_to_fit(); // should start defragmenting first segment
44351c0b2f7Stbbdev                     } break;
44451c0b2f7Stbbdev                 default:;
44551c0b2f7Stbbdev                 }
44651c0b2f7Stbbdev                 if(!t || m != reserve) REQUIRE_MESSAGE(false, "should throw an exception");
44751c0b2f7Stbbdev             } catch(std::bad_alloc &e) {
44851c0b2f7Stbbdev                 allocator_t::set_limits(); move_support_tests::max_foo_count = 0;
44951c0b2f7Stbbdev                 std::size_t capacity = victim.capacity();
45051c0b2f7Stbbdev                 std::size_t size = victim.size();
45151c0b2f7Stbbdev 
45251c0b2f7Stbbdev                 std::size_t req_size = get_early_size(victim);
45351c0b2f7Stbbdev 
45451c0b2f7Stbbdev                 verify_c_vector_size(size, capacity, req_size);
45551c0b2f7Stbbdev 
45651c0b2f7Stbbdev                 switch(m) {
45751c0b2f7Stbbdev                 case reserve:
45851c0b2f7Stbbdev                     if(t) REQUIRE(false);
45951c0b2f7Stbbdev                     utils_fallthrough;
46051c0b2f7Stbbdev                 case assign_nt:
46151c0b2f7Stbbdev                 case assign_ir:
46251c0b2f7Stbbdev                     if(!t) {
46351c0b2f7Stbbdev                         REQUIRE_MESSAGE(capacity < N/2, "unexpected capacity");
46451c0b2f7Stbbdev                         REQUIRE_MESSAGE(size == 0, "unexpected size");
46551c0b2f7Stbbdev                         break;
46651c0b2f7Stbbdev                     } else {
46751c0b2f7Stbbdev                         REQUIRE_MESSAGE(size == N, "unexpected size");
46851c0b2f7Stbbdev                         REQUIRE_MESSAGE(capacity >= N, "unexpected capacity");
46951c0b2f7Stbbdev                         int i;
47051c0b2f7Stbbdev                         for(i = 1; ; ++i)
47151c0b2f7Stbbdev                             if(!victim[i].zero_bar()) break;
47251c0b2f7Stbbdev                             else {
47351c0b2f7Stbbdev                                 REQUIRE(victim[i].bar() == (m == assign_ir? i : move_support_tests::initial_bar));
47451c0b2f7Stbbdev                             }
47551c0b2f7Stbbdev                         for(; size_t(i) < size; ++i) {
47651c0b2f7Stbbdev                             REQUIRE(!victim[i].zero_bar());
47751c0b2f7Stbbdev                         }
47851c0b2f7Stbbdev                         REQUIRE(size_t(i) == size);
47951c0b2f7Stbbdev                         break;
48051c0b2f7Stbbdev                     }
48151c0b2f7Stbbdev                 case compact:
48251c0b2f7Stbbdev                     REQUIRE_MESSAGE(capacity > 0, "unexpected capacity");
48351c0b2f7Stbbdev                     REQUIRE_MESSAGE(victim == src, "shrink_to_fit() is broken");
48451c0b2f7Stbbdev                     break;
48551c0b2f7Stbbdev 
48651c0b2f7Stbbdev                 default:; // nothing to check here
48751c0b2f7Stbbdev                 }
48851c0b2f7Stbbdev                 INFO("Exception " << m << ": " << e.what() << "\t- ok\n");
48951c0b2f7Stbbdev             }
49051c0b2f7Stbbdev         }
49151c0b2f7Stbbdev     } catch(...) {
49251c0b2f7Stbbdev         REQUIRE_MESSAGE(false, "unexpected exception");
49351c0b2f7Stbbdev     }
49451c0b2f7Stbbdev }
49551c0b2f7Stbbdev #endif
49651c0b2f7Stbbdev 
verify_c_vector_capacity_is_below(size_t capacity,size_t high)49751c0b2f7Stbbdev void verify_c_vector_capacity_is_below(size_t capacity, size_t high){
49851c0b2f7Stbbdev     REQUIRE_MESSAGE(capacity > 0, "unexpected capacity");
49951c0b2f7Stbbdev     REQUIRE_MESSAGE(capacity < high, "unexpected capacity");
50051c0b2f7Stbbdev }
50151c0b2f7Stbbdev 
50251c0b2f7Stbbdev template<typename allocator_t>
verify_vector_partially_copied(oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign,allocator_t> const & victim,size_t planned_victim_size,oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign,allocator_t> const & src,bool is_memory_allocation_failure)50351c0b2f7Stbbdev void verify_vector_partially_copied(
50449e08aacStbbdev         oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t> const& victim, size_t planned_victim_size,
50549e08aacStbbdev         oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t> const& src,  bool is_memory_allocation_failure)
50651c0b2f7Stbbdev {
50751c0b2f7Stbbdev     if (is_memory_allocation_failure) { // allocator generated exception
50849e08aacStbbdev         using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t>;
50951c0b2f7Stbbdev         REQUIRE_MESSAGE( victim == vector_t(src.begin(), src.begin() + victim.size(), src.get_allocator()), "failed to properly copy of source ?" );
51051c0b2f7Stbbdev     }else{
51151c0b2f7Stbbdev         REQUIRE_MESSAGE( std::equal(victim.begin(), victim.begin() + planned_victim_size, src.begin()), "failed to properly copy items before the exception?" );
51251c0b2f7Stbbdev         REQUIRE_MESSAGE( (std::all_of( victim.begin() + planned_victim_size, victim.end(), is_state_predicate<move_support_tests::Foo::ZeroInitialized>()) ), "failed to zero-initialize items left not constructed after the exception?" );
51351c0b2f7Stbbdev     }
51451c0b2f7Stbbdev }
51551c0b2f7Stbbdev 
51651c0b2f7Stbbdev template<typename vector_t>
verify_last_segment_allocation_failed(vector_t const & victim)51751c0b2f7Stbbdev void verify_last_segment_allocation_failed(vector_t const& victim){
51851c0b2f7Stbbdev     utils::suppress_unused_warning(victim);
51951c0b2f7Stbbdev     CHECK_THROWS_AS((victim.at(victim.size())), std::out_of_range);
52051c0b2f7Stbbdev }
52151c0b2f7Stbbdev 
52251c0b2f7Stbbdev template<typename vector_t>
verify_copy_and_assign_from_produce_the_same(vector_t const & victim)52351c0b2f7Stbbdev void verify_copy_and_assign_from_produce_the_same(vector_t const& victim){
52451c0b2f7Stbbdev     //TODO: remove explicit copy of allocator when full support of C++11 allocator_traits in concurrent_vector is present
52551c0b2f7Stbbdev     vector_t copy_of_victim(victim, victim.get_allocator());
52651c0b2f7Stbbdev     REQUIRE_MESSAGE(copy_of_victim == victim, "copy doesn't match original");
52751c0b2f7Stbbdev     vector_t copy_of_victim2(10, victim[0], victim.get_allocator());
52851c0b2f7Stbbdev     copy_of_victim2 = victim;
52951c0b2f7Stbbdev     REQUIRE_MESSAGE(copy_of_victim == copy_of_victim2, "assignment doesn't match copying");
53051c0b2f7Stbbdev }
53151c0b2f7Stbbdev 
53251c0b2f7Stbbdev template<typename vector_t>
verify_assignment_operator_throws_bad_last_alloc(vector_t & victim)53351c0b2f7Stbbdev void verify_assignment_operator_throws_bad_last_alloc(vector_t & victim){
53451c0b2f7Stbbdev     vector_t copy_of_victim(victim, victim.get_allocator());
53549e08aacStbbdev     //CHECK_THROWS_AS(victim = copy_of_victim, oneapi::tbb::bad_last_alloc); //TODO exceptions support
53651c0b2f7Stbbdev }
53751c0b2f7Stbbdev 
53855f9b178SIvan Kochin #if _MSC_VER
53955f9b178SIvan Kochin #pragma warning (push)
54055f9b178SIvan Kochin // Forcing value to bool 'true' or 'false'
54155f9b178SIvan Kochin #pragma warning (disable: 4800)
54255f9b178SIvan Kochin #endif //#if _MSC_VER
54355f9b178SIvan Kochin 
54451c0b2f7Stbbdev //TODO: split into two separate tests
54551c0b2f7Stbbdev //TODO: remove code duplication in exception safety tests
test_ex_assign_operator()54651c0b2f7Stbbdev void test_ex_assign_operator(){
54751c0b2f7Stbbdev     //TODO: use __FUNCTION__ for test name
54851c0b2f7Stbbdev     using allocator_t = StaticCountingAllocator<std::allocator<move_support_tests::FooWithAssign>>;
54949e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_support_tests::FooWithAssign, allocator_t>;
55051c0b2f7Stbbdev 
55151c0b2f7Stbbdev     move_support_tests::track_foo_count<__LINE__> check_all_foo_destroyed_on_exit{};
55251c0b2f7Stbbdev     move_support_tests::track_allocator_memory<allocator_t> verify_no_leak_at_exit{};
55351c0b2f7Stbbdev 
55451c0b2f7Stbbdev     vector_t src(move_support_tests::FooIterator(0), move_support_tests::FooIterator(N)); // original data
55551c0b2f7Stbbdev 
55651c0b2f7Stbbdev     const size_t planned_victim_size = N/4;
55751c0b2f7Stbbdev 
55851c0b2f7Stbbdev     for(int t = 0; t < 2; ++t) { // exception type
55951c0b2f7Stbbdev         vector_t victim;
56051c0b2f7Stbbdev         victim.reserve(2); // get fragmented assignment
56151c0b2f7Stbbdev         REQUIRE_THROWS_AS([&](){
56251c0b2f7Stbbdev             move_support_tests::LimitFooCountInScope foo_limit(move_support_tests::foo_count + planned_victim_size, t);
56351c0b2f7Stbbdev             move_support_tests::LimitAllocatedItemsInScope<allocator_t> allocator_limit(allocator_t::items_allocated + planned_victim_size, !t);
56451c0b2f7Stbbdev 
56551c0b2f7Stbbdev             victim = src; // fragmented assignment
56651c0b2f7Stbbdev         }(), const std::bad_alloc);
56751c0b2f7Stbbdev 
56851c0b2f7Stbbdev         verify_c_vector_size(victim);
56951c0b2f7Stbbdev 
57051c0b2f7Stbbdev         if(!t) {
57151c0b2f7Stbbdev             verify_c_vector_capacity_is_below(victim.capacity(), N);
57251c0b2f7Stbbdev         }
57351c0b2f7Stbbdev 
57451c0b2f7Stbbdev         verify_vector_partially_copied(victim, planned_victim_size, src, !t);
57551c0b2f7Stbbdev         verify_last_segment_allocation_failed(victim);
57651c0b2f7Stbbdev         verify_copy_and_assign_from_produce_the_same(victim);
57751c0b2f7Stbbdev         verify_assignment_operator_throws_bad_last_alloc(victim); //TODO exceptions support
57851c0b2f7Stbbdev     }
57951c0b2f7Stbbdev }
58051c0b2f7Stbbdev 
58155f9b178SIvan Kochin #if _MSC_VER
58255f9b178SIvan Kochin #pragma warning (pop)
58355f9b178SIvan Kochin #endif
58455f9b178SIvan Kochin 
58551c0b2f7Stbbdev template<typename T>
AssertSameType(const T &,const T &)58651c0b2f7Stbbdev void AssertSameType( const T& /*x*/, const T& /*y*/ ) {}
58751c0b2f7Stbbdev 
58851c0b2f7Stbbdev struct test_grow_by {
58951c0b2f7Stbbdev     template<typename container_type, typename element_type>
testtest_grow_by59051c0b2f7Stbbdev     static void test( std::initializer_list<element_type> const& il, container_type const& expected ) {
59151c0b2f7Stbbdev         container_type vd;
59251c0b2f7Stbbdev         vd.grow_by( il );
59351c0b2f7Stbbdev         REQUIRE_MESSAGE( vd == expected, "grow_by with an initializer list failed" );
59451c0b2f7Stbbdev     }
59551c0b2f7Stbbdev };
59651c0b2f7Stbbdev 
59751c0b2f7Stbbdev template<typename Iterator, typename T>
TestIteratorTraits()59851c0b2f7Stbbdev void TestIteratorTraits() {
59957f524caSIlya Isaev     AssertSameType( static_cast<typename Iterator::difference_type*>(nullptr), static_cast<std::ptrdiff_t*>(nullptr) );
60057f524caSIlya Isaev     AssertSameType( static_cast<typename Iterator::value_type*>(nullptr), static_cast<T*>(nullptr) );
60157f524caSIlya Isaev     AssertSameType( static_cast<typename Iterator::pointer*>(nullptr), static_cast<T**>(nullptr) );
60257f524caSIlya Isaev     AssertSameType( static_cast<typename Iterator::iterator_category*>(nullptr), static_cast<std::random_access_iterator_tag*>(nullptr) );
60351c0b2f7Stbbdev     T x;
60451c0b2f7Stbbdev     typename Iterator::reference xr = x;
60551c0b2f7Stbbdev     typename Iterator::pointer xp = &x;
60651c0b2f7Stbbdev     REQUIRE( &xr==xp );
60751c0b2f7Stbbdev }
60851c0b2f7Stbbdev 
TestInitList()60951c0b2f7Stbbdev void TestInitList() {
61051c0b2f7Stbbdev     using namespace initializer_list_support_tests;
61149e08aacStbbdev     test_initializer_list_support<oneapi::tbb::concurrent_vector<char>, test_grow_by>( { 1, 2, 3, 4, 5 } );
61249e08aacStbbdev     test_initializer_list_support<oneapi::tbb::concurrent_vector<int>, test_grow_by>( {} );
61351c0b2f7Stbbdev }
61451c0b2f7Stbbdev 
61551c0b2f7Stbbdev namespace TestMoveInShrinkToFitHelpers {
61651c0b2f7Stbbdev     struct dummy : StateTrackable<>{
61751c0b2f7Stbbdev         int i;
dummyTestMoveInShrinkToFitHelpers::dummy61851c0b2f7Stbbdev         dummy(int an_i) noexcept : StateTrackable<>(0), i(an_i) {}
61951c0b2f7Stbbdev 
operator ==(const dummy & lhs,const dummy & rhs)62051c0b2f7Stbbdev         friend bool operator== (const dummy &lhs, const dummy &rhs){ return lhs.i == rhs.i; }
62151c0b2f7Stbbdev     };
62251c0b2f7Stbbdev }
62351c0b2f7Stbbdev 
TestSerialMoveInShrinkToFit()62451c0b2f7Stbbdev void TestSerialMoveInShrinkToFit(){
62551c0b2f7Stbbdev     using TestMoveInShrinkToFitHelpers::dummy;
62651c0b2f7Stbbdev 
62751c0b2f7Stbbdev     static_assert(std::is_nothrow_move_constructible<dummy>::value,"incorrect test setup or broken configuration?");
62851c0b2f7Stbbdev     {
62951c0b2f7Stbbdev         dummy src(0);
63051c0b2f7Stbbdev         REQUIRE_MESSAGE(is_state<StateTrackableBase::MoveInitialized>(dummy(std::move_if_noexcept(src))),"broken configuration ?");
63151c0b2f7Stbbdev     }
63251c0b2f7Stbbdev     static const std::size_t sequence_size = 15;
63349e08aacStbbdev     using c_vector_t = oneapi::tbb::concurrent_vector<dummy>;
63451c0b2f7Stbbdev     std::vector<dummy> source(sequence_size, 0);
63551c0b2f7Stbbdev     std::generate_n(source.begin(), source.size(), std::rand);
63651c0b2f7Stbbdev 
63751c0b2f7Stbbdev     c_vector_t c_vector;
63851c0b2f7Stbbdev     c_vector.reserve(1); //make it fragmented
63951c0b2f7Stbbdev 
64051c0b2f7Stbbdev     c_vector.assign(source.begin(), source.end());
64151c0b2f7Stbbdev     move_support_tests::MemoryLocations c_vector_before_shrink(c_vector);
64251c0b2f7Stbbdev     c_vector.shrink_to_fit();
64351c0b2f7Stbbdev 
64451c0b2f7Stbbdev     REQUIRE_MESSAGE(c_vector_before_shrink.content_location_changed(c_vector), "incorrect test setup? shrink_to_fit should cause moving elements to other memory locations while it is not");
64551c0b2f7Stbbdev     REQUIRE_MESSAGE((std::all_of(c_vector.begin(), c_vector.end(), is_state_predicate<StateTrackableBase::MoveInitialized>())), "container did not move construct some elements?");
64651c0b2f7Stbbdev     REQUIRE((c_vector == c_vector_t(source.begin(),source.end())));
64751c0b2f7Stbbdev }
64851c0b2f7Stbbdev 
64951c0b2f7Stbbdev struct default_container_traits {
65051c0b2f7Stbbdev     template <typename container_type, typename iterator_type>
construct_containerdefault_container_traits65151c0b2f7Stbbdev     static container_type& construct_container(typename std::aligned_storage<sizeof(container_type)>::type& storage, iterator_type begin, iterator_type end){
65251c0b2f7Stbbdev         container_type* ptr = reinterpret_cast<container_type*>(&storage);
65351c0b2f7Stbbdev         new (ptr) container_type(begin, end);
65451c0b2f7Stbbdev         return *ptr;
65551c0b2f7Stbbdev     }
65651c0b2f7Stbbdev 
65751c0b2f7Stbbdev     template <typename container_type, typename iterator_type, typename allocator_type>
construct_containerdefault_container_traits65851c0b2f7Stbbdev     static container_type& construct_container(typename std::aligned_storage<sizeof(container_type)>::type& storage, iterator_type begin, iterator_type end, allocator_type const& a){
65951c0b2f7Stbbdev         container_type* ptr = reinterpret_cast<container_type*>(&storage);
66051c0b2f7Stbbdev         new (ptr) container_type(begin, end, a);
66151c0b2f7Stbbdev         return *ptr;
66251c0b2f7Stbbdev     }
66351c0b2f7Stbbdev };
66451c0b2f7Stbbdev 
66551c0b2f7Stbbdev struct c_vector_type : default_container_traits {
66651c0b2f7Stbbdev     template <typename T, typename Allocator>
66749e08aacStbbdev     using container_type = oneapi::tbb::concurrent_vector<T, Allocator>;
66851c0b2f7Stbbdev 
66951c0b2f7Stbbdev     template <typename T>
67051c0b2f7Stbbdev     using container_value_type = T;
67151c0b2f7Stbbdev 
67251c0b2f7Stbbdev     using init_iterator_type = move_support_tests::FooIterator;
67351c0b2f7Stbbdev     template<typename element_type, typename allocator_type>
67451c0b2f7Stbbdev     struct apply{
67549e08aacStbbdev         using type = oneapi::tbb::concurrent_vector<element_type,  allocator_type >;
67651c0b2f7Stbbdev     };
67751c0b2f7Stbbdev 
67851c0b2f7Stbbdev     enum{ expected_number_of_items_to_allocate_for_steal_move = 0 };
67951c0b2f7Stbbdev 
68051c0b2f7Stbbdev     template<typename element_type, typename allocator_type, typename iterator>
equalc_vector_type68149e08aacStbbdev     static bool equal(oneapi::tbb::concurrent_vector<element_type, allocator_type > const& c, iterator begin, iterator end){
68251c0b2f7Stbbdev         bool equal_sizes = (std::size_t)std::distance(begin, end) == c.size();
68351c0b2f7Stbbdev         return  equal_sizes && std::equal(c.begin(), c.end(), begin);
68451c0b2f7Stbbdev     }
68551c0b2f7Stbbdev };
68651c0b2f7Stbbdev 
TestSerialGrowByWithMoveIterators()68751c0b2f7Stbbdev void TestSerialGrowByWithMoveIterators(){
68851c0b2f7Stbbdev     using fixture_t = move_support_tests::DefaultStatefulFixtureHelper<c_vector_type>::type;
68951c0b2f7Stbbdev     using vector_t = fixture_t::container_type;
69051c0b2f7Stbbdev 
69151c0b2f7Stbbdev     fixture_t fixture;
69251c0b2f7Stbbdev 
69351c0b2f7Stbbdev     vector_t dst(fixture.dst_allocator);
69451c0b2f7Stbbdev     dst.grow_by(std::make_move_iterator(fixture.source.begin()), std::make_move_iterator(fixture.source.end()));
69551c0b2f7Stbbdev 
69651c0b2f7Stbbdev     fixture.verify_content_deep_moved(dst);
69751c0b2f7Stbbdev }
69851c0b2f7Stbbdev 
69951c0b2f7Stbbdev namespace test_grow_to_at_least_helpers {
70051c0b2f7Stbbdev     template<typename MyVector >
70151c0b2f7Stbbdev     class GrowToAtLeast {
70251c0b2f7Stbbdev         using const_reference = typename MyVector::const_reference;
70351c0b2f7Stbbdev 
70451c0b2f7Stbbdev         const bool my_use_two_args_form ;
70551c0b2f7Stbbdev         MyVector& my_vector;
70651c0b2f7Stbbdev         const_reference my_init_from;
70751c0b2f7Stbbdev     public:
operator ()(const oneapi::tbb::blocked_range<std::size_t> & range) const70849e08aacStbbdev         void operator()( const oneapi::tbb::blocked_range<std::size_t>& range ) const {
70951c0b2f7Stbbdev             for( std::size_t i=range.begin(); i!=range.end(); ++i ) {
71051c0b2f7Stbbdev                 std::size_t n = my_vector.size();
71151c0b2f7Stbbdev                 std::size_t req = (i % (2*n+1))+1;
71251c0b2f7Stbbdev 
71351c0b2f7Stbbdev                 typename MyVector::iterator p;
71451c0b2f7Stbbdev                 move_support_tests::Foo::State desired_state;
71551c0b2f7Stbbdev                 if (my_use_two_args_form){
71651c0b2f7Stbbdev                     p = my_vector.grow_to_at_least(req,my_init_from);
71751c0b2f7Stbbdev                     desired_state = move_support_tests::Foo::CopyInitialized;
71851c0b2f7Stbbdev                 }else{
71951c0b2f7Stbbdev                     p = my_vector.grow_to_at_least(req);
72051c0b2f7Stbbdev                     desired_state = move_support_tests::Foo::DefaultInitialized;
72151c0b2f7Stbbdev                 }
72251c0b2f7Stbbdev                 if( p-my_vector.begin() < typename MyVector::difference_type(req) )
72351c0b2f7Stbbdev                     CHECK((p->state == desired_state || p->state == move_support_tests::Foo::ZeroInitialized));
72451c0b2f7Stbbdev                 CHECK(my_vector.size() >= req);
72551c0b2f7Stbbdev             }
72651c0b2f7Stbbdev         }
GrowToAtLeast(bool use_two_args_form,MyVector & vector,const_reference init_from)72751c0b2f7Stbbdev         GrowToAtLeast(bool use_two_args_form, MyVector& vector, const_reference init_from )
72851c0b2f7Stbbdev             : my_use_two_args_form(use_two_args_form), my_vector(vector), my_init_from(init_from) {}
72951c0b2f7Stbbdev     };
73051c0b2f7Stbbdev }
73151c0b2f7Stbbdev 
73251c0b2f7Stbbdev template<bool use_two_arg_form>
TestConcurrentGrowToAtLeastImpl()73351c0b2f7Stbbdev void TestConcurrentGrowToAtLeastImpl() {
73451c0b2f7Stbbdev     using namespace test_grow_to_at_least_helpers;
73551c0b2f7Stbbdev     using MyAllocator = StaticCountingAllocator<std::allocator<move_support_tests::Foo>>;
73649e08aacStbbdev     using MyVector = oneapi::tbb::concurrent_vector<move_support_tests::Foo, MyAllocator>;
73751c0b2f7Stbbdev     move_support_tests::Foo copy_from;
73851c0b2f7Stbbdev     MyAllocator::init_counters();
73951c0b2f7Stbbdev     MyVector v(2, move_support_tests::Foo(), MyAllocator());
74051c0b2f7Stbbdev     for (std::size_t s=1; s<1000; s*=10) {
74149e08aacStbbdev         oneapi::tbb::parallel_for(oneapi::tbb::blocked_range<std::size_t>(0, 10000*s, s), GrowToAtLeast<MyVector>(use_two_arg_form, v, copy_from), oneapi::tbb::simple_partitioner());
74251c0b2f7Stbbdev     }
74351c0b2f7Stbbdev 
74451c0b2f7Stbbdev     v.clear();
74551c0b2f7Stbbdev     v.shrink_to_fit();
74651c0b2f7Stbbdev     std::size_t items_allocated = v.get_allocator().items_allocated,
74751c0b2f7Stbbdev            items_freed = v.get_allocator().items_freed;
74851c0b2f7Stbbdev     std::size_t allocations = v.get_allocator().allocations,
74951c0b2f7Stbbdev            frees = v.get_allocator().frees;
75051c0b2f7Stbbdev     REQUIRE( items_allocated == items_freed );
75151c0b2f7Stbbdev     REQUIRE( allocations == frees );
75251c0b2f7Stbbdev }
75351c0b2f7Stbbdev 
75451c0b2f7Stbbdev struct AssignElement {
75549e08aacStbbdev     using iterator = oneapi::tbb::concurrent_vector<int>::range_type::iterator;
75651c0b2f7Stbbdev     iterator base;
operator ()AssignElement75749e08aacStbbdev     void operator()( const oneapi::tbb::concurrent_vector<int>::range_type& range ) const {
75851c0b2f7Stbbdev         for (iterator i = range.begin(); i != range.end(); ++i) {
75951c0b2f7Stbbdev             if (*i != 0) {
76051c0b2f7Stbbdev                 REPORT("ERROR for v[%ld]\n", long(i - base));
76151c0b2f7Stbbdev             }
76251c0b2f7Stbbdev             *i = int(i-base);
76351c0b2f7Stbbdev         }
76451c0b2f7Stbbdev     }
AssignElementAssignElement76551c0b2f7Stbbdev     AssignElement( iterator base_ ) : base(base_) {}
76651c0b2f7Stbbdev };
76751c0b2f7Stbbdev 
76851c0b2f7Stbbdev struct CheckElement {
76949e08aacStbbdev     using iterator = oneapi::tbb::concurrent_vector<int>::const_range_type::iterator;
77051c0b2f7Stbbdev     iterator base;
operator ()CheckElement77149e08aacStbbdev     void operator()( const oneapi::tbb::concurrent_vector<int>::const_range_type& range ) const {
77251c0b2f7Stbbdev         for (iterator i = range.begin(); i != range.end(); ++i) {
77351c0b2f7Stbbdev             if (*i != int(i-base)) {
77451c0b2f7Stbbdev                 REPORT("ERROR for v[%ld]\n", long(i-base));
77551c0b2f7Stbbdev             }
77651c0b2f7Stbbdev         }
77751c0b2f7Stbbdev     }
CheckElementCheckElement77851c0b2f7Stbbdev     CheckElement( iterator base_ ) : base(base_) {}
77951c0b2f7Stbbdev };
78051c0b2f7Stbbdev 
78151c0b2f7Stbbdev // Test parallel access by iterators
TestParallelFor(std::size_t nthread)78251c0b2f7Stbbdev void TestParallelFor( std::size_t nthread ) {
78349e08aacStbbdev     using vector_type = oneapi::tbb::concurrent_vector<int>;
78451c0b2f7Stbbdev     vector_type v;
78551c0b2f7Stbbdev     v.resize(N);
78649e08aacStbbdev     oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now();
78751c0b2f7Stbbdev     INFO("Calling parallel_for with " << nthread << " threads");
78849e08aacStbbdev     oneapi::tbb::parallel_for(v.range(10000), AssignElement(v.begin()));
78949e08aacStbbdev     oneapi::tbb::tick_count t1 = oneapi::tbb::tick_count::now();
79051c0b2f7Stbbdev     const vector_type& u = v;
79149e08aacStbbdev     oneapi::tbb::parallel_for(u.range(10000), CheckElement(u.begin()));
79249e08aacStbbdev     oneapi::tbb::tick_count t2 = oneapi::tbb::tick_count::now();
79351c0b2f7Stbbdev     INFO("Time for parallel_for: assign time = " << (t1 - t0).seconds() <<
79451c0b2f7Stbbdev         " , check time = " << (t2 - t1).seconds());
79551c0b2f7Stbbdev     for (int i = 0; std::size_t(i) < v.size(); ++i) {
79651c0b2f7Stbbdev         if (v[i] != i) {
79751c0b2f7Stbbdev             REPORT("ERROR for v[%ld]\n", i);
79851c0b2f7Stbbdev         }
79951c0b2f7Stbbdev     }
80051c0b2f7Stbbdev }
80151c0b2f7Stbbdev 
80251c0b2f7Stbbdev 
80351c0b2f7Stbbdev struct grain_map {
80451c0b2f7Stbbdev     enum grow_method_enum {
80551c0b2f7Stbbdev         grow_by_range = 1,
80651c0b2f7Stbbdev         grow_by_default,
80751c0b2f7Stbbdev         grow_by_copy,
80851c0b2f7Stbbdev         grow_by_init_list,
80951c0b2f7Stbbdev         push_back,
81051c0b2f7Stbbdev         push_back_move,
81151c0b2f7Stbbdev         emplace_back,
81251c0b2f7Stbbdev         last_method
81351c0b2f7Stbbdev     };
81451c0b2f7Stbbdev 
81551c0b2f7Stbbdev     struct range_part {
81651c0b2f7Stbbdev         std::size_t number_of_parts;
81751c0b2f7Stbbdev         grain_map::grow_method_enum method;
81851c0b2f7Stbbdev         bool distribute;
81951c0b2f7Stbbdev         move_support_tests::Foo::State expected_element_state;
82051c0b2f7Stbbdev     };
82151c0b2f7Stbbdev 
82251c0b2f7Stbbdev     const std::vector<range_part> distributed;
82351c0b2f7Stbbdev     const std::vector<range_part> batched;
82451c0b2f7Stbbdev     const std::size_t total_number_of_parts;
82551c0b2f7Stbbdev 
grain_mapgrain_map82651c0b2f7Stbbdev     grain_map(const range_part* begin, const range_part* end)
82751c0b2f7Stbbdev     : distributed(separate(begin,end, &distributed::is_not))
82851c0b2f7Stbbdev     , batched(separate(begin,end, &distributed::is_yes))
82951c0b2f7Stbbdev     , total_number_of_parts(std::accumulate(begin, end, (std::size_t)0, &sum_number_of_parts::sum))
83051c0b2f7Stbbdev     {}
83151c0b2f7Stbbdev 
83251c0b2f7Stbbdev private:
83351c0b2f7Stbbdev     struct sum_number_of_parts{
sumgrain_map::sum_number_of_parts83451c0b2f7Stbbdev         static std::size_t sum(std::size_t accumulator, grain_map::range_part const& rp){ return accumulator + rp.number_of_parts;}
83551c0b2f7Stbbdev     };
83651c0b2f7Stbbdev 
83751c0b2f7Stbbdev     template <typename functor_t>
separategrain_map83851c0b2f7Stbbdev     static std::vector<range_part> separate(const range_part* begin, const range_part* end, functor_t f){
83951c0b2f7Stbbdev         std::vector<range_part> part;
84051c0b2f7Stbbdev         part.reserve(std::distance(begin,end));
84151c0b2f7Stbbdev         //copy all that false==f(*it)
84251c0b2f7Stbbdev         std::remove_copy_if(begin, end, std::back_inserter(part), f);
84351c0b2f7Stbbdev 
84451c0b2f7Stbbdev         return part;
84551c0b2f7Stbbdev     }
84651c0b2f7Stbbdev 
84751c0b2f7Stbbdev     struct distributed {
is_notgrain_map::distributed84851c0b2f7Stbbdev         static bool is_not(range_part const& rp){ return !rp.distribute;}
is_yesgrain_map::distributed84951c0b2f7Stbbdev         static bool is_yes(range_part const& rp){ return rp.distribute;}
85051c0b2f7Stbbdev     };
85151c0b2f7Stbbdev };
85251c0b2f7Stbbdev 
85351c0b2f7Stbbdev 
85451c0b2f7Stbbdev //! Test concurrent invocations of method concurrent_vector::grow_by
85551c0b2f7Stbbdev template<typename MyVector>
85651c0b2f7Stbbdev class GrowBy {
85751c0b2f7Stbbdev     MyVector& my_vector;
85851c0b2f7Stbbdev     const grain_map& my_grain_map;
85951c0b2f7Stbbdev     std::size_t my_part_weight;
86051c0b2f7Stbbdev public:
operator ()(const oneapi::tbb::blocked_range<std::size_t> & range) const86149e08aacStbbdev     void operator()( const oneapi::tbb::blocked_range<std::size_t>& range ) const {
86251c0b2f7Stbbdev         CHECK(range.begin() < range.end());
86351c0b2f7Stbbdev 
86451c0b2f7Stbbdev         std::size_t current_adding_index_in_cvector = range.begin();
86551c0b2f7Stbbdev 
86651c0b2f7Stbbdev         for (std::size_t index = 0; index < my_grain_map.batched.size(); ++index){
86751c0b2f7Stbbdev             const grain_map::range_part& batch_part = my_grain_map.batched[index];
86851c0b2f7Stbbdev             const std::size_t number_of_items_to_add = batch_part.number_of_parts * my_part_weight;
86951c0b2f7Stbbdev             const std::size_t end = current_adding_index_in_cvector + number_of_items_to_add;
87051c0b2f7Stbbdev 
87151c0b2f7Stbbdev             switch(batch_part.method){
87251c0b2f7Stbbdev             case grain_map::grow_by_range : {
87351c0b2f7Stbbdev                     my_vector.grow_by(move_support_tests::FooIterator(current_adding_index_in_cvector), move_support_tests::FooIterator(end));
87451c0b2f7Stbbdev                 } break;
87551c0b2f7Stbbdev             case grain_map::grow_by_default : {
87651c0b2f7Stbbdev                     typename MyVector::iterator const s = my_vector.grow_by(number_of_items_to_add);
87751c0b2f7Stbbdev                     for (std::size_t k = 0; k < number_of_items_to_add; ++k) {
87851c0b2f7Stbbdev                         s[k].bar() = current_adding_index_in_cvector + k;
87951c0b2f7Stbbdev                     }
88051c0b2f7Stbbdev                 } break;
88151c0b2f7Stbbdev             case grain_map::grow_by_init_list : {
88251c0b2f7Stbbdev                     move_support_tests::FooIterator curr(current_adding_index_in_cvector);
88351c0b2f7Stbbdev                     for (std::size_t k = 0; k < number_of_items_to_add; ++k) {
88451c0b2f7Stbbdev                         if (k + 4 < number_of_items_to_add) {
88551c0b2f7Stbbdev                             my_vector.grow_by( { *curr++, *curr++, *curr++, *curr++, *curr++ } );
88651c0b2f7Stbbdev                             k += 4;
88751c0b2f7Stbbdev                         } else {
88851c0b2f7Stbbdev                             my_vector.grow_by( { *curr++ } );
88951c0b2f7Stbbdev                         }
89051c0b2f7Stbbdev                     }
89151c0b2f7Stbbdev                     CHECK(curr == move_support_tests::FooIterator(end));
89251c0b2f7Stbbdev                 } break;
89351c0b2f7Stbbdev             default : { REQUIRE_MESSAGE(false, "using unimplemented method of batch add in ConcurrentGrow test.");} break;
89451c0b2f7Stbbdev             };
89551c0b2f7Stbbdev 
89651c0b2f7Stbbdev             current_adding_index_in_cvector = end;
89751c0b2f7Stbbdev         }
89851c0b2f7Stbbdev 
89951c0b2f7Stbbdev         std::vector<std::size_t> items_left_to_add(my_grain_map.distributed.size());
90051c0b2f7Stbbdev         for (std::size_t i=0; i < my_grain_map.distributed.size(); ++i) {
90151c0b2f7Stbbdev             items_left_to_add[i] = my_grain_map.distributed[i].number_of_parts * my_part_weight;
90251c0b2f7Stbbdev         }
90351c0b2f7Stbbdev 
90451c0b2f7Stbbdev         for (;current_adding_index_in_cvector < range.end(); ++current_adding_index_in_cvector) {
90551c0b2f7Stbbdev             std::size_t method_index = current_adding_index_in_cvector % my_grain_map.distributed.size();
90651c0b2f7Stbbdev 
90751c0b2f7Stbbdev             if (!items_left_to_add[method_index]) {
90851c0b2f7Stbbdev                 struct not_zero{
90955f9b178SIvan Kochin                     static bool is(std::size_t items_to_add){ return items_to_add != 0;}
91051c0b2f7Stbbdev                 };
91151c0b2f7Stbbdev                 method_index = std::distance(items_left_to_add.begin(), std::find_if(items_left_to_add.begin(), items_left_to_add.end(), &not_zero::is));
91251c0b2f7Stbbdev                 REQUIRE_MESSAGE(method_index < my_grain_map.distributed.size(), "incorrect test setup - wrong expected distribution: left free space but no elements to add?");
91351c0b2f7Stbbdev             };
91451c0b2f7Stbbdev 
91551c0b2f7Stbbdev             REQUIRE_MESSAGE(items_left_to_add[method_index], "logic error ?");
91651c0b2f7Stbbdev             const grain_map::range_part& distributed_part = my_grain_map.distributed[method_index];
91751c0b2f7Stbbdev 
91851c0b2f7Stbbdev             typename MyVector::iterator r;
91951c0b2f7Stbbdev             typename MyVector::value_type source;
92051c0b2f7Stbbdev             source.bar() = current_adding_index_in_cvector;
92151c0b2f7Stbbdev 
92251c0b2f7Stbbdev             switch(distributed_part.method){
92351c0b2f7Stbbdev             case grain_map::grow_by_default : {
92451c0b2f7Stbbdev                     (r = my_vector.grow_by(1))->bar() = current_adding_index_in_cvector;
92551c0b2f7Stbbdev                 } break;
92651c0b2f7Stbbdev             case grain_map::grow_by_copy : {
92751c0b2f7Stbbdev                     r = my_vector.grow_by(1, source);
92851c0b2f7Stbbdev                 } break;
92951c0b2f7Stbbdev             case grain_map::push_back : {
93051c0b2f7Stbbdev                     r = my_vector.push_back(source);
93151c0b2f7Stbbdev                 } break;
93251c0b2f7Stbbdev             case grain_map::push_back_move : {
93351c0b2f7Stbbdev                     r = my_vector.push_back(std::move(source));
93451c0b2f7Stbbdev                 } break;
93551c0b2f7Stbbdev             case grain_map::emplace_back : {
93651c0b2f7Stbbdev                     r = my_vector.emplace_back(current_adding_index_in_cvector);
93751c0b2f7Stbbdev                 } break;
93851c0b2f7Stbbdev 
93951c0b2f7Stbbdev             default : { REQUIRE_MESSAGE(false, "using unimplemented method of batch add in ConcurrentGrow test.");} break;
94051c0b2f7Stbbdev             };
94151c0b2f7Stbbdev 
94251c0b2f7Stbbdev             CHECK(static_cast<std::size_t>(r->bar()) == current_adding_index_in_cvector);
94351c0b2f7Stbbdev             }
94451c0b2f7Stbbdev 
94551c0b2f7Stbbdev         }
94651c0b2f7Stbbdev 
GrowBy(MyVector & vector,const grain_map & m,std::size_t part_weight)94751c0b2f7Stbbdev     GrowBy( MyVector& vector, const grain_map& m, std::size_t part_weight )
94851c0b2f7Stbbdev     : my_vector(vector), my_grain_map(m), my_part_weight(part_weight)
94951c0b2f7Stbbdev     {}
95051c0b2f7Stbbdev };
95151c0b2f7Stbbdev 
95251c0b2f7Stbbdev //! Test concurrent invocations of grow methods
TestConcurrentGrowBy()95351c0b2f7Stbbdev void TestConcurrentGrowBy() {
95451c0b2f7Stbbdev 
95551c0b2f7Stbbdev     const grain_map::range_part concurrent_grow_single_range_map [] = {
95651c0b2f7Stbbdev     //  number_of_parts,         method,             distribute,   expected_element_state
95751c0b2f7Stbbdev             {3,           grain_map::grow_by_range,     false,   move_support_tests::Foo::MoveInitialized},
95851c0b2f7Stbbdev 
95951c0b2f7Stbbdev             {1,           grain_map::grow_by_init_list, false,   move_support_tests::Foo::CopyInitialized},
96051c0b2f7Stbbdev 
96151c0b2f7Stbbdev             {2,           grain_map::grow_by_default,   false,   move_support_tests::Foo::DefaultInitialized},
96251c0b2f7Stbbdev             {1,           grain_map::grow_by_default,   true,    move_support_tests::Foo::DefaultInitialized},
96351c0b2f7Stbbdev             {1,           grain_map::grow_by_copy,      true,    move_support_tests::Foo::CopyInitialized},
96451c0b2f7Stbbdev             {1,           grain_map::push_back,         true,    move_support_tests::Foo::CopyInitialized},
96551c0b2f7Stbbdev 
96651c0b2f7Stbbdev             {1,           grain_map::push_back_move,    true,    move_support_tests::Foo::MoveInitialized},
96751c0b2f7Stbbdev 
96851c0b2f7Stbbdev             {1,           grain_map::emplace_back,      true,    move_support_tests::Foo::DirectInitialized},
96951c0b2f7Stbbdev 
97051c0b2f7Stbbdev     };
97151c0b2f7Stbbdev 
97251c0b2f7Stbbdev     using MyAllocator = StaticCountingAllocator<std::allocator<move_support_tests::Foo> >;
97349e08aacStbbdev     using MyVector = oneapi::tbb::concurrent_vector<move_support_tests::Foo, MyAllocator>;
97451c0b2f7Stbbdev 
97551c0b2f7Stbbdev     MyAllocator::init_counters();
97651c0b2f7Stbbdev     {
97751c0b2f7Stbbdev         grain_map m(concurrent_grow_single_range_map, end(concurrent_grow_single_range_map));
97851c0b2f7Stbbdev 
97951c0b2f7Stbbdev         static const std::size_t desired_grain_size = 100;
98051c0b2f7Stbbdev 
98151c0b2f7Stbbdev         static const std::size_t part_weight = desired_grain_size / m.total_number_of_parts;
98251c0b2f7Stbbdev         static const std::size_t grain_size = part_weight * m.total_number_of_parts;
98351c0b2f7Stbbdev         static const std::size_t number_of_grains = 8; //this should be (power of two) in order to get minimal ranges equal to grain_size
98451c0b2f7Stbbdev         static const std::size_t range_size = grain_size * number_of_grains;
98551c0b2f7Stbbdev 
98651c0b2f7Stbbdev         MyAllocator a;
98751c0b2f7Stbbdev         MyVector v(a);
98849e08aacStbbdev         oneapi::tbb::parallel_for(oneapi::tbb::blocked_range<std::size_t>(0, range_size, grain_size), GrowBy<MyVector>(v, m, part_weight), oneapi::tbb::simple_partitioner());
98951c0b2f7Stbbdev 
99051c0b2f7Stbbdev         REQUIRE( v.size() == std::size_t(range_size) );
99151c0b2f7Stbbdev 
99251c0b2f7Stbbdev         // Verify that v is a permutation of 0..m
9931168c5cbSvlserov         size_t direct_inits = 0, def_inits = 0, copy_inits = 0, move_inits = 0;
99451c0b2f7Stbbdev         std::vector<bool> found(range_size, 0);
99551c0b2f7Stbbdev         for( std::size_t i=0; i<range_size; ++i ) {
99651c0b2f7Stbbdev             if( v[i].state == move_support_tests::Foo::DefaultInitialized ) ++def_inits;
99751c0b2f7Stbbdev             else if( v[i].state == move_support_tests::Foo::DirectInitialized ) ++direct_inits;
99851c0b2f7Stbbdev             else if( v[i].state == move_support_tests::Foo::CopyInitialized ) ++copy_inits;
99951c0b2f7Stbbdev             else if( v[i].state == move_support_tests::Foo::MoveInitialized ) ++move_inits;
100051c0b2f7Stbbdev             else {
100151c0b2f7Stbbdev                 REQUIRE_MESSAGE( false, "v[i] seems not initialized");
100251c0b2f7Stbbdev             }
100351c0b2f7Stbbdev             intptr_t index = v[i].bar();
100451c0b2f7Stbbdev             REQUIRE( !found[index] );
100551c0b2f7Stbbdev             found[index] = true;
100651c0b2f7Stbbdev         }
100751c0b2f7Stbbdev 
100851c0b2f7Stbbdev         std::size_t expected_direct_inits = 0, expected_def_inits = 0, expected_copy_inits = 0, expected_move_inits = 0;
100951c0b2f7Stbbdev         for (std::size_t i=0; i < utils::array_length(concurrent_grow_single_range_map); ++i){
101051c0b2f7Stbbdev             const grain_map::range_part& rp =concurrent_grow_single_range_map[i];
101151c0b2f7Stbbdev             switch (rp.expected_element_state){
101251c0b2f7Stbbdev             case move_support_tests::Foo::DefaultInitialized: { expected_def_inits += rp.number_of_parts ; } break;
101351c0b2f7Stbbdev             case move_support_tests::Foo::DirectInitialized:  { expected_direct_inits += rp.number_of_parts ;} break;
101451c0b2f7Stbbdev             case move_support_tests::Foo::MoveInitialized:    { expected_move_inits += rp.number_of_parts ;} break;
101551c0b2f7Stbbdev             case move_support_tests::Foo::CopyInitialized:    { expected_copy_inits += rp.number_of_parts ;} break;
101651c0b2f7Stbbdev             default: {REQUIRE_MESSAGE(false, "unexpected expected state");}break;
101751c0b2f7Stbbdev             };
101851c0b2f7Stbbdev         }
101951c0b2f7Stbbdev 
102051c0b2f7Stbbdev         expected_def_inits    *= part_weight * number_of_grains;
102151c0b2f7Stbbdev         expected_move_inits   *= part_weight * number_of_grains;
102251c0b2f7Stbbdev         expected_copy_inits   *= part_weight * number_of_grains;
102351c0b2f7Stbbdev         expected_direct_inits *= part_weight * number_of_grains;
102451c0b2f7Stbbdev 
102551c0b2f7Stbbdev         REQUIRE( def_inits == expected_def_inits );
102651c0b2f7Stbbdev         REQUIRE( copy_inits == expected_copy_inits );
102751c0b2f7Stbbdev         REQUIRE( move_inits == expected_move_inits );
102851c0b2f7Stbbdev         REQUIRE( direct_inits == expected_direct_inits );
102951c0b2f7Stbbdev     }
103051c0b2f7Stbbdev     //TODO: factor this into separate thing, as it seems to used in big number of tests
103151c0b2f7Stbbdev     std::size_t items_allocated = MyAllocator::items_allocated,
103251c0b2f7Stbbdev            items_freed = MyAllocator::items_freed;
103351c0b2f7Stbbdev     std::size_t allocations = MyAllocator::allocations,
103451c0b2f7Stbbdev            frees = MyAllocator::frees;
103551c0b2f7Stbbdev     REQUIRE(items_allocated == items_freed);
103651c0b2f7Stbbdev     REQUIRE(allocations == frees);
103751c0b2f7Stbbdev }
103851c0b2f7Stbbdev 
TestComparison()103951c0b2f7Stbbdev void TestComparison() {
104051c0b2f7Stbbdev     std::string str[3];
104151c0b2f7Stbbdev     str[0] = "abc";
104251c0b2f7Stbbdev     str[1].assign("cba");
104351c0b2f7Stbbdev     str[2].assign("abc"); // same as 0th
104449e08aacStbbdev     oneapi::tbb::concurrent_vector<char> var[3];
104551c0b2f7Stbbdev     var[0].assign(str[0].begin(), str[0].end());
104651c0b2f7Stbbdev     var[1].assign(str[0].rbegin(), str[0].rend());
104751c0b2f7Stbbdev     var[2].assign(var[1].rbegin(), var[1].rend()); // same as 0th
104851c0b2f7Stbbdev     for (int i = 0; i < 3; ++i) {
104951c0b2f7Stbbdev         for (int j = 0; j < 3; ++j) {
105051c0b2f7Stbbdev             REQUIRE( (var[i] == var[j]) == (str[i] == str[j]) );
105151c0b2f7Stbbdev             REQUIRE( (var[i] != var[j]) == (str[i] != str[j]) );
105251c0b2f7Stbbdev             REQUIRE( (var[i] < var[j]) == (str[i] < str[j]) );
105351c0b2f7Stbbdev             REQUIRE( (var[i] > var[j]) == (str[i] > str[j]) );
105451c0b2f7Stbbdev             REQUIRE( (var[i] <= var[j]) == (str[i] <= str[j]) );
105551c0b2f7Stbbdev             REQUIRE( (var[i] >= var[j]) == (str[i] >= str[j]) );
105651c0b2f7Stbbdev         }
105751c0b2f7Stbbdev     }
105851c0b2f7Stbbdev }
105951c0b2f7Stbbdev 
106051c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
test_ex_move_assignment_memory_failure()106151c0b2f7Stbbdev void test_ex_move_assignment_memory_failure() {
106251c0b2f7Stbbdev     using fixture_type = move_support_tests::DefaultStatefulFixtureHelper<c_vector_type, /*POCMA = */std::false_type>::type;
106351c0b2f7Stbbdev     using arena_allocator_fixture_type = move_support_tests::ArenaAllocatorFixture<move_support_tests::FooWithAssign, /*POCMA = */std::false_type>;
106451c0b2f7Stbbdev     using allocator_type = fixture_type::allocator_type;
106551c0b2f7Stbbdev     using vector_type = fixture_type::container_type;
106651c0b2f7Stbbdev 
106751c0b2f7Stbbdev     fixture_type fixture;
106851c0b2f7Stbbdev     arena_allocator_fixture_type arena_allocator_fixture(4 * fixture.container_size);
106951c0b2f7Stbbdev 
107051c0b2f7Stbbdev     const std::size_t allocation_limit = fixture.container_size/4;
107151c0b2f7Stbbdev 
107251c0b2f7Stbbdev     vector_type victim(arena_allocator_fixture.allocator);
107351c0b2f7Stbbdev     victim.reserve(2); // for fragmented assignment
107451c0b2f7Stbbdev 
107551c0b2f7Stbbdev     REQUIRE_THROWS_AS(
107651c0b2f7Stbbdev         [&]() {
107751c0b2f7Stbbdev             move_support_tests::LimitAllocatedItemsInScope<allocator_type> allocator_limit(allocator_type::items_allocated + allocation_limit);
107851c0b2f7Stbbdev             victim = std::move(fixture.source); // fragmented assignment
107951c0b2f7Stbbdev         }(),
108051c0b2f7Stbbdev         std::bad_alloc
108151c0b2f7Stbbdev     );
108251c0b2f7Stbbdev 
108351c0b2f7Stbbdev     verify_c_vector_size(victim);
108451c0b2f7Stbbdev     verify_c_vector_capacity_is_below(victim.capacity(), allocation_limit + 2);
108551c0b2f7Stbbdev     fixture.verify_part_of_content_deep_moved(victim, victim.size());
108651c0b2f7Stbbdev 
108751c0b2f7Stbbdev     verify_last_segment_allocation_failed(victim);
108851c0b2f7Stbbdev     verify_copy_and_assign_from_produce_the_same(victim);
108951c0b2f7Stbbdev     verify_assignment_operator_throws_bad_last_alloc(victim);
109051c0b2f7Stbbdev }
109151c0b2f7Stbbdev 
test_ex_move_assignment_element_ctor_exception()109251c0b2f7Stbbdev void test_ex_move_assignment_element_ctor_exception(){
109351c0b2f7Stbbdev     using fixture_type = move_support_tests::DefaultStatefulFixtureHelper<c_vector_type, std::false_type>::type;
109451c0b2f7Stbbdev     using arena_allocator_fixture_type = move_support_tests::ArenaAllocatorFixture<move_support_tests::FooWithAssign, std::false_type>;
109551c0b2f7Stbbdev     using vector_type = fixture_type::container_type;
109651c0b2f7Stbbdev 
109751c0b2f7Stbbdev     fixture_type fixture;
109851c0b2f7Stbbdev     const size_t planned_victim_size = fixture.container_size/4;
109951c0b2f7Stbbdev     arena_allocator_fixture_type arena_allocator_fixture(4 * fixture.container_size);
110051c0b2f7Stbbdev 
110151c0b2f7Stbbdev     vector_type victim(arena_allocator_fixture.allocator);
110251c0b2f7Stbbdev     victim.reserve(2); // get fragmented assignment
110351c0b2f7Stbbdev 
110451c0b2f7Stbbdev     REQUIRE_THROWS_AS(
110551c0b2f7Stbbdev         [&](){
110651c0b2f7Stbbdev             move_support_tests::LimitFooCountInScope foo_limit(move_support_tests::foo_count + planned_victim_size);
110751c0b2f7Stbbdev             victim = std::move(fixture.source); // fragmented assignment
110851c0b2f7Stbbdev         }(),
110951c0b2f7Stbbdev         std::bad_alloc
111051c0b2f7Stbbdev     );
111151c0b2f7Stbbdev 
111251c0b2f7Stbbdev     verify_c_vector_size(victim);
111351c0b2f7Stbbdev 
111451c0b2f7Stbbdev     fixture.verify_part_of_content_deep_moved(victim, planned_victim_size);
111551c0b2f7Stbbdev 
111651c0b2f7Stbbdev     verify_last_segment_allocation_failed(victim);
111751c0b2f7Stbbdev     verify_copy_and_assign_from_produce_the_same(victim);
111851c0b2f7Stbbdev     verify_assignment_operator_throws_bad_last_alloc(victim);
111951c0b2f7Stbbdev }
112051c0b2f7Stbbdev 
test_ex_move_assignment()112151c0b2f7Stbbdev void test_ex_move_assignment() {
112251c0b2f7Stbbdev     test_ex_move_assignment_memory_failure();
112351c0b2f7Stbbdev     test_ex_move_assignment_element_ctor_exception();
112451c0b2f7Stbbdev }
112551c0b2f7Stbbdev #endif
112651c0b2f7Stbbdev 
112751c0b2f7Stbbdev template <typename Type, typename Allocator>
112851c0b2f7Stbbdev class test_grow_by_and_resize {
112949e08aacStbbdev     oneapi::tbb::concurrent_vector<Type, Allocator> &my_c;
113051c0b2f7Stbbdev public:
test_grow_by_and_resize(oneapi::tbb::concurrent_vector<Type,Allocator> & c)113149e08aacStbbdev     test_grow_by_and_resize( oneapi::tbb::concurrent_vector<Type, Allocator> &c ) : my_c(c) {}
operator ()() const113251c0b2f7Stbbdev     void operator()() const {
113349e08aacStbbdev         const typename oneapi::tbb::concurrent_vector<Type, Allocator>::size_type sz = my_c.size();
113451c0b2f7Stbbdev         my_c.grow_by( 5 );
113551c0b2f7Stbbdev         REQUIRE( my_c.size() == sz + 5 );
113651c0b2f7Stbbdev         my_c.resize( sz );
113751c0b2f7Stbbdev         REQUIRE( my_c.size() == sz );
113851c0b2f7Stbbdev     }
113951c0b2f7Stbbdev };
114051c0b2f7Stbbdev 
114151c0b2f7Stbbdev namespace push_back_exception_safety_helpers {
114251c0b2f7Stbbdev     //TODO: remove code duplication with emplace_helpers::wrapper_type
114351c0b2f7Stbbdev     struct throwing_foo:move_support_tests::Foo {
114451c0b2f7Stbbdev         int value1;
114551c0b2f7Stbbdev         int value2;
throwing_foopush_back_exception_safety_helpers::throwing_foo114651c0b2f7Stbbdev         explicit throwing_foo(int v1, int v2) : value1 (v1), value2(v2) {}
114751c0b2f7Stbbdev     };
114851c0b2f7Stbbdev 
114951c0b2f7Stbbdev     template< typename foo_t = throwing_foo>
115051c0b2f7Stbbdev     struct fixture {
115149e08aacStbbdev         using vector_t = oneapi::tbb::concurrent_vector<foo_t, std::allocator<foo_t> >;
115251c0b2f7Stbbdev         vector_t v;
115351c0b2f7Stbbdev 
testpush_back_exception_safety_helpers::fixture115451c0b2f7Stbbdev         void test( void(*p_test)(vector_t&)){
115551c0b2f7Stbbdev             utils::suppress_unused_warning(p_test);
115651c0b2f7Stbbdev             move_support_tests::track_foo_count<__LINE__> verify_no_foo_leaked_during_exception{};
115751c0b2f7Stbbdev             utils::suppress_unused_warning(verify_no_foo_leaked_during_exception);
115851c0b2f7Stbbdev             REQUIRE_MESSAGE(v.empty(),"incorrect test setup?" );
115951c0b2f7Stbbdev             REQUIRE_THROWS_AS(p_test(v), move_support_tests::FooException);
116051c0b2f7Stbbdev             REQUIRE_MESSAGE(is_state<move_support_tests::Foo::ZeroInitialized>(v[0]),"incorrectly filled item during exception in emplace_back?");
116151c0b2f7Stbbdev         }
116251c0b2f7Stbbdev     };
116351c0b2f7Stbbdev }
116451c0b2f7Stbbdev 
TestPushBackMoveExceptionSafety()116551c0b2f7Stbbdev void TestPushBackMoveExceptionSafety() {
116651c0b2f7Stbbdev     using fixture_t = push_back_exception_safety_helpers::fixture<move_support_tests::Foo>;
116751c0b2f7Stbbdev     fixture_t t;
116851c0b2f7Stbbdev 
116951c0b2f7Stbbdev     move_support_tests::LimitFooCountInScope foo_limit(move_support_tests::foo_count + 1);
117051c0b2f7Stbbdev 
117151c0b2f7Stbbdev     struct test {
117251c0b2f7Stbbdev         static void test_move_push_back(fixture_t::vector_t& v) {
117351c0b2f7Stbbdev             move_support_tests::Foo f;
117451c0b2f7Stbbdev             v.push_back(std::move(f));
117551c0b2f7Stbbdev         }
117651c0b2f7Stbbdev     };
117751c0b2f7Stbbdev     t.test(&test::test_move_push_back);
117851c0b2f7Stbbdev }
117951c0b2f7Stbbdev 
TestEmplaceBackExceptionSafety()118051c0b2f7Stbbdev void TestEmplaceBackExceptionSafety(){
118151c0b2f7Stbbdev     using fixture_t = push_back_exception_safety_helpers::fixture<>;
118251c0b2f7Stbbdev     fixture_t t;
118351c0b2f7Stbbdev 
118451c0b2f7Stbbdev     move_support_tests::Foo dummy; //make FooCount non zero;
118551c0b2f7Stbbdev     utils::suppress_unused_warning(dummy);
118651c0b2f7Stbbdev     move_support_tests::LimitFooCountInScope foo_limit(move_support_tests::foo_count);
118751c0b2f7Stbbdev 
118851c0b2f7Stbbdev     struct test {
118951c0b2f7Stbbdev         static void test_emplace(fixture_t::vector_t& v) {
119051c0b2f7Stbbdev             v.emplace_back(1,2);
119151c0b2f7Stbbdev         }
119251c0b2f7Stbbdev     };
119351c0b2f7Stbbdev     t.test(&test::test_emplace);
119451c0b2f7Stbbdev }
119551c0b2f7Stbbdev 
119651c0b2f7Stbbdev namespace move_semantics_helpers {
119751c0b2f7Stbbdev     struct move_only_type {
119851c0b2f7Stbbdev         const int* my_pointer;
move_only_typemove_semantics_helpers::move_only_type119951c0b2f7Stbbdev         move_only_type(move_only_type && other): my_pointer(other.my_pointer){other.my_pointer=nullptr;}
move_only_typemove_semantics_helpers::move_only_type120051c0b2f7Stbbdev         explicit move_only_type(const int* value): my_pointer(value) {}
120151c0b2f7Stbbdev     };
120251c0b2f7Stbbdev }
120351c0b2f7Stbbdev 
TestPushBackMoveOnlyContainer()120451c0b2f7Stbbdev void TestPushBackMoveOnlyContainer(){
120551c0b2f7Stbbdev     using namespace move_semantics_helpers;
120649e08aacStbbdev     using vector_t = oneapi::tbb::concurrent_vector<move_only_type >;
120751c0b2f7Stbbdev     vector_t v;
120851c0b2f7Stbbdev     static const int magic_number = 7;
120951c0b2f7Stbbdev     move_only_type src(&magic_number);
121051c0b2f7Stbbdev     v.push_back(std::move(src));
121151c0b2f7Stbbdev     REQUIRE_MESSAGE((v[0].my_pointer == &magic_number),"item was incorrectly moved during push_back?");
121251c0b2f7Stbbdev     REQUIRE_MESSAGE(src.my_pointer == nullptr,"item was incorrectly moved during push_back?");
121351c0b2f7Stbbdev }
121451c0b2f7Stbbdev 
121551c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
121651c0b2f7Stbbdev template <template <typename...> typename TVector>
TestDeductionGuides()121751c0b2f7Stbbdev void TestDeductionGuides() {
121851c0b2f7Stbbdev     using ComplexType = const std::string*;
121951c0b2f7Stbbdev     std::vector<ComplexType> v;
122051c0b2f7Stbbdev     std::string s = "s";
122151c0b2f7Stbbdev     auto l = {ComplexType(&s), ComplexType(&s)};
122251c0b2f7Stbbdev 
122351c0b2f7Stbbdev     // check TVector(InputIterator, InputIterator)
122451c0b2f7Stbbdev     TVector v1(v.begin(), v.end());
122551c0b2f7Stbbdev     static_assert(std::is_same<decltype(v1), TVector<ComplexType>>::value);
122651c0b2f7Stbbdev 
1227*c4a799dfSJhaShweta1     // check TVector(InputIterator, InputIterator, Allocator)
122851c0b2f7Stbbdev     TVector v2(v.begin(), v.end(), std::allocator<ComplexType>());
122951c0b2f7Stbbdev     static_assert(std::is_same<decltype(v2),
123051c0b2f7Stbbdev        TVector<ComplexType, std::allocator<ComplexType>>>::value);
123151c0b2f7Stbbdev 
123251c0b2f7Stbbdev     // check TVector(std::initializer_list<T>)
123351c0b2f7Stbbdev     TVector v3(l);
123451c0b2f7Stbbdev     static_assert(std::is_same<decltype(v3),
123551c0b2f7Stbbdev         TVector<ComplexType>>::value);
123651c0b2f7Stbbdev 
1237*c4a799dfSJhaShweta1     // check TVector(std::initializer_list, Allocator)
123851c0b2f7Stbbdev     TVector v4(l, std::allocator<ComplexType>());
123951c0b2f7Stbbdev     static_assert(std::is_same<decltype(v4), TVector<ComplexType, std::allocator<ComplexType>>>::value);
124051c0b2f7Stbbdev 
124151c0b2f7Stbbdev     // check TVector(TVector&)
124251c0b2f7Stbbdev     TVector v5(v1);
124351c0b2f7Stbbdev     static_assert(std::is_same<decltype(v5), TVector<ComplexType>>::value);
124451c0b2f7Stbbdev 
124551c0b2f7Stbbdev     // check TVector(TVector&, Allocator)
124649e08aacStbbdev     TVector v6(v5, oneapi::tbb::cache_aligned_allocator<ComplexType>());
124749e08aacStbbdev     static_assert(std::is_same<decltype(v6), TVector<ComplexType, oneapi::tbb::cache_aligned_allocator<ComplexType>>>::value);
124851c0b2f7Stbbdev 
124951c0b2f7Stbbdev     // check TVector(TVector&&)
125051c0b2f7Stbbdev     TVector v7(std::move(v1));
125151c0b2f7Stbbdev     static_assert(std::is_same<decltype(v7), decltype(v1)>::value);
125251c0b2f7Stbbdev 
125351c0b2f7Stbbdev     // check TVector(TVector&&, Allocator)
125449e08aacStbbdev     TVector v8(std::move(v5), oneapi::tbb::cache_aligned_allocator<ComplexType>());
125549e08aacStbbdev     static_assert(std::is_same<decltype(v8), TVector<ComplexType, oneapi::tbb::cache_aligned_allocator<ComplexType>>>::value);
125651c0b2f7Stbbdev 
125751c0b2f7Stbbdev }
125851c0b2f7Stbbdev #endif
125951c0b2f7Stbbdev 
126051c0b2f7Stbbdev template <template <typename... > class ContainerType>
test_member_types()126151c0b2f7Stbbdev void test_member_types() {
126251c0b2f7Stbbdev     using default_container_type = ContainerType<int>;
126351c0b2f7Stbbdev 
126451c0b2f7Stbbdev     static_assert(std::is_same<typename default_container_type::allocator_type,
126549e08aacStbbdev                                oneapi::tbb::cache_aligned_allocator<int>>::value,
126651c0b2f7Stbbdev                   "Incorrect default template allocator");
126751c0b2f7Stbbdev 
126851c0b2f7Stbbdev 
126949e08aacStbbdev     using test_allocator_type = oneapi::tbb::cache_aligned_allocator<int>;
127051c0b2f7Stbbdev     using container_type = ContainerType<int, test_allocator_type>;
127151c0b2f7Stbbdev 
127251c0b2f7Stbbdev     static_assert(std::is_same<typename container_type::value_type, int>::value,
127351c0b2f7Stbbdev                   "Incorrect container value_type member type");
127451c0b2f7Stbbdev 
127551c0b2f7Stbbdev     static_assert(std::is_unsigned<typename container_type::size_type>::value,
127651c0b2f7Stbbdev                   "Incorrect container size_type member type");
127751c0b2f7Stbbdev     static_assert(std::is_signed<typename container_type::difference_type>::value,
127851c0b2f7Stbbdev                   "Incorrect container difference_type member type");
127951c0b2f7Stbbdev 
128051c0b2f7Stbbdev     using value_type = typename container_type::value_type;
128151c0b2f7Stbbdev     static_assert(std::is_same<typename container_type::reference, value_type&>::value,
128251c0b2f7Stbbdev                   "Incorrect container reference member type");
128351c0b2f7Stbbdev     static_assert(std::is_same<typename container_type::const_reference, const value_type&>::value,
128451c0b2f7Stbbdev                   "Incorrect container const_reference member type");
128551c0b2f7Stbbdev     using allocator_type = typename container_type::allocator_type;
128651c0b2f7Stbbdev     static_assert(std::is_same<typename container_type::pointer, typename std::allocator_traits<allocator_type>::pointer>::value,
128751c0b2f7Stbbdev                   "Incorrect container pointer member type");
128851c0b2f7Stbbdev     static_assert(std::is_same<typename container_type::const_pointer, typename std::allocator_traits<allocator_type>::const_pointer>::value,
128951c0b2f7Stbbdev                   "Incorrect container const_pointer member type");
129051c0b2f7Stbbdev 
129151c0b2f7Stbbdev     static_assert(utils::is_random_access_iterator<typename container_type::iterator>::value,
129251c0b2f7Stbbdev                   "Incorrect container iterator member type");
129351c0b2f7Stbbdev     static_assert(!std::is_const<typename container_type::iterator::value_type>::value,
129451c0b2f7Stbbdev                   "Incorrect container iterator member type");
129551c0b2f7Stbbdev     static_assert(utils::is_random_access_iterator<typename container_type::const_iterator>::value,
129651c0b2f7Stbbdev                   "Incorrect container const_iterator member type");
129751c0b2f7Stbbdev     static_assert(std::is_const<typename container_type::const_iterator::value_type>::value,
129851c0b2f7Stbbdev                   "Incorrect container iterator member type");
129951c0b2f7Stbbdev }
130051c0b2f7Stbbdev 
TestConcurrentGrowToAtLeast()130151c0b2f7Stbbdev void TestConcurrentGrowToAtLeast() {
130251c0b2f7Stbbdev     TestConcurrentGrowToAtLeastImpl<false>();
130351c0b2f7Stbbdev     TestConcurrentGrowToAtLeastImpl<true>();
130451c0b2f7Stbbdev }
130551c0b2f7Stbbdev 
1306b15aabb3Stbbdev template <typename Vector>
test_comparisons_basic()1307b15aabb3Stbbdev void test_comparisons_basic() {
1308b15aabb3Stbbdev     using comparisons_testing::testEqualityAndLessComparisons;
1309b15aabb3Stbbdev     Vector v1, v2;
1310b15aabb3Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(v1, v2);
1311b15aabb3Stbbdev 
1312b15aabb3Stbbdev     v1.emplace_back(1);
1313b15aabb3Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */false>(v1, v2);
1314b15aabb3Stbbdev 
1315b15aabb3Stbbdev     v2.emplace_back(1);
1316b15aabb3Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(v1, v2);
1317b15aabb3Stbbdev 
1318b15aabb3Stbbdev     v2.emplace_back(2);
1319b15aabb3Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */true>(v1, v2);
1320b15aabb3Stbbdev 
1321b15aabb3Stbbdev     v1.clear();
1322b15aabb3Stbbdev     v2.clear();
1323b15aabb3Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(v1, v2);
1324b15aabb3Stbbdev }
1325b15aabb3Stbbdev 
1326b15aabb3Stbbdev template <typename TwoWayComparableVectorType>
test_two_way_comparable_vector()1327b15aabb3Stbbdev void test_two_way_comparable_vector() {
1328b15aabb3Stbbdev     TwoWayComparableVectorType v1, v2;
1329b15aabb3Stbbdev     v1.emplace_back(1);
1330b15aabb3Stbbdev     v2.emplace_back(1);
1331b15aabb3Stbbdev     comparisons_testing::TwoWayComparable::reset();
1332b15aabb3Stbbdev     REQUIRE_MESSAGE(!(v1 < v2), "Incorrect operator < result");
1333b15aabb3Stbbdev     comparisons_testing::check_two_way_comparison();
1334b15aabb3Stbbdev     REQUIRE_MESSAGE(!(v1 > v2), "Incorrect operator > result");
1335b15aabb3Stbbdev     comparisons_testing::check_two_way_comparison();
1336b15aabb3Stbbdev     REQUIRE_MESSAGE(v1 <= v2, "Incorrect operator <= result");
1337b15aabb3Stbbdev     comparisons_testing::check_two_way_comparison();
1338b15aabb3Stbbdev     REQUIRE_MESSAGE(v1 >= v2, "Incorrect operator >= result");
1339b15aabb3Stbbdev     comparisons_testing::check_two_way_comparison();
1340b15aabb3Stbbdev }
1341b15aabb3Stbbdev 
1342b15aabb3Stbbdev #if __TBB_TEST_CPP20_COMPARISONS
1343b15aabb3Stbbdev template <typename ThreeWayComparableVectorType>
test_three_way_comparable_vector()1344b15aabb3Stbbdev void test_three_way_comparable_vector() {
1345b15aabb3Stbbdev     ThreeWayComparableVectorType v1, v2;
1346b15aabb3Stbbdev     v1.emplace_back(1);
1347b15aabb3Stbbdev     v2.emplace_back(1);
1348b15aabb3Stbbdev     comparisons_testing::ThreeWayComparable::reset();
1349b15aabb3Stbbdev     REQUIRE_MESSAGE(!(v1 <=> v2 < 0), "Incorrect operator<=> result");
1350b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
1351b15aabb3Stbbdev 
1352b15aabb3Stbbdev     REQUIRE_MESSAGE(!(v1 < v2), "Incorrect operator< result");
1353b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
1354b15aabb3Stbbdev 
1355b15aabb3Stbbdev     REQUIRE_MESSAGE(!(v1 > v2), "Incorrect operator> result");
1356b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
1357b15aabb3Stbbdev 
1358b15aabb3Stbbdev     REQUIRE_MESSAGE(v1 <= v2, "Incorrect operator>= result");
1359b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
1360b15aabb3Stbbdev 
1361b15aabb3Stbbdev     REQUIRE_MESSAGE(v1 >= v2, "Incorrect operator>= result");
1362b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
1363b15aabb3Stbbdev }
1364b15aabb3Stbbdev #endif // __TBB_TEST_CPP20_COMPARISONS
1365b15aabb3Stbbdev 
TestVectorComparisons()1366b15aabb3Stbbdev void TestVectorComparisons() {
1367b15aabb3Stbbdev     using integral_vector = oneapi::tbb::concurrent_vector<int>;
1368b15aabb3Stbbdev     using two_way_comparable_vector = oneapi::tbb::concurrent_vector<comparisons_testing::TwoWayComparable>;
1369b15aabb3Stbbdev 
1370b15aabb3Stbbdev     test_comparisons_basic<integral_vector>();
1371b15aabb3Stbbdev     test_comparisons_basic<two_way_comparable_vector>();
1372b15aabb3Stbbdev     test_two_way_comparable_vector<two_way_comparable_vector>();
1373b15aabb3Stbbdev 
1374b15aabb3Stbbdev #if __TBB_TEST_CPP20_COMPARISONS
1375b15aabb3Stbbdev     using two_way_less_only_vector = oneapi::tbb::concurrent_vector<comparisons_testing::LessComparableOnly>;
1376b15aabb3Stbbdev     using three_way_only_vector = oneapi::tbb::concurrent_vector<comparisons_testing::ThreeWayComparableOnly>;
1377b15aabb3Stbbdev     using three_way_comparable_vector = oneapi::tbb::concurrent_vector<comparisons_testing::ThreeWayComparable>;
1378b15aabb3Stbbdev 
1379b15aabb3Stbbdev     test_comparisons_basic<two_way_less_only_vector>();
1380b15aabb3Stbbdev     test_comparisons_basic<three_way_only_vector>();
1381b15aabb3Stbbdev     test_comparisons_basic<three_way_comparable_vector>();
1382b15aabb3Stbbdev     test_three_way_comparable_vector<three_way_comparable_vector>();
1383b15aabb3Stbbdev #endif // __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONVEPTS_PRESENT
1384b15aabb3Stbbdev }
1385b15aabb3Stbbdev 
1386b15aabb3Stbbdev template <bool ExpectEqual, bool ExpectLess, typename Iterator>
DoVectorIteratorComparisons(const Iterator & lhs,const Iterator & rhs)1387b15aabb3Stbbdev void DoVectorIteratorComparisons( const Iterator& lhs, const Iterator& rhs ) {
1388b15aabb3Stbbdev     // TODO: replace with testEqualityAndLessComparisons after adding <=> operator for concurrent_vector iterator
1389b15aabb3Stbbdev     using namespace comparisons_testing;
1390b15aabb3Stbbdev     testEqualityComparisons<ExpectEqual>(lhs, rhs);
1391b15aabb3Stbbdev     testTwoWayComparisons<ExpectEqual, ExpectLess>(lhs, rhs);
1392b15aabb3Stbbdev }
1393b15aabb3Stbbdev 
1394b15aabb3Stbbdev template <typename Iterator, typename VectorType>
TestVectorIteratorComparisonsBasic(VectorType & vec)1395b15aabb3Stbbdev void TestVectorIteratorComparisonsBasic( VectorType& vec ) {
1396b15aabb3Stbbdev     REQUIRE_MESSAGE(!vec.empty(), "Incorrect test setup");
1397b15aabb3Stbbdev     Iterator it1, it2;
1398b15aabb3Stbbdev     DoVectorIteratorComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(it1, it2);
1399b15aabb3Stbbdev     it1 = vec.begin();
1400b15aabb3Stbbdev     it2 = vec.begin();
1401b15aabb3Stbbdev     DoVectorIteratorComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(it1, it2);
1402b15aabb3Stbbdev     it2 = std::prev(vec.end());
1403b15aabb3Stbbdev     DoVectorIteratorComparisons</*ExpectEqual = */false, /*ExpectLess = */true>(it1, it2);
1404b15aabb3Stbbdev }
1405b15aabb3Stbbdev 
TestVectorIteratorComparisons()1406b15aabb3Stbbdev void TestVectorIteratorComparisons() {
1407b15aabb3Stbbdev     using vector_type = oneapi::tbb::concurrent_vector<int>;
1408b15aabb3Stbbdev     vector_type vec = {1, 2, 3, 4, 5};
1409b15aabb3Stbbdev     TestVectorIteratorComparisonsBasic<typename vector_type::iterator>(vec);
1410b15aabb3Stbbdev     const vector_type& cvec = vec;
1411b15aabb3Stbbdev     TestVectorIteratorComparisonsBasic<typename vector_type::const_iterator>(cvec);
1412b15aabb3Stbbdev }
141351c0b2f7Stbbdev 
141451c0b2f7Stbbdev //! Test type matching
141551c0b2f7Stbbdev //! \brief \ref interface \ref requirement
141651c0b2f7Stbbdev TEST_CASE("test type matching") {
141749e08aacStbbdev     test_member_types<oneapi::tbb::concurrent_vector>();
141851c0b2f7Stbbdev }
141951c0b2f7Stbbdev 
142051c0b2f7Stbbdev //! Test sequential access to elements
142151c0b2f7Stbbdev //! \brief \ref interface \ref requirement
142251c0b2f7Stbbdev TEST_CASE("testing sequential for") {
142351c0b2f7Stbbdev     TestSequentialFor<move_support_tests::FooWithAssign> ();
142451c0b2f7Stbbdev }
142551c0b2f7Stbbdev 
142651c0b2f7Stbbdev //! Test of assign, grow, copying with various sizes
142751c0b2f7Stbbdev //! \brief \ref interface \ref requirement
142851c0b2f7Stbbdev TEST_CASE("testing resize and copy"){
142951c0b2f7Stbbdev     TestResizeAndCopy();
143051c0b2f7Stbbdev }
143151c0b2f7Stbbdev 
143251c0b2f7Stbbdev //! Test the assignment operator and swap
143351c0b2f7Stbbdev //! \brief \ref interface \ref requirement
143451c0b2f7Stbbdev TEST_CASE("testing copy assignment"){
143551c0b2f7Stbbdev     TestCopyAssignment();
143651c0b2f7Stbbdev }
143751c0b2f7Stbbdev 
143851c0b2f7Stbbdev //! Testing grow_to_at_least operations
143951c0b2f7Stbbdev //! \brief \ref interface
144051c0b2f7Stbbdev TEST_CASE("testing grow_to_at_least with source parameter"){
144149e08aacStbbdev     TestGrowToAtLeastWithSourceParameter<oneapi::tbb::concurrent_vector<int>>(12345);
144251c0b2f7Stbbdev }
144351c0b2f7Stbbdev 
144451c0b2f7Stbbdev //! Test of capacity, reserve, and shrink_to_fit
144551c0b2f7Stbbdev //! \brief \ref interface \ref requirement
144651c0b2f7Stbbdev TEST_CASE("testing capacity"){
144751c0b2f7Stbbdev    TestCapacity();
144851c0b2f7Stbbdev }
144951c0b2f7Stbbdev 
145051c0b2f7Stbbdev #if TBB_USE_EXCEPTIONS
145151c0b2f7Stbbdev //! Test exceptions
145251c0b2f7Stbbdev //! \brief \ref requirement
145351c0b2f7Stbbdev TEST_CASE("testing exceptions"){
145451c0b2f7Stbbdev     TestExceptions();
145551c0b2f7Stbbdev }
145651c0b2f7Stbbdev 
145751c0b2f7Stbbdev //! Test of push_back move exception safety
145851c0b2f7Stbbdev //! \brief \ref requirement
145951c0b2f7Stbbdev TEST_CASE("testing push_back move exception safety"){
146051c0b2f7Stbbdev     TestPushBackMoveExceptionSafety();
146151c0b2f7Stbbdev }
146251c0b2f7Stbbdev 
146351c0b2f7Stbbdev //! Test of emplace back move exception safety
146451c0b2f7Stbbdev //! \brief \ref requirement
146551c0b2f7Stbbdev TEST_CASE("testing emplace back exception safety"){
146651c0b2f7Stbbdev     TestEmplaceBackExceptionSafety();
146751c0b2f7Stbbdev }
146851c0b2f7Stbbdev 
146951c0b2f7Stbbdev //! Test exceptions guarantees for assign operator
147051c0b2f7Stbbdev //! \brief \ref requirement
147151c0b2f7Stbbdev TEST_CASE("testing exception safety guaranteees for assign operator"){
147251c0b2f7Stbbdev     test_ex_assign_operator();
147351c0b2f7Stbbdev }
147451c0b2f7Stbbdev 
147551c0b2f7Stbbdev //! Test exceptions safety guarantees for concurrent_vector move constructor
147651c0b2f7Stbbdev //! \brief \ref requirement
147751c0b2f7Stbbdev TEST_CASE("exception safety guarantees for concurrent_vector move constructor") {
147851c0b2f7Stbbdev     move_support_tests::test_ex_move_constructor<c_vector_type>();
147951c0b2f7Stbbdev }
148051c0b2f7Stbbdev 
148151c0b2f7Stbbdev //! Test exceptions safety guarantees for concurrent_vector move assignment
148251c0b2f7Stbbdev //! \brief \ref requirement
148351c0b2f7Stbbdev TEST_CASE("test exception safety on concurrent_vector move assignment") {
148451c0b2f7Stbbdev     test_ex_move_assignment();
148551c0b2f7Stbbdev }
148651c0b2f7Stbbdev #endif
148751c0b2f7Stbbdev //! Test push_back in move only container
148851c0b2f7Stbbdev //! \brief \ref requirement
148951c0b2f7Stbbdev TEST_CASE("testing push_back move only container"){
149051c0b2f7Stbbdev     TestPushBackMoveOnlyContainer();
149151c0b2f7Stbbdev }
149251c0b2f7Stbbdev 
149351c0b2f7Stbbdev //! Test types for std::iterator_traits in concurrent_vector::iterator
149451c0b2f7Stbbdev //! \brief \ref requirement
149551c0b2f7Stbbdev TEST_CASE("testing std::iterator_traits for concurrent_vector::iterator"){
149649e08aacStbbdev     TestIteratorTraits<oneapi::tbb::concurrent_vector<move_support_tests::Foo>::iterator,move_support_tests::Foo>();
149751c0b2f7Stbbdev }
149851c0b2f7Stbbdev 
149951c0b2f7Stbbdev //! Test types for std::iterator_traits in concurrent_vector::const_iterator
150051c0b2f7Stbbdev //! \brief \ref requirement
150151c0b2f7Stbbdev TEST_CASE("testing std::iterator_traits for concurrent_vector::const_iterator"){
150249e08aacStbbdev     TestIteratorTraits<oneapi::tbb::concurrent_vector<move_support_tests::Foo>::const_iterator,const move_support_tests::Foo>();
150351c0b2f7Stbbdev }
150451c0b2f7Stbbdev 
150551c0b2f7Stbbdev //! Test initializer_list support
150651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
150751c0b2f7Stbbdev TEST_CASE("testing initializer_list support"){
150851c0b2f7Stbbdev     TestInitList();
150951c0b2f7Stbbdev }
151051c0b2f7Stbbdev 
151151c0b2f7Stbbdev //! Test move constructor
151251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
151351c0b2f7Stbbdev TEST_CASE("testing move constructor"){
151451c0b2f7Stbbdev     move_support_tests::test_move_constructor<c_vector_type>();
151551c0b2f7Stbbdev }
151651c0b2f7Stbbdev 
151751c0b2f7Stbbdev //! Test move assign operator
151851c0b2f7Stbbdev //! \brief \ref interface \ref requirement
151951c0b2f7Stbbdev TEST_CASE("testing move assign operator"){
152051c0b2f7Stbbdev     move_support_tests::test_move_assignment<c_vector_type>();
152151c0b2f7Stbbdev }
152251c0b2f7Stbbdev 
152351c0b2f7Stbbdev //! Test constructor with move iterators
152451c0b2f7Stbbdev //! \brief \ref requirement
152551c0b2f7Stbbdev TEST_CASE("testing constructor with move iterators"){
152651c0b2f7Stbbdev     move_support_tests::test_constructor_with_move_iterators<c_vector_type>();
152751c0b2f7Stbbdev }
152851c0b2f7Stbbdev 
152951c0b2f7Stbbdev //! Test assign with move iterators
153051c0b2f7Stbbdev //! \brief \ref interface \ref requirement
153151c0b2f7Stbbdev TEST_CASE("testing assign with move iterators"){
153251c0b2f7Stbbdev     move_support_tests::test_assign_with_move_iterators<c_vector_type>();
153351c0b2f7Stbbdev }
153451c0b2f7Stbbdev 
153551c0b2f7Stbbdev //! Test grow_by with move iterator
153651c0b2f7Stbbdev //! \brief \ref requirement
153751c0b2f7Stbbdev TEST_CASE("testing serial grow_by with move iterator"){
153851c0b2f7Stbbdev     TestSerialGrowByWithMoveIterators();
153951c0b2f7Stbbdev }
154051c0b2f7Stbbdev 
154151c0b2f7Stbbdev //! Test grow_by with move iterator
154251c0b2f7Stbbdev //! \brief \ref requirement
154351c0b2f7Stbbdev TEST_CASE("testing serial move in shrink_to_fit"){
154451c0b2f7Stbbdev     TestSerialMoveInShrinkToFit();
154551c0b2f7Stbbdev }
154651c0b2f7Stbbdev 
154751c0b2f7Stbbdev //! Test concurrent grow
154851c0b2f7Stbbdev //! \brief \ref requirement
154951c0b2f7Stbbdev TEST_CASE("testing concurrency"){
155051c0b2f7Stbbdev     REQUIRE(!move_support_tests::foo_count);
155151c0b2f7Stbbdev     for (std::size_t p = 1; p <= 4; ++p) {
155249e08aacStbbdev         oneapi::tbb::global_control limit(oneapi::tbb::global_control::max_allowed_parallelism, p);
155351c0b2f7Stbbdev         TestParallelFor(p);
155451c0b2f7Stbbdev         TestConcurrentGrowToAtLeast();
155551c0b2f7Stbbdev         TestConcurrentGrowBy();
155651c0b2f7Stbbdev     }
155751c0b2f7Stbbdev 
155851c0b2f7Stbbdev     REQUIRE(!move_support_tests::foo_count);
155951c0b2f7Stbbdev }
156051c0b2f7Stbbdev 
156151c0b2f7Stbbdev //! Test assign operations
156251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
1563b15aabb3Stbbdev TEST_CASE("testing comparison on assign operations"){
156451c0b2f7Stbbdev     TestComparison();
156551c0b2f7Stbbdev }
156651c0b2f7Stbbdev 
156751c0b2f7Stbbdev //! Test allocator_traits support in concurrent_vector
156851c0b2f7Stbbdev //! \brief \ref requirement
156951c0b2f7Stbbdev TEST_CASE("test allocator_traits support in concurrent_vector") {
157051c0b2f7Stbbdev     test_allocator_traits_support<c_vector_type>();
157151c0b2f7Stbbdev }
157251c0b2f7Stbbdev 
157351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
157451c0b2f7Stbbdev //! Test deduction guides
157551c0b2f7Stbbdev //! \brief \ref requirement
157651c0b2f7Stbbdev TEST_CASE("testing deduction guides"){
157749e08aacStbbdev     TestDeductionGuides<oneapi::tbb::concurrent_vector>();
157851c0b2f7Stbbdev }
157951c0b2f7Stbbdev #endif
1580b15aabb3Stbbdev 
1581b15aabb3Stbbdev //! Test concurrent_vector comparisons
1582b15aabb3Stbbdev //! \brief \ref interface \ref requirement
1583b15aabb3Stbbdev TEST_CASE("concurrent_vector comparisons") {
1584b15aabb3Stbbdev     TestVectorComparisons();
1585b15aabb3Stbbdev }
1586b15aabb3Stbbdev 
1587b15aabb3Stbbdev //! Test concurrent_vector iterators comparisons
1588b15aabb3Stbbdev //! \brief \ref interface \ref requirement
1589b15aabb3Stbbdev TEST_CASE("concurrent_vector iterators comparisons") {
1590b15aabb3Stbbdev     TestVectorIteratorComparisons();
1591b15aabb3Stbbdev }
1592