00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_concurrent_vector_H
00022 #define __TBB_concurrent_vector_H
00023
00024 #include "tbb_stddef.h"
00025 #include <algorithm>
00026 #include <iterator>
00027 #include <memory>
00028 #include <limits>
00029 #include <new>
00030 #include <cstring>
00031 #include "atomic.h"
00032 #include "cache_aligned_allocator.h"
00033 #include "blocked_range.h"
00034
00035 #include "tbb_machine.h"
00036
00037 #if defined(_MSC_VER) && defined(_Wp64)
00038
00039 #pragma warning (push)
00040 #pragma warning (disable: 4267)
00041 #endif
00042
00043 namespace tbb {
00044
00045 template<typename T, class A = cache_aligned_allocator<T> >
00046 class concurrent_vector;
00047
00049 #define __TBB_BAD_ALLOC reinterpret_cast<void*>(63)
00050
00052 namespace internal {
00053
00055
00056 class concurrent_vector_base_v3 {
00057 protected:
00058
00059
00060 typedef size_t segment_index_t;
00061 typedef size_t size_type;
00062
00063
00064 enum {
00065
00066 default_initial_segments = 1,
00068 pointers_per_short_table = 3,
00069 pointers_per_long_table = sizeof(segment_index_t) * 8
00070 };
00071
00072
00073 struct segment_t {
00074 void* array;
00075 #if TBB_DO_ASSERT
00076 ~segment_t() {
00077 __TBB_ASSERT( array <= __TBB_BAD_ALLOC, "should have been freed by clear" );
00078 }
00079 #endif
00080 };
00081
00082
00083
00085 void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00086
00088 atomic<size_type> my_first_block;
00089
00091 atomic<size_type> my_early_size;
00092
00094 atomic<segment_t*> my_segment;
00095
00097 segment_t my_storage[pointers_per_short_table];
00098
00099
00100
00101 concurrent_vector_base_v3() {
00102 my_early_size = 0;
00103 my_first_block = 0;
00104 for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00105 my_storage[i].array = NULL;
00106 my_segment = my_storage;
00107 }
00108 ~concurrent_vector_base_v3();
00109
00110 static segment_index_t segment_index_of( size_type index ) {
00111 return segment_index_t( __TBB_Log2( index|1 ) );
00112 }
00113
00114 static segment_index_t segment_base( segment_index_t k ) {
00115 return (segment_index_t(1)<<k & ~segment_index_t(1));
00116 }
00117
00118 static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00119 segment_index_t k = segment_index_of( index );
00120 index -= segment_base(k);
00121 return k;
00122 }
00123
00124 static size_type segment_size( segment_index_t k ) {
00125 return segment_index_t(1)<<k;
00126 }
00127
00129 typedef void(*internal_array_op1)(void* begin, size_type n );
00130
00132 typedef void(*internal_array_op2)(void* dst, const void* src, size_type n );
00133
00135 struct internal_segments_table {
00136 segment_index_t first_block;
00137 void* table[pointers_per_long_table];
00138 };
00139
00140 void internal_reserve( size_type n, size_type element_size, size_type max_size );
00141 size_type internal_capacity() const;
00142 void internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00143 void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00144 size_type internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00145 void* internal_push_back( size_type element_size, size_type& index );
00146 segment_index_t internal_clear( internal_array_op1 destroy );
00147 void* internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00148 void internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00149 void internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00150 internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00151 void internal_throw_exception(size_type) const;
00152 void internal_swap(concurrent_vector_base_v3& v);
00153
00154 private:
00156 class helper;
00157 friend class helper;
00158 };
00159
00160 typedef concurrent_vector_base_v3 concurrent_vector_base;
00161
00162
00164
00166 template<typename Container, typename Value>
00167 class vector_iterator
00168 #if defined(_WIN64) && defined(_MSC_VER)
00169
00170 : public std::iterator<std::random_access_iterator_tag,Value>
00171 #endif
00172 {
00174 Container* my_vector;
00175
00177 size_t my_index;
00178
00180
00181 mutable Value* my_item;
00182
00183 template<typename C, typename T>
00184 friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00185
00186 template<typename C, typename T, typename U>
00187 friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00188
00189 template<typename C, typename T, typename U>
00190 friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00191
00192 template<typename C, typename T, typename U>
00193 friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00194
00195 template<typename C, typename U>
00196 friend class internal::vector_iterator;
00197
00198 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00199 template<typename T, class A>
00200 friend class tbb::concurrent_vector;
00201 #else
00202 public:
00203 #endif
00204
00205 vector_iterator( const Container& vector, size_t index ) :
00206 my_vector(const_cast<Container*>(&vector)),
00207 my_index(index),
00208 my_item(NULL)
00209 {}
00210
00211 public:
00213 vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00214
00215 vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00216 my_vector(other.my_vector),
00217 my_index(other.my_index),
00218 my_item(other.my_item)
00219 {}
00220
00221 vector_iterator operator+( ptrdiff_t offset ) const {
00222 return vector_iterator( *my_vector, my_index+offset );
00223 }
00224 vector_iterator operator+=( ptrdiff_t offset ) {
00225 my_index+=offset;
00226 my_item = NULL;
00227 return *this;
00228 }
00229 vector_iterator operator-( ptrdiff_t offset ) const {
00230 return vector_iterator( *my_vector, my_index-offset );
00231 }
00232 vector_iterator operator-=( ptrdiff_t offset ) {
00233 my_index-=offset;
00234 my_item = NULL;
00235 return *this;
00236 }
00237 Value& operator*() const {
00238 Value* item = my_item;
00239 if( !item ) {
00240 item = my_item = &my_vector->internal_subscript(my_index);
00241 }
00242 __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00243 return *item;
00244 }
00245 Value& operator[]( ptrdiff_t k ) const {
00246 return my_vector->internal_subscript(my_index+k);
00247 }
00248 Value* operator->() const {return &operator*();}
00249
00251 vector_iterator& operator++() {
00252 size_t k = ++my_index;
00253 if( my_item ) {
00254
00255 if( (k& (k-2))==0 ) {
00256
00257 my_item= NULL;
00258 } else {
00259 ++my_item;
00260 }
00261 }
00262 return *this;
00263 }
00264
00266 vector_iterator& operator--() {
00267 __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
00268 size_t k = my_index--;
00269 if( my_item ) {
00270
00271 if( (k& (k-2))==0 ) {
00272
00273 my_item= NULL;
00274 } else {
00275 --my_item;
00276 }
00277 }
00278 return *this;
00279 }
00280
00282 vector_iterator operator++(int) {
00283 vector_iterator result = *this;
00284 operator++();
00285 return result;
00286 }
00287
00289 vector_iterator operator--(int) {
00290 vector_iterator result = *this;
00291 operator--();
00292 return result;
00293 }
00294
00295
00296
00297 typedef ptrdiff_t difference_type;
00298 typedef Value value_type;
00299 typedef Value* pointer;
00300 typedef Value& reference;
00301 typedef std::random_access_iterator_tag iterator_category;
00302 };
00303
00304 template<typename Container, typename T>
00305 vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00306 return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
00307 }
00308
00309 template<typename Container, typename T, typename U>
00310 bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00311 return i.my_index==j.my_index;
00312 }
00313
00314 template<typename Container, typename T, typename U>
00315 bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00316 return !(i==j);
00317 }
00318
00319 template<typename Container, typename T, typename U>
00320 bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00321 return i.my_index<j.my_index;
00322 }
00323
00324 template<typename Container, typename T, typename U>
00325 bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00326 return j<i;
00327 }
00328
00329 template<typename Container, typename T, typename U>
00330 bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00331 return !(i<j);
00332 }
00333
00334 template<typename Container, typename T, typename U>
00335 bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00336 return !(j<i);
00337 }
00338
00339 template<typename Container, typename T, typename U>
00340 ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00341 return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00342 }
00343
00344 template<typename T, class A>
00345 class allocator_base {
00346 public:
00347 typedef typename A::template
00348 rebind<T>::other allocator_type;
00349 allocator_type my_allocator;
00350
00351 allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00352 };
00353
00354 }
00356
00358
00413 template<typename T, class A>
00414 class concurrent_vector: protected internal::allocator_base<T, A>,
00415 private internal::concurrent_vector_base_v3 {
00416 private:
00417 template<typename I>
00418 class generic_range_type: public blocked_range<I> {
00419 public:
00420 typedef T value_type;
00421 typedef T& reference;
00422 typedef const T& const_reference;
00423 typedef I iterator;
00424 typedef ptrdiff_t difference_type;
00425 generic_range_type( I begin_, I end_, size_t grainsize = 1) : blocked_range<I>(begin_,end_,grainsize) {}
00426 template<typename U>
00427 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
00428 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00429 };
00430
00431 template<typename C, typename U>
00432 friend class internal::vector_iterator;
00433 public:
00434
00435
00436
00437 typedef internal::concurrent_vector_base_v3::size_type size_type;
00438 typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00439
00440 typedef T value_type;
00441 typedef ptrdiff_t difference_type;
00442 typedef T& reference;
00443 typedef const T& const_reference;
00444 typedef T *pointer;
00445 typedef const T *const_pointer;
00446
00447 typedef internal::vector_iterator<concurrent_vector,T> iterator;
00448 typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00449
00450 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
00451
00452 typedef std::reverse_iterator<iterator> reverse_iterator;
00453 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00454 #else
00455
00456 typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00457 typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00458 #endif
00459
00460
00461
00462
00463 typedef generic_range_type<iterator> range_type;
00464 typedef generic_range_type<const_iterator> const_range_type;
00465
00466
00467
00468
00469
00471 explicit concurrent_vector(const allocator_type &a = allocator_type())
00472 : internal::allocator_base<T, A>(a)
00473 {
00474 vector_allocator_ptr = &internal_allocator;
00475 }
00476
00478 concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00479 : internal::allocator_base<T, A>(a)
00480 {
00481 vector_allocator_ptr = &internal_allocator;
00482 internal_copy(vector, sizeof(T), ©_array);
00483 }
00484
00486 template<class M>
00487 concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00488 : internal::allocator_base<T, A>(a)
00489 {
00490 vector_allocator_ptr = &internal_allocator;
00491 internal_copy(vector.internal_vector_base(), sizeof(T), ©_array);
00492 }
00493
00495 explicit concurrent_vector(size_type n)
00496 {
00497 vector_allocator_ptr = &internal_allocator;
00498 if ( !n ) return;
00499 internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00500 __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00501 initialize_array(static_cast<T*>(my_segment[0].array), NULL, n);
00502 }
00503
00505 concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00506 : internal::allocator_base<T, A>(a)
00507 {
00508 vector_allocator_ptr = &internal_allocator;
00509 internal_assign( n, t );
00510 }
00511
00513 template<class I>
00514 concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00515 : internal::allocator_base<T, A>(a)
00516 {
00517 vector_allocator_ptr = &internal_allocator;
00518 internal_assign(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00519 }
00520
00522 concurrent_vector& operator=( const concurrent_vector& vector ) {
00523 if( this != &vector )
00524 concurrent_vector_base_v3::internal_assign(vector, sizeof(T), &destroy_array, &assign_array, ©_array);
00525 return *this;
00526 }
00527
00529 template<class M>
00530 concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00531 if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00532 concurrent_vector_base_v3::internal_assign(vector.internal_vector_base(),
00533 sizeof(T), &destroy_array, &assign_array, ©_array);
00534 return *this;
00535 }
00536
00537
00538
00539
00541
00542 size_type grow_by( size_type delta ) {
00543 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00544 }
00545
00547
00548 size_type grow_by( size_type delta, const_reference t ) {
00549 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00550 }
00551
00553 void grow_to_at_least( size_type n ) {
00554 if( my_early_size<n )
00555 internal_grow_to_at_least( n, sizeof(T), &initialize_array, NULL );
00556 };
00557
00559 size_type push_back( const_reference item ) {
00560 size_type k;
00561 internal_loop_guide loop(1, internal_push_back(sizeof(T),k));
00562 loop.init(&item);
00563 return k;
00564 }
00565
00567
00569 reference operator[]( size_type index ) {
00570 return internal_subscript(index);
00571 }
00572
00574 const_reference operator[]( size_type index ) const {
00575 return internal_subscript(index);
00576 }
00577
00579 reference at( size_type index ) {
00580 return internal_subscript_with_exceptions(index);
00581 }
00582
00584 const_reference at( size_type index ) const {
00585 return internal_subscript_with_exceptions(index);
00586 }
00587
00589 range_type range( size_t grainsize = 1) {
00590 return range_type( begin(), end(), grainsize );
00591 }
00592
00594 const_range_type range( size_t grainsize = 1 ) const {
00595 return const_range_type( begin(), end(), grainsize );
00596 }
00597
00598
00599
00601 size_type size() const {return my_early_size;}
00602
00604 bool empty() const {return !my_early_size;}
00605
00607 size_type capacity() const {return internal_capacity();}
00608
00610
00612 void reserve( size_type n ) {
00613 if( n )
00614 internal_reserve(n, sizeof(T), max_size());
00615 }
00616
00618 void compact();
00619
00621 size_type max_size() const {return (~size_type(0))/sizeof(T);}
00622
00623
00624
00625
00626
00628 iterator begin() {return iterator(*this,0);}
00630 iterator end() {return iterator(*this,size());}
00632 const_iterator begin() const {return const_iterator(*this,0);}
00634 const_iterator end() const {return const_iterator(*this,size());}
00636 reverse_iterator rbegin() {return reverse_iterator(end());}
00638 reverse_iterator rend() {return reverse_iterator(begin());}
00640 const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00642 const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00644 reference front() {
00645 __TBB_ASSERT( size()>0, NULL);
00646 return static_cast<T*>(my_segment[0].array)[0];
00647 }
00649 const_reference front() const {
00650 __TBB_ASSERT( size()>0, NULL);
00651 return static_cast<const T*>(my_segment[0].array)[0];
00652 }
00654 reference back() {
00655 __TBB_ASSERT( size()>0, NULL);
00656 return internal_subscript( my_early_size-1 );
00657 }
00659 const_reference back() const {
00660 __TBB_ASSERT( size()>0, NULL);
00661 return internal_subscript( my_early_size-1 );
00662 }
00664 allocator_type get_allocator() const { return this->my_allocator; }
00665
00667 void assign(size_type n, const_reference t) { clear(); internal_assign( n, t ); }
00668
00670 template<class I>
00671 void assign(I first, I last) {
00672 clear(); internal_assign( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00673 }
00674
00676 void swap(concurrent_vector &vector) {
00677 if( this != &vector ) {
00678 concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00679 std::swap(this->my_allocator, vector.my_allocator);
00680 }
00681 }
00682
00684 void clear() {
00685 segment_t *table = my_segment;
00686 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00687 my_first_block = 0;
00688 }
00689
00691 ~concurrent_vector() {
00692 clear();
00693
00694 }
00695
00696 const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00697 private:
00699 static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00700 return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00701 }
00703 void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00704
00706 T& internal_subscript( size_type index ) const;
00707
00709 T& internal_subscript_with_exceptions( size_type index ) const;
00710
00712 void internal_assign(size_type n, const_reference t);
00713
00715 template<bool B> class is_integer_tag;
00716
00718 template<class I>
00719 void internal_assign(I first, I last, is_integer_tag<true> *) {
00720 internal_assign(static_cast<size_type>(first), static_cast<T>(last));
00721 }
00723 template<class I>
00724 void internal_assign(I first, I last, is_integer_tag<false> *) {
00725 internal_assign_iterators(first, last);
00726 }
00728 template<class I>
00729 void internal_assign_iterators(I first, I last);
00730
00732 static void initialize_array( void* begin, const void*, size_type n );
00733
00735 static void initialize_array_by( void* begin, const void* src, size_type n );
00736
00738 static void copy_array( void* dst, const void* src, size_type n );
00739
00741 static void assign_array( void* dst, const void* src, size_type n );
00742
00744 static void destroy_array( void* begin, size_type n );
00745
00747 class internal_loop_guide {
00748 public:
00749 const pointer array;
00750 const size_type n;
00751 size_type i;
00752 internal_loop_guide(size_type ntrials, void *ptr)
00753 : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00754 void init() { for(; i < n; ++i) new( &array[i] ) T(); }
00755 void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00756 void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00757 void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00758 template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00759 ~internal_loop_guide() {
00760 if(i < n)
00761 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00762 }
00763 };
00764 };
00765
00766 template<typename T, class A>
00767 void concurrent_vector<T, A>::compact() {
00768 internal_segments_table old;
00769 try {
00770 if( internal_compact( sizeof(T), &old, &destroy_array, ©_array ) )
00771 internal_free_segments( old.table, pointers_per_long_table, old.first_block );
00772 } catch(...) {
00773 if( old.first_block )
00774 internal_free_segments( old.table, 1, old.first_block );
00775 throw;
00776 }
00777 }
00778
00779 template<typename T, class A>
00780 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00781
00782 while( k > first_block ) {
00783 --k;
00784 T* array = static_cast<T*>(table[k]);
00785 table[k] = NULL;
00786 if( array > __TBB_BAD_ALLOC )
00787 this->my_allocator.deallocate( array, segment_size(k) );
00788 }
00789 T* array = static_cast<T*>(table[0]);
00790 if( array > __TBB_BAD_ALLOC ) {
00791 __TBB_ASSERT( first_block > 0, NULL );
00792 while(k > 0) table[--k] = NULL;
00793 this->my_allocator.deallocate( array, segment_size(first_block) );
00794 }
00795 }
00796
00797 template<typename T, class A>
00798 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00799 __TBB_ASSERT( index<size(), "index out of bounds" );
00800 size_type j = index;
00801 segment_index_t k = segment_base_index_of( j );
00802
00803 return static_cast<T*>(my_segment[k].array)[j];
00804 }
00805
00806 template<typename T, class A>
00807 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00808 if( index >= size() )
00809 internal_throw_exception(0);
00810 size_type j = index;
00811 segment_index_t k = segment_base_index_of( j );
00812 if( my_segment == (segment_t*)my_storage && k >= pointers_per_short_table )
00813 internal_throw_exception(1);
00814 void *array = my_segment[k].array;
00815 if( array <= __TBB_BAD_ALLOC )
00816 internal_throw_exception(2);
00817 return static_cast<T*>(array)[j];
00818 }
00819
00820 template<typename T, class A>
00821 void concurrent_vector<T, A>::internal_assign(size_type n, const_reference t)
00822 {
00823 if( !n ) return;
00824 internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00825 __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00826 initialize_array_by(static_cast<T*>(my_segment[0].array), static_cast<const void*>(&t), n);
00827 }
00828
00829 template<typename T, class A> template<class I>
00830 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00831 size_type n = std::distance(first, last);
00832 if( !n ) return;
00833 internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00834 __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00835 internal_loop_guide loop(n, my_segment[0].array); loop.iterate(first);
00836 }
00837
00838 template<typename T, class A>
00839 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00840 internal_loop_guide loop(n, begin); loop.init();
00841 }
00842
00843 template<typename T, class A>
00844 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00845 internal_loop_guide loop(n, begin); loop.init(src);
00846 }
00847
00848 template<typename T, class A>
00849 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00850 internal_loop_guide loop(n, dst); loop.copy(src);
00851 }
00852
00853 template<typename T, class A>
00854 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
00855 internal_loop_guide loop(n, dst); loop.assign(src);
00856 }
00857
00858 template<typename T, class A>
00859 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
00860 T* array = static_cast<T*>(begin);
00861 for( size_type j=n; j>0; --j )
00862 array[j-1].~T();
00863 }
00864
00865
00866 template<typename T, class A1, class A2>
00867 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
00868
00869
00870 if(a.size() != b.size()) return false;
00871 typename concurrent_vector<T, A1>::const_iterator i(a.begin());
00872 typename concurrent_vector<T, A2>::const_iterator j(b.begin());
00873 for(; i != a.end(); ++i, ++j)
00874 if( !(*i == *j) ) return false;
00875 return true;
00876 }
00877
00878 template<typename T, class A1, class A2>
00879 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00880 { return !(a == b); }
00881
00882 template<typename T, class A1, class A2>
00883 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00884 { return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
00885
00886 template<typename T, class A1, class A2>
00887 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00888 { return b < a; }
00889
00890 template<typename T, class A1, class A2>
00891 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00892 { return !(b < a); }
00893
00894 template<typename T, class A1, class A2>
00895 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00896 { return !(a < b); }
00897
00898 template<typename T, class A>
00899 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
00900 { a.swap( b ); }
00901
00902 }
00903
00904 #if defined(_MSC_VER) && defined(_Wp64)
00905
00906 #pragma warning (pop)
00907 #endif
00908
00909 #endif