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