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 "tbb_exception.h"
00026 #include "atomic.h"
00027 #include "cache_aligned_allocator.h"
00028 #include "blocked_range.h"
00029 #include "tbb_machine.h"
00030 #include "tbb_profiling.h"
00031 #include <new>
00032 #include <cstring>
00033
00034 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00035
00036 #pragma warning (push)
00037 #pragma warning (disable: 4530)
00038 #endif
00039
00040 #include <algorithm>
00041 #include <iterator>
00042
00043 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00044 #pragma warning (pop)
00045 #endif
00046
00047 #if _MSC_VER==1500 && !__INTEL_COMPILER
00048
00049 #pragma warning( push )
00050 #pragma warning( disable: 4985 )
00051 #endif
00052 #include <limits>
00053 #if _MSC_VER==1500 && !__INTEL_COMPILER
00054 #pragma warning( pop )
00055 #endif
00056
00057 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
00058
00059 #pragma warning (push)
00060 #pragma warning (disable: 4267)
00061 #endif
00062
00063 namespace tbb {
00064
00065 template<typename T, class A = cache_aligned_allocator<T> >
00066 class concurrent_vector;
00067
00069 namespace internal {
00070
00072 static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
00073
00075
00076 class concurrent_vector_base_v3 {
00077 protected:
00078
00079
00080 typedef size_t segment_index_t;
00081 typedef size_t size_type;
00082
00083
00084 enum {
00085
00086 default_initial_segments = 1,
00088 pointers_per_short_table = 3,
00089 pointers_per_long_table = sizeof(segment_index_t) * 8
00090 };
00091
00092
00093 struct segment_t {
00094 void* array;
00095 #if TBB_USE_ASSERT
00096 ~segment_t() {
00097 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
00098 }
00099 #endif
00100 };
00101
00102
00103
00105 void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00106
00108 atomic<size_type> my_first_block;
00109
00111 atomic<size_type> my_early_size;
00112
00114 atomic<segment_t*> my_segment;
00115
00117 segment_t my_storage[pointers_per_short_table];
00118
00119
00120
00121 concurrent_vector_base_v3() {
00122 my_early_size = 0;
00123 my_first_block = 0;
00124 for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00125 my_storage[i].array = NULL;
00126 my_segment = my_storage;
00127 }
00128 __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
00129
00130 static segment_index_t segment_index_of( size_type index ) {
00131 return segment_index_t( __TBB_Log2( index|1 ) );
00132 }
00133
00134 static segment_index_t segment_base( segment_index_t k ) {
00135 return (segment_index_t(1)<<k & ~segment_index_t(1));
00136 }
00137
00138 static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00139 segment_index_t k = segment_index_of( index );
00140 index -= segment_base(k);
00141 return k;
00142 }
00143
00144 static size_type segment_size( segment_index_t k ) {
00145 return segment_index_t(1)<<k;
00146 }
00147
00149 typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
00150
00152 typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
00153
00155 struct internal_segments_table {
00156 segment_index_t first_block;
00157 void* table[pointers_per_long_table];
00158 };
00159
00160 void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
00161 size_type __TBB_EXPORTED_METHOD internal_capacity() const;
00162 void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00163 size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00164 void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
00165 segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
00166 void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00167 void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00168 void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00169 internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00171 void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
00172 void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
00173
00174 void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
00175 internal_array_op1 destroy, internal_array_op2 init );
00176 size_type __TBB_EXPORTED_METHOD internal_grow_to_at_least_with_result( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00177
00179 void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00180 private:
00182 class helper;
00183 friend class helper;
00184 };
00185
00186 typedef concurrent_vector_base_v3 concurrent_vector_base;
00187
00189
00191 template<typename Container, typename Value>
00192 class vector_iterator
00193 {
00195 Container* my_vector;
00196
00198 size_t my_index;
00199
00201
00202 mutable Value* my_item;
00203
00204 template<typename C, typename T>
00205 friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00206
00207 template<typename C, typename T, typename U>
00208 friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00209
00210 template<typename C, typename T, typename U>
00211 friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00212
00213 template<typename C, typename T, typename U>
00214 friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00215
00216 template<typename C, typename U>
00217 friend class internal::vector_iterator;
00218
00219 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00220 template<typename T, class A>
00221 friend class tbb::concurrent_vector;
00222 #else
00223 public:
00224 #endif
00225
00226 vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
00227 my_vector(const_cast<Container*>(&vector)),
00228 my_index(index),
00229 my_item(static_cast<Value*>(ptr))
00230 {}
00231
00232 public:
00234 vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00235
00236 vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00237 my_vector(other.my_vector),
00238 my_index(other.my_index),
00239 my_item(other.my_item)
00240 {}
00241
00242 vector_iterator operator+( ptrdiff_t offset ) const {
00243 return vector_iterator( *my_vector, my_index+offset );
00244 }
00245 vector_iterator &operator+=( ptrdiff_t offset ) {
00246 my_index+=offset;
00247 my_item = NULL;
00248 return *this;
00249 }
00250 vector_iterator operator-( ptrdiff_t offset ) const {
00251 return vector_iterator( *my_vector, my_index-offset );
00252 }
00253 vector_iterator &operator-=( ptrdiff_t offset ) {
00254 my_index-=offset;
00255 my_item = NULL;
00256 return *this;
00257 }
00258 Value& operator*() const {
00259 Value* item = my_item;
00260 if( !item ) {
00261 item = my_item = &my_vector->internal_subscript(my_index);
00262 }
00263 __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00264 return *item;
00265 }
00266 Value& operator[]( ptrdiff_t k ) const {
00267 return my_vector->internal_subscript(my_index+k);
00268 }
00269 Value* operator->() const {return &operator*();}
00270
00272 vector_iterator& operator++() {
00273 size_t k = ++my_index;
00274 if( my_item ) {
00275
00276 if( (k& (k-2))==0 ) {
00277
00278 my_item= NULL;
00279 } else {
00280 ++my_item;
00281 }
00282 }
00283 return *this;
00284 }
00285
00287 vector_iterator& operator--() {
00288 __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
00289 size_t k = my_index--;
00290 if( my_item ) {
00291
00292 if( (k& (k-2))==0 ) {
00293
00294 my_item= NULL;
00295 } else {
00296 --my_item;
00297 }
00298 }
00299 return *this;
00300 }
00301
00303 vector_iterator operator++(int) {
00304 vector_iterator result = *this;
00305 operator++();
00306 return result;
00307 }
00308
00310 vector_iterator operator--(int) {
00311 vector_iterator result = *this;
00312 operator--();
00313 return result;
00314 }
00315
00316
00317
00318 typedef ptrdiff_t difference_type;
00319 typedef Value value_type;
00320 typedef Value* pointer;
00321 typedef Value& reference;
00322 typedef std::random_access_iterator_tag iterator_category;
00323 };
00324
00325 template<typename Container, typename T>
00326 vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00327 return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
00328 }
00329
00330 template<typename Container, typename T, typename U>
00331 bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00332 return i.my_index==j.my_index && i.my_vector == j.my_vector;
00333 }
00334
00335 template<typename Container, typename T, typename U>
00336 bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00337 return !(i==j);
00338 }
00339
00340 template<typename Container, typename T, typename U>
00341 bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00342 return i.my_index<j.my_index;
00343 }
00344
00345 template<typename Container, typename T, typename U>
00346 bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00347 return j<i;
00348 }
00349
00350 template<typename Container, typename T, typename U>
00351 bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00352 return !(i<j);
00353 }
00354
00355 template<typename Container, typename T, typename U>
00356 bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00357 return !(j<i);
00358 }
00359
00360 template<typename Container, typename T, typename U>
00361 ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00362 return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00363 }
00364
00365 template<typename T, class A>
00366 class allocator_base {
00367 public:
00368 typedef typename A::template
00369 rebind<T>::other allocator_type;
00370 allocator_type my_allocator;
00371
00372 allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00373 };
00374
00375 }
00377
00379
00440 template<typename T, class A>
00441 class concurrent_vector: protected internal::allocator_base<T, A>,
00442 private internal::concurrent_vector_base {
00443 private:
00444 template<typename I>
00445 class generic_range_type: public blocked_range<I> {
00446 public:
00447 typedef T value_type;
00448 typedef T& reference;
00449 typedef const T& const_reference;
00450 typedef I iterator;
00451 typedef ptrdiff_t difference_type;
00452 generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
00453 template<typename U>
00454 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
00455 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00456 };
00457
00458 template<typename C, typename U>
00459 friend class internal::vector_iterator;
00460 public:
00461
00462
00463
00464 typedef internal::concurrent_vector_base_v3::size_type size_type;
00465 typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00466
00467 typedef T value_type;
00468 typedef ptrdiff_t difference_type;
00469 typedef T& reference;
00470 typedef const T& const_reference;
00471 typedef T *pointer;
00472 typedef const T *const_pointer;
00473
00474 typedef internal::vector_iterator<concurrent_vector,T> iterator;
00475 typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00476
00477 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
00478
00479 typedef std::reverse_iterator<iterator> reverse_iterator;
00480 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00481 #else
00482
00483 typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00484 typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00485 #endif
00486
00487
00488
00489
00490 typedef generic_range_type<iterator> range_type;
00491 typedef generic_range_type<const_iterator> const_range_type;
00492
00493
00494
00495
00496
00498 explicit concurrent_vector(const allocator_type &a = allocator_type())
00499 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00500 {
00501 vector_allocator_ptr = &internal_allocator;
00502 }
00503
00505 concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00506 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00507 {
00508 vector_allocator_ptr = &internal_allocator;
00509 __TBB_TRY {
00510 internal_copy(vector, sizeof(T), ©_array);
00511 } __TBB_CATCH(...) {
00512 segment_t *table = my_segment;
00513 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00514 __TBB_RETHROW();
00515 }
00516 }
00517
00519 template<class M>
00520 concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00521 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00522 {
00523 vector_allocator_ptr = &internal_allocator;
00524 __TBB_TRY {
00525 internal_copy(vector.internal_vector_base(), sizeof(T), ©_array);
00526 } __TBB_CATCH(...) {
00527 segment_t *table = my_segment;
00528 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00529 __TBB_RETHROW();
00530 }
00531 }
00532
00534 explicit concurrent_vector(size_type n)
00535 {
00536 vector_allocator_ptr = &internal_allocator;
00537 __TBB_TRY {
00538 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00539 } __TBB_CATCH(...) {
00540 segment_t *table = my_segment;
00541 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00542 __TBB_RETHROW();
00543 }
00544 }
00545
00547 concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00548 : internal::allocator_base<T, A>(a)
00549 {
00550 vector_allocator_ptr = &internal_allocator;
00551 __TBB_TRY {
00552 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00553 } __TBB_CATCH(...) {
00554 segment_t *table = my_segment;
00555 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00556 __TBB_RETHROW();
00557 }
00558 }
00559
00561 template<class I>
00562 concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00563 : internal::allocator_base<T, A>(a)
00564 {
00565 vector_allocator_ptr = &internal_allocator;
00566 __TBB_TRY {
00567 internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00568 } __TBB_CATCH(...) {
00569 segment_t *table = my_segment;
00570 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00571 __TBB_RETHROW();
00572 }
00573 }
00574
00576 concurrent_vector& operator=( const concurrent_vector& vector ) {
00577 if( this != &vector )
00578 internal_assign(vector, sizeof(T), &destroy_array, &assign_array, ©_array);
00579 return *this;
00580 }
00581
00583 template<class M>
00584 concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00585 if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00586 internal_assign(vector.internal_vector_base(),
00587 sizeof(T), &destroy_array, &assign_array, ©_array);
00588 return *this;
00589 }
00590
00591
00592
00593
00595 #if TBB_DEPRECATED
00596
00597 size_type grow_by( size_type delta ) {
00598 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00599 }
00600 #else
00601
00602 iterator grow_by( size_type delta ) {
00603 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
00604 }
00605 #endif
00606
00608 #if TBB_DEPRECATED
00609
00610 size_type grow_by( size_type delta, const_reference t ) {
00611 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00612 }
00613 #else
00614
00615 iterator grow_by( size_type delta, const_reference t ) {
00616 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
00617 }
00618 #endif
00619
00621 #if TBB_DEPRECATED
00622
00624 void grow_to_at_least( size_type n ) {
00625 if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00626 };
00627 #else
00628
00632 iterator grow_to_at_least( size_type n ) {
00633 size_type m=0;
00634 if( n ) {
00635 m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00636 if( m>n ) m=n;
00637 }
00638 return iterator(*this, m);
00639 };
00640 #endif
00641
00643 #if TBB_DEPRECATED
00644 size_type push_back( const_reference item )
00645 #else
00646
00647 iterator push_back( const_reference item )
00648 #endif
00649 {
00650 size_type k;
00651 void *ptr = internal_push_back(sizeof(T),k);
00652 internal_loop_guide loop(1, ptr);
00653 loop.init(&item);
00654 #if TBB_DEPRECATED
00655 return k;
00656 #else
00657 return iterator(*this, k, ptr);
00658 #endif
00659 }
00660
00662
00664 reference operator[]( size_type index ) {
00665 return internal_subscript(index);
00666 }
00667
00669 const_reference operator[]( size_type index ) const {
00670 return internal_subscript(index);
00671 }
00672
00674 reference at( size_type index ) {
00675 return internal_subscript_with_exceptions(index);
00676 }
00677
00679 const_reference at( size_type index ) const {
00680 return internal_subscript_with_exceptions(index);
00681 }
00682
00684 range_type range( size_t grainsize = 1) {
00685 return range_type( begin(), end(), grainsize );
00686 }
00687
00689 const_range_type range( size_t grainsize = 1 ) const {
00690 return const_range_type( begin(), end(), grainsize );
00691 }
00692
00693
00694
00696 size_type size() const {
00697 size_type sz = my_early_size, cp = internal_capacity();
00698 return cp < sz ? cp : sz;
00699 }
00700
00702 bool empty() const {return !my_early_size;}
00703
00705 size_type capacity() const {return internal_capacity();}
00706
00708
00710 void reserve( size_type n ) {
00711 if( n )
00712 internal_reserve(n, sizeof(T), max_size());
00713 }
00714
00716 void resize( size_type n ) {
00717 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00718 }
00719
00721 void resize( size_type n, const_reference t ) {
00722 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00723 }
00724
00725 #if TBB_DEPRECATED
00727 void compact() {shrink_to_fit();}
00728 #endif
00729
00731 void shrink_to_fit();
00732
00734 size_type max_size() const {return (~size_type(0))/sizeof(T);}
00735
00736
00737
00738
00739
00741 iterator begin() {return iterator(*this,0);}
00743 iterator end() {return iterator(*this,size());}
00745 const_iterator begin() const {return const_iterator(*this,0);}
00747 const_iterator end() const {return const_iterator(*this,size());}
00749 const_iterator cbegin() const {return const_iterator(*this,0);}
00751 const_iterator cend() const {return const_iterator(*this,size());}
00753 reverse_iterator rbegin() {return reverse_iterator(end());}
00755 reverse_iterator rend() {return reverse_iterator(begin());}
00757 const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00759 const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00761 const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
00763 const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
00765 reference front() {
00766 __TBB_ASSERT( size()>0, NULL);
00767 return static_cast<T*>(my_segment[0].array)[0];
00768 }
00770 const_reference front() const {
00771 __TBB_ASSERT( size()>0, NULL);
00772 return static_cast<const T*>(my_segment[0].array)[0];
00773 }
00775 reference back() {
00776 __TBB_ASSERT( size()>0, NULL);
00777 return internal_subscript( size()-1 );
00778 }
00780 const_reference back() const {
00781 __TBB_ASSERT( size()>0, NULL);
00782 return internal_subscript( size()-1 );
00783 }
00785 allocator_type get_allocator() const { return this->my_allocator; }
00786
00788 void assign(size_type n, const_reference t) {
00789 clear();
00790 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00791 }
00792
00794 template<class I>
00795 void assign(I first, I last) {
00796 clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00797 }
00798
00800 void swap(concurrent_vector &vector) {
00801 if( this != &vector ) {
00802 concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00803 std::swap(this->my_allocator, vector.my_allocator);
00804 }
00805 }
00806
00808
00809 void clear() {
00810 internal_clear(&destroy_array);
00811 }
00812
00814 ~concurrent_vector() {
00815 segment_t *table = my_segment;
00816 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00817
00818 }
00819
00820 const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00821 private:
00823 static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00824 return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00825 }
00827 void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00828
00830 T& internal_subscript( size_type index ) const;
00831
00833 T& internal_subscript_with_exceptions( size_type index ) const;
00834
00836 void internal_assign_n(size_type n, const_pointer p) {
00837 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
00838 }
00839
00841 template<bool B> class is_integer_tag;
00842
00844 template<class I>
00845 void internal_assign_range(I first, I last, is_integer_tag<true> *) {
00846 internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
00847 }
00849 template<class I>
00850 void internal_assign_range(I first, I last, is_integer_tag<false> *) {
00851 internal_assign_iterators(first, last);
00852 }
00854 template<class I>
00855 void internal_assign_iterators(I first, I last);
00856
00858 static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
00859
00861 static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
00862
00864 static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
00865
00867 static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
00868
00870 static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
00871
00873 class internal_loop_guide : internal::no_copy {
00874 public:
00875 const pointer array;
00876 const size_type n;
00877 size_type i;
00878 internal_loop_guide(size_type ntrials, void *ptr)
00879 : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00880 void init() { for(; i < n; ++i) new( &array[i] ) T(); }
00881 void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00882 void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00883 void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00884 template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00885 ~internal_loop_guide() {
00886 if(i < n)
00887 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00888 }
00889 };
00890 };
00891
00892 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
00893 #pragma warning (push)
00894 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
00895 #endif
00896 template<typename T, class A>
00897 void concurrent_vector<T, A>::shrink_to_fit() {
00898 internal_segments_table old;
00899 __TBB_TRY {
00900 if( internal_compact( sizeof(T), &old, &destroy_array, ©_array ) )
00901 internal_free_segments( old.table, pointers_per_long_table, old.first_block );
00902 } __TBB_CATCH(...) {
00903 if( old.first_block )
00904 internal_free_segments( old.table, 1, old.first_block );
00905 __TBB_RETHROW();
00906 }
00907 }
00908 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
00909 #pragma warning (pop)
00910 #endif // warning 4701 is back
00911
00912 template<typename T, class A>
00913 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00914
00915 while( k > first_block ) {
00916 --k;
00917 T* array = static_cast<T*>(table[k]);
00918 table[k] = NULL;
00919 if( array > internal::vector_allocation_error_flag )
00920 this->my_allocator.deallocate( array, segment_size(k) );
00921 }
00922 T* array = static_cast<T*>(table[0]);
00923 if( array > internal::vector_allocation_error_flag ) {
00924 __TBB_ASSERT( first_block > 0, NULL );
00925 while(k > 0) table[--k] = NULL;
00926 this->my_allocator.deallocate( array, segment_size(first_block) );
00927 }
00928 }
00929
00930 template<typename T, class A>
00931 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00932 __TBB_ASSERT( index < my_early_size, "index out of bounds" );
00933 size_type j = index;
00934 segment_index_t k = segment_base_index_of( j );
00935 __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
00936
00937 T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segment[k].array));
00938 __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
00939 __TBB_ASSERT( array, "index is being allocated" );
00940 return array[j];
00941 }
00942
00943 template<typename T, class A>
00944 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00945 if( index >= my_early_size )
00946 internal::throw_exception(internal::eid_out_of_range);
00947 size_type j = index;
00948 segment_index_t k = segment_base_index_of( j );
00949 if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
00950 internal::throw_exception(internal::eid_segment_range_error);
00951 void *array = my_segment[k].array;
00952 if( array <= internal::vector_allocation_error_flag )
00953 internal::throw_exception(internal::eid_index_range_error);
00954 return static_cast<T*>(array)[j];
00955 }
00956
00957 template<typename T, class A> template<class I>
00958 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00959 __TBB_ASSERT(my_early_size == 0, NULL);
00960 size_type n = std::distance(first, last);
00961 if( !n ) return;
00962 internal_reserve(n, sizeof(T), max_size());
00963 my_early_size = n;
00964 segment_index_t k = 0;
00965 size_type sz = segment_size( my_first_block );
00966 while( sz < n ) {
00967 internal_loop_guide loop(sz, my_segment[k].array);
00968 loop.iterate(first);
00969 n -= sz;
00970 if( !k ) k = my_first_block;
00971 else { ++k; sz <<= 1; }
00972 }
00973 internal_loop_guide loop(n, my_segment[k].array);
00974 loop.iterate(first);
00975 }
00976
00977 template<typename T, class A>
00978 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00979 internal_loop_guide loop(n, begin); loop.init();
00980 }
00981
00982 template<typename T, class A>
00983 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00984 internal_loop_guide loop(n, begin); loop.init(src);
00985 }
00986
00987 template<typename T, class A>
00988 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00989 internal_loop_guide loop(n, dst); loop.copy(src);
00990 }
00991
00992 template<typename T, class A>
00993 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
00994 internal_loop_guide loop(n, dst); loop.assign(src);
00995 }
00996
00997 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
00998
00999 #pragma warning (push)
01000 #pragma warning (disable: 4189)
01001 #endif
01002 template<typename T, class A>
01003 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
01004 T* array = static_cast<T*>(begin);
01005 for( size_type j=n; j>0; --j )
01006 array[j-1].~T();
01007 }
01008 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
01009 #pragma warning (pop)
01010 #endif // warning 4189 is back
01011
01012
01013 template<typename T, class A1, class A2>
01014 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
01015
01016 if(a.size() != b.size()) return false;
01017 typename concurrent_vector<T, A1>::const_iterator i(a.begin());
01018 typename concurrent_vector<T, A2>::const_iterator j(b.begin());
01019 for(; i != a.end(); ++i, ++j)
01020 if( !(*i == *j) ) return false;
01021 return true;
01022 }
01023
01024 template<typename T, class A1, class A2>
01025 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01026 { return !(a == b); }
01027
01028 template<typename T, class A1, class A2>
01029 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01030 { return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
01031
01032 template<typename T, class A1, class A2>
01033 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01034 { return b < a; }
01035
01036 template<typename T, class A1, class A2>
01037 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01038 { return !(b < a); }
01039
01040 template<typename T, class A1, class A2>
01041 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01042 { return !(a < b); }
01043
01044 template<typename T, class A>
01045 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
01046 { a.swap( b ); }
01047
01048 }
01049
01050 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
01051 #pragma warning (pop)
01052 #endif // warning 4267 is back
01053
01054 #endif