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 __TBB_INITIALIZER_LISTS_PRESENT
00058 #include <initializer_list>
00059 #endif
00060
00061 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
00062
00063 #pragma warning (push)
00064 #pragma warning (disable: 4267)
00065 #endif
00066
00067 namespace tbb {
00068
00069 template<typename T, class A = cache_aligned_allocator<T> >
00070 class concurrent_vector;
00071
00073 namespace internal {
00074
00076 static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
00077
00079
00080 class concurrent_vector_base_v3 {
00081 protected:
00082
00083
00084 typedef size_t segment_index_t;
00085 typedef size_t size_type;
00086
00087
00088 enum {
00089
00090 default_initial_segments = 1,
00092 pointers_per_short_table = 3,
00093 pointers_per_long_table = sizeof(segment_index_t) * 8
00094 };
00095
00096
00097 struct segment_t {
00098 void* array;
00099 #if TBB_USE_ASSERT
00100 ~segment_t() {
00101 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
00102 }
00103 #endif
00104 };
00105
00106
00107
00109 void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00110
00112 atomic<size_type> my_first_block;
00113
00115 atomic<size_type> my_early_size;
00116
00118 atomic<segment_t*> my_segment;
00119
00121 segment_t my_storage[pointers_per_short_table];
00122
00123
00124
00125 concurrent_vector_base_v3() {
00126 my_early_size = 0;
00127 my_first_block = 0;
00128 for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00129 my_storage[i].array = NULL;
00130 my_segment = my_storage;
00131 }
00132 __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
00133
00134 static segment_index_t segment_index_of( size_type index ) {
00135 return segment_index_t( __TBB_Log2( index|1 ) );
00136 }
00137
00138 static segment_index_t segment_base( segment_index_t k ) {
00139 return (segment_index_t(1)<<k & ~segment_index_t(1));
00140 }
00141
00142 static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00143 segment_index_t k = segment_index_of( index );
00144 index -= segment_base(k);
00145 return k;
00146 }
00147
00148 static size_type segment_size( segment_index_t k ) {
00149 return segment_index_t(1)<<k;
00150 }
00151
00153 typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
00154
00156 typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
00157
00159 struct internal_segments_table {
00160 segment_index_t first_block;
00161 void* table[pointers_per_long_table];
00162 };
00163
00164 void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
00165 size_type __TBB_EXPORTED_METHOD internal_capacity() const;
00166 void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00167 size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00168 void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
00169 segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
00170 void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00171 void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00172 void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00173 internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00175 void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
00176 void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
00177
00178 void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
00179 internal_array_op1 destroy, internal_array_op2 init );
00180 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 );
00181
00183 void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00184 private:
00186 class helper;
00187 friend class helper;
00188 };
00189
00190 typedef concurrent_vector_base_v3 concurrent_vector_base;
00191
00193
00195 template<typename Container, typename Value>
00196 class vector_iterator
00197 {
00199 Container* my_vector;
00200
00202 size_t my_index;
00203
00205
00206 mutable Value* my_item;
00207
00208 template<typename C, typename T>
00209 friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00210
00211 template<typename C, typename T, typename U>
00212 friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00213
00214 template<typename C, typename T, typename U>
00215 friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00216
00217 template<typename C, typename T, typename U>
00218 friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00219
00220 template<typename C, typename U>
00221 friend class internal::vector_iterator;
00222
00223 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00224 template<typename T, class A>
00225 friend class tbb::concurrent_vector;
00226 #else
00227 public:
00228 #endif
00229
00230 vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
00231 my_vector(const_cast<Container*>(&vector)),
00232 my_index(index),
00233 my_item(static_cast<Value*>(ptr))
00234 {}
00235
00236 public:
00238 vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00239
00240 vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00241 my_vector(other.my_vector),
00242 my_index(other.my_index),
00243 my_item(other.my_item)
00244 {}
00245
00246 vector_iterator operator+( ptrdiff_t offset ) const {
00247 return vector_iterator( *my_vector, my_index+offset );
00248 }
00249 vector_iterator &operator+=( ptrdiff_t offset ) {
00250 my_index+=offset;
00251 my_item = NULL;
00252 return *this;
00253 }
00254 vector_iterator operator-( ptrdiff_t offset ) const {
00255 return vector_iterator( *my_vector, my_index-offset );
00256 }
00257 vector_iterator &operator-=( ptrdiff_t offset ) {
00258 my_index-=offset;
00259 my_item = NULL;
00260 return *this;
00261 }
00262 Value& operator*() const {
00263 Value* item = my_item;
00264 if( !item ) {
00265 item = my_item = &my_vector->internal_subscript(my_index);
00266 }
00267 __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00268 return *item;
00269 }
00270 Value& operator[]( ptrdiff_t k ) const {
00271 return my_vector->internal_subscript(my_index+k);
00272 }
00273 Value* operator->() const {return &operator*();}
00274
00276 vector_iterator& operator++() {
00277 size_t k = ++my_index;
00278 if( my_item ) {
00279
00280 if( (k& (k-2))==0 ) {
00281
00282 my_item= NULL;
00283 } else {
00284 ++my_item;
00285 }
00286 }
00287 return *this;
00288 }
00289
00291 vector_iterator& operator--() {
00292 __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
00293 size_t k = my_index--;
00294 if( my_item ) {
00295
00296 if( (k& (k-2))==0 ) {
00297
00298 my_item= NULL;
00299 } else {
00300 --my_item;
00301 }
00302 }
00303 return *this;
00304 }
00305
00307 vector_iterator operator++(int) {
00308 vector_iterator result = *this;
00309 operator++();
00310 return result;
00311 }
00312
00314 vector_iterator operator--(int) {
00315 vector_iterator result = *this;
00316 operator--();
00317 return result;
00318 }
00319
00320
00321
00322 typedef ptrdiff_t difference_type;
00323 typedef Value value_type;
00324 typedef Value* pointer;
00325 typedef Value& reference;
00326 typedef std::random_access_iterator_tag iterator_category;
00327 };
00328
00329 template<typename Container, typename T>
00330 vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00331 return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
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 i.my_index==j.my_index && i.my_vector == j.my_vector;
00337 }
00338
00339 template<typename Container, typename T, typename U>
00340 bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00341 return !(i==j);
00342 }
00343
00344 template<typename Container, typename T, typename U>
00345 bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00346 return i.my_index<j.my_index;
00347 }
00348
00349 template<typename Container, typename T, typename U>
00350 bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00351 return j<i;
00352 }
00353
00354 template<typename Container, typename T, typename U>
00355 bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00356 return !(i<j);
00357 }
00358
00359 template<typename Container, typename T, typename U>
00360 bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00361 return !(j<i);
00362 }
00363
00364 template<typename Container, typename T, typename U>
00365 ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00366 return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00367 }
00368
00369 template<typename T, class A>
00370 class allocator_base {
00371 public:
00372 typedef typename A::template
00373 rebind<T>::other allocator_type;
00374 allocator_type my_allocator;
00375
00376 allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00377 };
00378
00379 }
00381
00383
00444 template<typename T, class A>
00445 class concurrent_vector: protected internal::allocator_base<T, A>,
00446 private internal::concurrent_vector_base {
00447 private:
00448 template<typename I>
00449 class generic_range_type: public blocked_range<I> {
00450 public:
00451 typedef T value_type;
00452 typedef T& reference;
00453 typedef const T& const_reference;
00454 typedef I iterator;
00455 typedef ptrdiff_t difference_type;
00456 generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
00457 template<typename U>
00458 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
00459 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00460 };
00461
00462 template<typename C, typename U>
00463 friend class internal::vector_iterator;
00464 public:
00465
00466
00467
00468 typedef internal::concurrent_vector_base_v3::size_type size_type;
00469 typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00470
00471 typedef T value_type;
00472 typedef ptrdiff_t difference_type;
00473 typedef T& reference;
00474 typedef const T& const_reference;
00475 typedef T *pointer;
00476 typedef const T *const_pointer;
00477
00478 typedef internal::vector_iterator<concurrent_vector,T> iterator;
00479 typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00480
00481 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
00482
00483 typedef std::reverse_iterator<iterator> reverse_iterator;
00484 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00485 #else
00486
00487 typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00488 typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00489 #endif
00490
00491
00492
00493
00494 typedef generic_range_type<iterator> range_type;
00495 typedef generic_range_type<const_iterator> const_range_type;
00496
00497
00498
00499
00500
00502 explicit concurrent_vector(const allocator_type &a = allocator_type())
00503 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00504 {
00505 vector_allocator_ptr = &internal_allocator;
00506 }
00507
00508 #if __TBB_INITIALIZER_LISTS_PRESENT
00510 concurrent_vector(std::initializer_list<T> init_list, const allocator_type &a = allocator_type())
00511 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00512 {
00513 vector_allocator_ptr = &internal_allocator;
00514 __TBB_TRY {
00515 internal_assign_iterators(init_list.begin(), init_list.end());
00516 } __TBB_CATCH(...) {
00517 segment_t *table = my_segment;
00518 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00519 __TBB_RETHROW();
00520 }
00521
00522 }
00523 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
00524
00526 concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00527 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00528 {
00529 vector_allocator_ptr = &internal_allocator;
00530 __TBB_TRY {
00531 internal_copy(vector, sizeof(T), ©_array);
00532 } __TBB_CATCH(...) {
00533 segment_t *table = my_segment;
00534 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00535 __TBB_RETHROW();
00536 }
00537 }
00538
00540 template<class M>
00541 concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00542 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00543 {
00544 vector_allocator_ptr = &internal_allocator;
00545 __TBB_TRY {
00546 internal_copy(vector.internal_vector_base(), sizeof(T), ©_array);
00547 } __TBB_CATCH(...) {
00548 segment_t *table = my_segment;
00549 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00550 __TBB_RETHROW();
00551 }
00552 }
00553
00555 explicit concurrent_vector(size_type n)
00556 {
00557 vector_allocator_ptr = &internal_allocator;
00558 __TBB_TRY {
00559 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00560 } __TBB_CATCH(...) {
00561 segment_t *table = my_segment;
00562 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00563 __TBB_RETHROW();
00564 }
00565 }
00566
00568 concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00569 : internal::allocator_base<T, A>(a)
00570 {
00571 vector_allocator_ptr = &internal_allocator;
00572 __TBB_TRY {
00573 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00574 } __TBB_CATCH(...) {
00575 segment_t *table = my_segment;
00576 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00577 __TBB_RETHROW();
00578 }
00579 }
00580
00582 template<class I>
00583 concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00584 : internal::allocator_base<T, A>(a)
00585 {
00586 vector_allocator_ptr = &internal_allocator;
00587 __TBB_TRY {
00588 internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00589 } __TBB_CATCH(...) {
00590 segment_t *table = my_segment;
00591 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00592 __TBB_RETHROW();
00593 }
00594 }
00595
00597 concurrent_vector& operator=( const concurrent_vector& vector ) {
00598 if( this != &vector )
00599 internal_assign(vector, sizeof(T), &destroy_array, &assign_array, ©_array);
00600 return *this;
00601 }
00602
00603
00604
00606 template<class M>
00607 concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00608 if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00609 internal_assign(vector.internal_vector_base(),
00610 sizeof(T), &destroy_array, &assign_array, ©_array);
00611 return *this;
00612 }
00613
00614 #if __TBB_INITIALIZER_LISTS_PRESENT
00616 concurrent_vector& operator=( const std::initializer_list<T> & init_list) {
00617 internal_clear(&destroy_array);
00618 internal_assign_iterators(init_list.begin(), init_list.end());
00619 return *this;
00620 }
00621 #endif //#if __TBB_INITIALIZER_LISTS_PRESENT
00622
00623
00624
00625
00626
00627
00629 #if TBB_DEPRECATED
00630
00631 size_type grow_by( size_type delta ) {
00632 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00633 }
00634 #else
00635
00636 iterator grow_by( size_type delta ) {
00637 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
00638 }
00639 #endif
00640
00642 #if TBB_DEPRECATED
00643
00644 size_type grow_by( size_type delta, const_reference t ) {
00645 return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00646 }
00647 #else
00648
00649 iterator grow_by( size_type delta, const_reference t ) {
00650 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
00651 }
00652 #endif
00653
00655 #if TBB_DEPRECATED
00656
00658 void grow_to_at_least( size_type n ) {
00659 if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00660 };
00661 #else
00662
00666 iterator grow_to_at_least( size_type n ) {
00667 size_type m=0;
00668 if( n ) {
00669 m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00670 if( m>n ) m=n;
00671 }
00672 return iterator(*this, m);
00673 };
00674 #endif
00675
00677 #if TBB_DEPRECATED
00678 size_type push_back( const_reference item )
00679 #else
00680
00681 iterator push_back( const_reference item )
00682 #endif
00683 {
00684 size_type k;
00685 void *ptr = internal_push_back(sizeof(T),k);
00686 internal_loop_guide loop(1, ptr);
00687 loop.init(&item);
00688 #if TBB_DEPRECATED
00689 return k;
00690 #else
00691 return iterator(*this, k, ptr);
00692 #endif
00693 }
00694
00696
00698 reference operator[]( size_type index ) {
00699 return internal_subscript(index);
00700 }
00701
00703 const_reference operator[]( size_type index ) const {
00704 return internal_subscript(index);
00705 }
00706
00708 reference at( size_type index ) {
00709 return internal_subscript_with_exceptions(index);
00710 }
00711
00713 const_reference at( size_type index ) const {
00714 return internal_subscript_with_exceptions(index);
00715 }
00716
00718 range_type range( size_t grainsize = 1 ) {
00719 return range_type( begin(), end(), grainsize );
00720 }
00721
00723 const_range_type range( size_t grainsize = 1 ) const {
00724 return const_range_type( begin(), end(), grainsize );
00725 }
00726
00727
00728
00729
00731 size_type size() const {
00732 size_type sz = my_early_size, cp = internal_capacity();
00733 return cp < sz ? cp : sz;
00734 }
00735
00737 bool empty() const {return !my_early_size;}
00738
00740 size_type capacity() const {return internal_capacity();}
00741
00743
00745 void reserve( size_type n ) {
00746 if( n )
00747 internal_reserve(n, sizeof(T), max_size());
00748 }
00749
00751 void resize( size_type n ) {
00752 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00753 }
00754
00756 void resize( size_type n, const_reference t ) {
00757 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00758 }
00759
00760 #if TBB_DEPRECATED
00762 void compact() {shrink_to_fit();}
00763 #endif
00764
00766 void shrink_to_fit();
00767
00769 size_type max_size() const {return (~size_type(0))/sizeof(T);}
00770
00771
00772
00773
00774
00776 iterator begin() {return iterator(*this,0);}
00778 iterator end() {return iterator(*this,size());}
00780 const_iterator begin() const {return const_iterator(*this,0);}
00782 const_iterator end() const {return const_iterator(*this,size());}
00784 const_iterator cbegin() const {return const_iterator(*this,0);}
00786 const_iterator cend() const {return const_iterator(*this,size());}
00788 reverse_iterator rbegin() {return reverse_iterator(end());}
00790 reverse_iterator rend() {return reverse_iterator(begin());}
00792 const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00794 const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00796 const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
00798 const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
00800 reference front() {
00801 __TBB_ASSERT( size()>0, NULL);
00802 return static_cast<T*>(my_segment[0].array)[0];
00803 }
00805 const_reference front() const {
00806 __TBB_ASSERT( size()>0, NULL);
00807 return static_cast<const T*>(my_segment[0].array)[0];
00808 }
00810 reference back() {
00811 __TBB_ASSERT( size()>0, NULL);
00812 return internal_subscript( size()-1 );
00813 }
00815 const_reference back() const {
00816 __TBB_ASSERT( size()>0, NULL);
00817 return internal_subscript( size()-1 );
00818 }
00820 allocator_type get_allocator() const { return this->my_allocator; }
00821
00823 void assign(size_type n, const_reference t) {
00824 clear();
00825 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00826 }
00827
00829 template<class I>
00830 void assign(I first, I last) {
00831 clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00832 }
00833
00834 #if __TBB_INITIALIZER_LISTS_PRESENT
00836 void assign(std::initializer_list<T> init_list) {
00837 clear(); internal_assign_iterators( init_list.begin(), init_list.end());
00838 }
00839 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
00840
00842 void swap(concurrent_vector &vector) {
00843 if( this != &vector ) {
00844 concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00845 std::swap(this->my_allocator, vector.my_allocator);
00846 }
00847 }
00848
00850
00851 void clear() {
00852 internal_clear(&destroy_array);
00853 }
00854
00856 ~concurrent_vector() {
00857 segment_t *table = my_segment;
00858 internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00859
00860 }
00861
00862 const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00863 private:
00865 static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00866 return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00867 }
00869 void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00870
00872 T& internal_subscript( size_type index ) const;
00873
00875 T& internal_subscript_with_exceptions( size_type index ) const;
00876
00878 void internal_assign_n(size_type n, const_pointer p) {
00879 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
00880 }
00881
00883 template<bool B> class is_integer_tag;
00884
00886 template<class I>
00887 void internal_assign_range(I first, I last, is_integer_tag<true> *) {
00888 internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
00889 }
00891 template<class I>
00892 void internal_assign_range(I first, I last, is_integer_tag<false> *) {
00893 internal_assign_iterators(first, last);
00894 }
00896 template<class I>
00897 void internal_assign_iterators(I first, I last);
00898
00900 static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
00901
00903 static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
00904
00906 static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
00907
00909 static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
00910
00912 static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
00913
00915 class internal_loop_guide : internal::no_copy {
00916 public:
00917 const pointer array;
00918 const size_type n;
00919 size_type i;
00920 internal_loop_guide(size_type ntrials, void *ptr)
00921 : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00922 void init() { for(; i < n; ++i) new( &array[i] ) T(); }
00923 void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00924 void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00925 void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00926
00927 template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00928 ~internal_loop_guide() {
00929 if(i < n)
00930 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00931 }
00932 };
00933 };
00934
00935 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
00936 #pragma warning (push)
00937 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
00938 #endif
00939 template<typename T, class A>
00940 void concurrent_vector<T, A>::shrink_to_fit() {
00941 internal_segments_table old;
00942 __TBB_TRY {
00943 if( internal_compact( sizeof(T), &old, &destroy_array, ©_array ) )
00944 internal_free_segments( old.table, pointers_per_long_table, old.first_block );
00945 } __TBB_CATCH(...) {
00946 if( old.first_block )
00947 internal_free_segments( old.table, 1, old.first_block );
00948 __TBB_RETHROW();
00949 }
00950 }
00951 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
00952 #pragma warning (pop)
00953 #endif // warning 4701 is back
00954
00955 template<typename T, class A>
00956 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00957
00958 while( k > first_block ) {
00959 --k;
00960 T* array = static_cast<T*>(table[k]);
00961 table[k] = NULL;
00962 if( array > internal::vector_allocation_error_flag )
00963 this->my_allocator.deallocate( array, segment_size(k) );
00964 }
00965 T* array = static_cast<T*>(table[0]);
00966 if( array > internal::vector_allocation_error_flag ) {
00967 __TBB_ASSERT( first_block > 0, NULL );
00968 while(k > 0) table[--k] = NULL;
00969 this->my_allocator.deallocate( array, segment_size(first_block) );
00970 }
00971 }
00972
00973 template<typename T, class A>
00974 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00975 __TBB_ASSERT( index < my_early_size, "index out of bounds" );
00976 size_type j = index;
00977 segment_index_t k = segment_base_index_of( j );
00978 __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
00979
00980 T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segment[k].array));
00981 __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
00982 __TBB_ASSERT( array, "index is being allocated" );
00983 return array[j];
00984 }
00985
00986 template<typename T, class A>
00987 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00988 if( index >= my_early_size )
00989 internal::throw_exception(internal::eid_out_of_range);
00990 size_type j = index;
00991 segment_index_t k = segment_base_index_of( j );
00992 if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
00993 internal::throw_exception(internal::eid_segment_range_error);
00994 void *array = my_segment[k].array;
00995 if( array <= internal::vector_allocation_error_flag )
00996 internal::throw_exception(internal::eid_index_range_error);
00997 return static_cast<T*>(array)[j];
00998 }
00999
01000 template<typename T, class A> template<class I>
01001 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
01002 __TBB_ASSERT(my_early_size == 0, NULL);
01003 size_type n = std::distance(first, last);
01004 if( !n ) return;
01005 internal_reserve(n, sizeof(T), max_size());
01006 my_early_size = n;
01007 segment_index_t k = 0;
01008 size_type sz = segment_size( my_first_block );
01009 while( sz < n ) {
01010 internal_loop_guide loop(sz, my_segment[k].array);
01011 loop.iterate(first);
01012 n -= sz;
01013 if( !k ) k = my_first_block;
01014 else { ++k; sz <<= 1; }
01015 }
01016 internal_loop_guide loop(n, my_segment[k].array);
01017 loop.iterate(first);
01018 }
01019
01020 template<typename T, class A>
01021 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
01022 internal_loop_guide loop(n, begin); loop.init();
01023 }
01024
01025 template<typename T, class A>
01026 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
01027 internal_loop_guide loop(n, begin); loop.init(src);
01028 }
01029
01030 template<typename T, class A>
01031 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
01032 internal_loop_guide loop(n, dst); loop.copy(src);
01033 }
01034
01035 template<typename T, class A>
01036 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
01037 internal_loop_guide loop(n, dst); loop.assign(src);
01038 }
01039
01040 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
01041
01042 #pragma warning (push)
01043 #pragma warning (disable: 4189)
01044 #endif
01045 template<typename T, class A>
01046 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
01047 T* array = static_cast<T*>(begin);
01048 for( size_type j=n; j>0; --j )
01049 array[j-1].~T();
01050 }
01051 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
01052 #pragma warning (pop)
01053 #endif // warning 4189 is back
01054
01055
01056 template<typename T, class A1, class A2>
01057 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
01058
01059 if(a.size() != b.size()) return false;
01060 typename concurrent_vector<T, A1>::const_iterator i(a.begin());
01061 typename concurrent_vector<T, A2>::const_iterator j(b.begin());
01062 for(; i != a.end(); ++i, ++j)
01063 if( !(*i == *j) ) return false;
01064 return true;
01065 }
01066
01067 template<typename T, class A1, class A2>
01068 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01069 { return !(a == b); }
01070
01071 template<typename T, class A1, class A2>
01072 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01073 { return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
01074
01075 template<typename T, class A1, class A2>
01076 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01077 { return b < a; }
01078
01079 template<typename T, class A1, class A2>
01080 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01081 { return !(b < a); }
01082
01083 template<typename T, class A1, class A2>
01084 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01085 { return !(a < b); }
01086
01087 template<typename T, class A>
01088 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
01089 { a.swap( b ); }
01090
01091 }
01092
01093 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
01094 #pragma warning (pop)
01095 #endif // warning 4267 is back
01096
01097 #endif