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