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(), ¬_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