File indexing completed on 2025-01-18 10:12:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB_concurrent_vector_H
0018 #define __TBB_concurrent_vector_H
0019
0020 #define __TBB_concurrent_vector_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022
0023 #include "tbb_stddef.h"
0024 #include "tbb_exception.h"
0025 #include "atomic.h"
0026 #include "cache_aligned_allocator.h"
0027 #include "blocked_range.h"
0028 #include "tbb_machine.h"
0029 #include "tbb_profiling.h"
0030 #include <new>
0031 #include <cstring> // for memset()
0032 #include __TBB_STD_SWAP_HEADER
0033 #include <algorithm>
0034 #include <iterator>
0035
0036 #include "internal/_allocator_traits.h"
0037
0038 #if _MSC_VER==1500 && !__INTEL_COMPILER
0039
0040 #pragma warning( push )
0041 #pragma warning( disable: 4985 )
0042 #endif
0043 #include <limits> /* std::numeric_limits */
0044 #if _MSC_VER==1500 && !__INTEL_COMPILER
0045 #pragma warning( pop )
0046 #endif
0047
0048 #if __TBB_INITIALIZER_LISTS_PRESENT
0049 #include <initializer_list>
0050 #endif
0051
0052 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
0053
0054 #pragma warning (push)
0055 #if defined(_Wp64)
0056 #pragma warning (disable: 4267)
0057 #endif
0058 #pragma warning (disable: 4127)
0059 #endif
0060
0061 namespace tbb {
0062
0063 template<typename T, class A = cache_aligned_allocator<T> >
0064 class concurrent_vector;
0065
0066
0067 namespace internal {
0068
0069 template<typename Container, typename Value>
0070 class vector_iterator;
0071
0072
0073 static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
0074
0075
0076 template<typename T>
0077 void handle_unconstructed_elements(T* array, size_t n_of_elements){
0078 std::memset( static_cast<void*>(array), 0, n_of_elements * sizeof( T ) );
0079 }
0080
0081
0082
0083 class concurrent_vector_base_v3 {
0084 protected:
0085
0086
0087 typedef size_t segment_index_t;
0088 typedef size_t size_type;
0089
0090
0091 enum {
0092
0093 default_initial_segments = 1,
0094
0095 pointers_per_short_table = 3,
0096 pointers_per_long_table = sizeof(segment_index_t) * 8
0097 };
0098
0099 struct segment_not_used {};
0100 struct segment_allocated {};
0101 struct segment_allocation_failed {};
0102
0103 class segment_t;
0104 class segment_value_t {
0105 void* array;
0106 private:
0107
0108 friend class segment_t;
0109 explicit segment_value_t(void* an_array):array(an_array) {}
0110 public:
0111 friend bool operator==(segment_value_t const& lhs, segment_not_used ) { return lhs.array == 0;}
0112 friend bool operator==(segment_value_t const& lhs, segment_allocated) { return lhs.array > internal::vector_allocation_error_flag;}
0113 friend bool operator==(segment_value_t const& lhs, segment_allocation_failed) { return lhs.array == internal::vector_allocation_error_flag;}
0114 template<typename argument_type>
0115 friend bool operator!=(segment_value_t const& lhs, argument_type arg) { return ! (lhs == arg);}
0116
0117 template<typename T>
0118 T* pointer() const { return static_cast<T*>(const_cast<void*>(array)); }
0119 };
0120
0121 friend void enforce_segment_allocated(segment_value_t const& s, internal::exception_id exception = eid_bad_last_alloc){
0122 if(s != segment_allocated()){
0123 internal::throw_exception(exception);
0124 }
0125 }
0126
0127
0128 class segment_t {
0129 atomic<void*> array;
0130 public:
0131 segment_t(){ store<relaxed>(segment_not_used());}
0132
0133
0134
0135 segment_t(segment_t const& rhs ){ array.store<relaxed>(rhs.array.load<relaxed>());}
0136
0137 void swap(segment_t & rhs ){
0138 tbb::internal::swap<relaxed>(array, rhs.array);
0139 }
0140
0141 segment_t& operator=(segment_t const& rhs ){
0142 array.store<relaxed>(rhs.array.load<relaxed>());
0143 return *this;
0144 }
0145
0146 template<memory_semantics M>
0147 segment_value_t load() const { return segment_value_t(array.load<M>());}
0148
0149 template<memory_semantics M>
0150 void store(segment_not_used) {
0151 array.store<M>(0);
0152 }
0153
0154 template<memory_semantics M>
0155 void store(segment_allocation_failed) {
0156 __TBB_ASSERT(load<relaxed>() != segment_allocated(),"transition from \"allocated\" to \"allocation failed\" state looks non-logical");
0157 array.store<M>(internal::vector_allocation_error_flag);
0158 }
0159
0160 template<memory_semantics M>
0161 void store(void* allocated_segment_pointer) __TBB_NOEXCEPT(true) {
0162 __TBB_ASSERT(segment_value_t(allocated_segment_pointer) == segment_allocated(),
0163 "other overloads of store should be used for marking segment as not_used or allocation_failed" );
0164 array.store<M>(allocated_segment_pointer);
0165 }
0166
0167 #if TBB_USE_ASSERT
0168 ~segment_t() {
0169 __TBB_ASSERT(load<relaxed>() != segment_allocated(), "should have been freed by clear" );
0170 }
0171 #endif
0172 };
0173 friend void swap(segment_t & , segment_t & ) __TBB_NOEXCEPT(true);
0174
0175
0176
0177
0178 void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
0179
0180
0181 atomic<size_type> my_first_block;
0182
0183
0184 atomic<size_type> my_early_size;
0185
0186
0187 atomic<segment_t*> my_segment;
0188
0189
0190 segment_t my_storage[pointers_per_short_table];
0191
0192
0193
0194 concurrent_vector_base_v3() {
0195
0196
0197
0198
0199
0200
0201
0202
0203 my_early_size.store<relaxed>(0);
0204 my_first_block.store<relaxed>(0);
0205 my_segment.store<relaxed>(my_storage);
0206 }
0207
0208 __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
0209
0210
0211
0212
0213
0214 static segment_index_t segment_index_of( size_type index ) {
0215 return segment_index_t( __TBB_Log2( index|1 ) );
0216 }
0217
0218 static segment_index_t segment_base( segment_index_t k ) {
0219 return (segment_index_t(1)<<k & ~segment_index_t(1));
0220 }
0221
0222 static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
0223 segment_index_t k = segment_index_of( index );
0224 index -= segment_base(k);
0225 return k;
0226 }
0227
0228 static size_type segment_size( segment_index_t k ) {
0229 return segment_index_t(1)<<k;
0230 }
0231
0232
0233 static bool is_first_element_in_segment(size_type element_index){
0234
0235
0236
0237 __TBB_ASSERT(element_index, "there should be no need to call "
0238 "is_first_element_in_segment for 0th element" );
0239 return is_power_of_two_at_least( element_index, 2 );
0240 }
0241
0242
0243 typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
0244
0245
0246 typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
0247
0248
0249 struct internal_segments_table {
0250 segment_index_t first_block;
0251 segment_t table[pointers_per_long_table];
0252 };
0253
0254 void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
0255 size_type __TBB_EXPORTED_METHOD internal_capacity() const;
0256 void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
0257 size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
0258 void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
0259 segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
0260 void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
0261 void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
0262 void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
0263 internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
0264
0265 void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
0266 void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
0267
0268 void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
0269 internal_array_op1 destroy, internal_array_op2 init );
0270 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 );
0271
0272
0273 void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
0274 private:
0275
0276 class helper;
0277 friend class helper;
0278
0279 template<typename Container, typename Value>
0280 friend class vector_iterator;
0281
0282 };
0283
0284 inline void swap(concurrent_vector_base_v3::segment_t & lhs, concurrent_vector_base_v3::segment_t & rhs) __TBB_NOEXCEPT(true) {
0285 lhs.swap(rhs);
0286 }
0287
0288 typedef concurrent_vector_base_v3 concurrent_vector_base;
0289
0290
0291
0292
0293 template<typename Container, typename Value>
0294 class vector_iterator
0295 {
0296
0297 Container* my_vector;
0298
0299
0300 size_t my_index;
0301
0302
0303
0304 mutable Value* my_item;
0305
0306 template<typename C, typename T>
0307 friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
0308
0309 template<typename C, typename T, typename U>
0310 friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0311
0312 template<typename C, typename T, typename U>
0313 friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0314
0315 template<typename C, typename T, typename U>
0316 friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0317
0318 template<typename C, typename U>
0319 friend class internal::vector_iterator;
0320
0321 #if !__TBB_TEMPLATE_FRIENDS_BROKEN
0322 template<typename T, class A>
0323 friend class tbb::concurrent_vector;
0324 #else
0325 public:
0326 #endif
0327
0328 vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
0329 my_vector(const_cast<Container*>(&vector)),
0330 my_index(index),
0331 my_item(static_cast<Value*>(ptr))
0332 {}
0333
0334 public:
0335
0336 vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
0337
0338 vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
0339 my_vector(other.my_vector),
0340 my_index(other.my_index),
0341 my_item(other.my_item)
0342 {}
0343
0344 vector_iterator& operator=( const vector_iterator<Container,typename Container::value_type>& other )
0345 {
0346 my_vector=other.my_vector;
0347 my_index=other.my_index;
0348 my_item=other.my_item;
0349 return *this;
0350 }
0351
0352 vector_iterator operator+( ptrdiff_t offset ) const {
0353 return vector_iterator( *my_vector, my_index+offset );
0354 }
0355 vector_iterator &operator+=( ptrdiff_t offset ) {
0356 my_index+=offset;
0357 my_item = NULL;
0358 return *this;
0359 }
0360 vector_iterator operator-( ptrdiff_t offset ) const {
0361 return vector_iterator( *my_vector, my_index-offset );
0362 }
0363 vector_iterator &operator-=( ptrdiff_t offset ) {
0364 my_index-=offset;
0365 my_item = NULL;
0366 return *this;
0367 }
0368 Value& operator*() const {
0369 Value* item = my_item;
0370 if( !item ) {
0371 item = my_item = &my_vector->internal_subscript(my_index);
0372 }
0373 __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
0374 return *item;
0375 }
0376 Value& operator[]( ptrdiff_t k ) const {
0377 return my_vector->internal_subscript(my_index+k);
0378 }
0379 Value* operator->() const {return &operator*();}
0380
0381
0382 vector_iterator& operator++() {
0383 size_t element_index = ++my_index;
0384 if( my_item ) {
0385
0386 if( concurrent_vector_base::is_first_element_in_segment(element_index)) {
0387
0388
0389 my_item= NULL;
0390 } else {
0391 ++my_item;
0392 }
0393 }
0394 return *this;
0395 }
0396
0397
0398 vector_iterator& operator--() {
0399 __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
0400 size_t element_index = my_index--;
0401 if( my_item ) {
0402 if(concurrent_vector_base::is_first_element_in_segment(element_index)) {
0403
0404
0405 my_item= NULL;
0406 } else {
0407 --my_item;
0408 }
0409 }
0410 return *this;
0411 }
0412
0413
0414 vector_iterator operator++(int) {
0415 vector_iterator result = *this;
0416 operator++();
0417 return result;
0418 }
0419
0420
0421 vector_iterator operator--(int) {
0422 vector_iterator result = *this;
0423 operator--();
0424 return result;
0425 }
0426
0427
0428
0429 typedef ptrdiff_t difference_type;
0430 typedef Value value_type;
0431 typedef Value* pointer;
0432 typedef Value& reference;
0433 typedef std::random_access_iterator_tag iterator_category;
0434 };
0435
0436 template<typename Container, typename T>
0437 vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
0438 return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
0439 }
0440
0441 template<typename Container, typename T, typename U>
0442 bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0443 return i.my_index==j.my_index && i.my_vector == j.my_vector;
0444 }
0445
0446 template<typename Container, typename T, typename U>
0447 bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0448 return !(i==j);
0449 }
0450
0451 template<typename Container, typename T, typename U>
0452 bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0453 return i.my_index<j.my_index;
0454 }
0455
0456 template<typename Container, typename T, typename U>
0457 bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0458 return j<i;
0459 }
0460
0461 template<typename Container, typename T, typename U>
0462 bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0463 return !(i<j);
0464 }
0465
0466 template<typename Container, typename T, typename U>
0467 bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0468 return !(j<i);
0469 }
0470
0471 template<typename Container, typename T, typename U>
0472 ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0473 return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
0474 }
0475
0476 template<typename T, class A>
0477 class allocator_base {
0478 public:
0479 typedef typename tbb::internal::allocator_rebind<A, T>::type allocator_type;
0480 allocator_type my_allocator;
0481 allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
0482 };
0483
0484 }
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549 template<typename T, class A>
0550 class concurrent_vector: protected internal::allocator_base<T, A>,
0551 private internal::concurrent_vector_base {
0552 private:
0553 template<typename I>
0554 class generic_range_type: public blocked_range<I> {
0555 public:
0556 typedef T value_type;
0557 typedef T& reference;
0558 typedef const T& const_reference;
0559 typedef I iterator;
0560 typedef ptrdiff_t difference_type;
0561 generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
0562 template<typename U>
0563 generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
0564 generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
0565 };
0566
0567 template<typename C, typename U>
0568 friend class internal::vector_iterator;
0569
0570 public:
0571
0572
0573
0574 typedef internal::concurrent_vector_base_v3::size_type size_type;
0575 typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
0576
0577 typedef T value_type;
0578 typedef ptrdiff_t difference_type;
0579 typedef T& reference;
0580 typedef const T& const_reference;
0581 typedef T *pointer;
0582 typedef const T *const_pointer;
0583
0584 typedef internal::vector_iterator<concurrent_vector,T> iterator;
0585 typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
0586
0587 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
0588
0589 typedef std::reverse_iterator<iterator> reverse_iterator;
0590 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
0591 #else
0592
0593 typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
0594 typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
0595 #endif
0596
0597
0598
0599
0600 typedef generic_range_type<iterator> range_type;
0601 typedef generic_range_type<const_iterator> const_range_type;
0602
0603
0604
0605
0606
0607
0608 explicit concurrent_vector(const allocator_type &a = allocator_type())
0609 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0610 {
0611 vector_allocator_ptr = &internal_allocator;
0612 }
0613
0614
0615
0616 #if __TBB_INITIALIZER_LISTS_PRESENT
0617
0618 concurrent_vector(std::initializer_list<T> init_list, const allocator_type &a = allocator_type())
0619 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0620 {
0621 vector_allocator_ptr = &internal_allocator;
0622 __TBB_TRY {
0623 internal_assign_iterators(init_list.begin(), init_list.end());
0624 } __TBB_CATCH(...) {
0625 segment_t *table = my_segment.load<relaxed>();;
0626 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0627 __TBB_RETHROW();
0628 }
0629
0630 }
0631 #endif
0632
0633
0634 concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
0635 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0636 {
0637 vector_allocator_ptr = &internal_allocator;
0638 __TBB_TRY {
0639 internal_copy(vector, sizeof(T), ©_array);
0640 } __TBB_CATCH(...) {
0641 segment_t *table = my_segment.load<relaxed>();
0642 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0643 __TBB_RETHROW();
0644 }
0645 }
0646
0647 #if __TBB_CPP11_RVALUE_REF_PRESENT
0648
0649
0650 concurrent_vector( concurrent_vector&& source)
0651 : internal::allocator_base<T, A>(std::move(source)), internal::concurrent_vector_base()
0652 {
0653 vector_allocator_ptr = &internal_allocator;
0654 concurrent_vector_base_v3::internal_swap(source);
0655 }
0656
0657 concurrent_vector( concurrent_vector&& source, const allocator_type& a)
0658 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0659 {
0660 vector_allocator_ptr = &internal_allocator;
0661
0662
0663 if (a == source.my_allocator) {
0664 concurrent_vector_base_v3::internal_swap(source);
0665 } else {
0666 __TBB_TRY {
0667 internal_copy(source, sizeof(T), &move_array);
0668 } __TBB_CATCH(...) {
0669 segment_t *table = my_segment.load<relaxed>();
0670 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0671 __TBB_RETHROW();
0672 }
0673 }
0674 }
0675
0676 #endif
0677
0678
0679 template<class M>
0680 __TBB_DEPRECATED concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
0681 : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0682 {
0683 vector_allocator_ptr = &internal_allocator;
0684 __TBB_TRY {
0685 internal_copy(vector.internal_vector_base(), sizeof(T), ©_array);
0686 } __TBB_CATCH(...) {
0687 segment_t *table = my_segment.load<relaxed>();
0688 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0689 __TBB_RETHROW();
0690 }
0691 }
0692
0693
0694 explicit concurrent_vector(size_type n)
0695 {
0696 vector_allocator_ptr = &internal_allocator;
0697 __TBB_TRY {
0698 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
0699 } __TBB_CATCH(...) {
0700 segment_t *table = my_segment.load<relaxed>();
0701 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0702 __TBB_RETHROW();
0703 }
0704 }
0705
0706
0707 concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
0708 : internal::allocator_base<T, A>(a)
0709 {
0710 vector_allocator_ptr = &internal_allocator;
0711 __TBB_TRY {
0712 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0713 } __TBB_CATCH(...) {
0714 segment_t *table = my_segment.load<relaxed>();
0715 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0716 __TBB_RETHROW();
0717 }
0718 }
0719
0720
0721 template<class I>
0722 concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
0723 : internal::allocator_base<T, A>(a)
0724 {
0725 vector_allocator_ptr = &internal_allocator;
0726 __TBB_TRY {
0727 internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
0728 } __TBB_CATCH(...) {
0729 segment_t *table = my_segment.load<relaxed>();
0730 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0731 __TBB_RETHROW();
0732 }
0733 }
0734
0735
0736 concurrent_vector& operator=( const concurrent_vector& vector ) {
0737 if( this != &vector )
0738 internal_assign(vector, sizeof(T), &destroy_array, &assign_array, ©_array);
0739 return *this;
0740 }
0741
0742 #if __TBB_CPP11_RVALUE_REF_PRESENT
0743
0744
0745 concurrent_vector& operator=( concurrent_vector&& other ) {
0746 __TBB_ASSERT(this != &other, "Move assignment to itself is prohibited ");
0747 typedef typename tbb::internal::allocator_traits<A>::propagate_on_container_move_assignment pocma_t;
0748 if(pocma_t::value || this->my_allocator == other.my_allocator) {
0749 concurrent_vector trash (std::move(*this));
0750 internal_swap(other);
0751 tbb::internal::allocator_move_assignment(this->my_allocator, other.my_allocator, pocma_t());
0752 } else {
0753 internal_assign(other, sizeof(T), &destroy_array, &move_assign_array, &move_array);
0754 }
0755 return *this;
0756 }
0757 #endif
0758
0759
0760
0761 template<class M>
0762 __TBB_DEPRECATED concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
0763 if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
0764 internal_assign(vector.internal_vector_base(),
0765 sizeof(T), &destroy_array, &assign_array, ©_array);
0766 return *this;
0767 }
0768
0769 #if __TBB_INITIALIZER_LISTS_PRESENT
0770
0771 concurrent_vector& operator=( std::initializer_list<T> init_list ) {
0772 internal_clear(&destroy_array);
0773 internal_assign_iterators(init_list.begin(), init_list.end());
0774 return *this;
0775 }
0776 #endif
0777
0778
0779
0780
0781
0782
0783 iterator grow_by( size_type delta ) {
0784 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size.load());
0785 }
0786
0787
0788
0789 iterator grow_by( size_type delta, const_reference t ) {
0790 return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size.load());
0791 }
0792
0793
0794 template<typename I>
0795 iterator grow_by( I first, I last ) {
0796 typename std::iterator_traits<I>::difference_type delta = std::distance(first, last);
0797 __TBB_ASSERT( delta >= 0, NULL);
0798
0799 return iterator(*this, delta ? internal_grow_by(delta, sizeof(T), ©_range<I>, static_cast<const void*>(&first)) : my_early_size.load());
0800 }
0801
0802 #if __TBB_INITIALIZER_LISTS_PRESENT
0803
0804 iterator grow_by( std::initializer_list<T> init_list ) {
0805 return grow_by( init_list.begin(), init_list.end() );
0806 }
0807 #endif
0808
0809
0810
0811
0812
0813
0814 iterator grow_to_at_least( size_type n ) {
0815 size_type m=0;
0816 if( n ) {
0817 m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
0818 if( m>n ) m=n;
0819 }
0820 return iterator(*this, m);
0821 };
0822
0823
0824
0825 iterator grow_to_at_least( size_type n, const_reference t ) {
0826 size_type m=0;
0827 if( n ) {
0828 m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array_by, &t);
0829 if( m>n ) m=n;
0830 }
0831 return iterator(*this, m);
0832 };
0833
0834
0835
0836 iterator push_back( const_reference item )
0837 {
0838 push_back_helper prolog(*this);
0839 new(prolog.internal_push_back_result()) T(item);
0840 return prolog.return_iterator_and_dismiss();
0841 }
0842
0843 #if __TBB_CPP11_RVALUE_REF_PRESENT
0844
0845
0846 iterator push_back( T&& item )
0847 {
0848 push_back_helper prolog(*this);
0849 new(prolog.internal_push_back_result()) T(std::move(item));
0850 return prolog.return_iterator_and_dismiss();
0851 }
0852 #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0853
0854
0855 template<typename... Args>
0856 iterator emplace_back( Args&&... args )
0857 {
0858 push_back_helper prolog(*this);
0859 new(prolog.internal_push_back_result()) T(std::forward<Args>(args)...);
0860 return prolog.return_iterator_and_dismiss();
0861 }
0862 #endif
0863 #endif
0864
0865
0866
0867 reference operator[]( size_type index ) {
0868 return internal_subscript(index);
0869 }
0870
0871
0872 const_reference operator[]( size_type index ) const {
0873 return internal_subscript(index);
0874 }
0875
0876
0877 reference at( size_type index ) {
0878 return internal_subscript_with_exceptions(index);
0879 }
0880
0881
0882 const_reference at( size_type index ) const {
0883 return internal_subscript_with_exceptions(index);
0884 }
0885
0886
0887 range_type range( size_t grainsize = 1 ) {
0888 return range_type( begin(), end(), grainsize );
0889 }
0890
0891
0892 const_range_type range( size_t grainsize = 1 ) const {
0893 return const_range_type( begin(), end(), grainsize );
0894 }
0895
0896
0897
0898
0899
0900 size_type size() const {
0901 size_type sz = my_early_size, cp = internal_capacity();
0902 return cp < sz ? cp : sz;
0903 }
0904
0905
0906 bool empty() const {return !my_early_size;}
0907
0908
0909 size_type capacity() const {return internal_capacity();}
0910
0911
0912
0913
0914 void reserve( size_type n ) {
0915 if( n )
0916 internal_reserve(n, sizeof(T), max_size());
0917 }
0918
0919
0920 void resize( size_type n ) {
0921 internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
0922 }
0923
0924
0925 void resize( size_type n, const_reference t ) {
0926 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0927 }
0928
0929
0930 void shrink_to_fit();
0931
0932
0933 size_type max_size() const {return (~size_type(0))/sizeof(T);}
0934
0935
0936
0937
0938
0939
0940 iterator begin() {return iterator(*this,0);}
0941
0942 iterator end() {return iterator(*this,size());}
0943
0944 const_iterator begin() const {return const_iterator(*this,0);}
0945
0946 const_iterator end() const {return const_iterator(*this,size());}
0947
0948 const_iterator cbegin() const {return const_iterator(*this,0);}
0949
0950 const_iterator cend() const {return const_iterator(*this,size());}
0951
0952 reverse_iterator rbegin() {return reverse_iterator(end());}
0953
0954 reverse_iterator rend() {return reverse_iterator(begin());}
0955
0956 const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
0957
0958 const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
0959
0960 const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
0961
0962 const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
0963
0964 reference front() {
0965 __TBB_ASSERT( size()>0, NULL);
0966 const segment_value_t& segment_value = my_segment[0].template load<relaxed>();
0967 return (segment_value.template pointer<T>())[0];
0968 }
0969
0970 const_reference front() const {
0971 __TBB_ASSERT( size()>0, NULL);
0972 const segment_value_t& segment_value = my_segment[0].template load<relaxed>();
0973 return (segment_value.template pointer<const T>())[0];
0974 }
0975
0976 reference back() {
0977 __TBB_ASSERT( size()>0, NULL);
0978 return internal_subscript( size()-1 );
0979 }
0980
0981 const_reference back() const {
0982 __TBB_ASSERT( size()>0, NULL);
0983 return internal_subscript( size()-1 );
0984 }
0985
0986 allocator_type get_allocator() const { return this->my_allocator; }
0987
0988
0989 void assign(size_type n, const_reference t) {
0990 clear();
0991 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0992 }
0993
0994
0995 template<class I>
0996 void assign(I first, I last) {
0997 clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
0998 }
0999
1000 #if __TBB_INITIALIZER_LISTS_PRESENT
1001
1002 void assign(std::initializer_list<T> init_list) {
1003 clear(); internal_assign_iterators( init_list.begin(), init_list.end());
1004 }
1005 #endif
1006
1007
1008 void swap(concurrent_vector &vector) {
1009 typedef typename tbb::internal::allocator_traits<A>::propagate_on_container_swap pocs_t;
1010 if( this != &vector && (this->my_allocator == vector.my_allocator || pocs_t::value) ) {
1011 concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
1012 tbb::internal::allocator_swap(this->my_allocator, vector.my_allocator, pocs_t());
1013 }
1014 }
1015
1016
1017
1018 void clear() {
1019 internal_clear(&destroy_array);
1020 }
1021
1022
1023 ~concurrent_vector() {
1024 segment_t *table = my_segment.load<relaxed>();
1025 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
1026
1027 }
1028
1029 const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
1030 private:
1031
1032 static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
1033 return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
1034 }
1035
1036 void internal_free_segments(segment_t table[], segment_index_t k, segment_index_t first_block);
1037
1038
1039 T& internal_subscript( size_type index ) const;
1040
1041
1042 T& internal_subscript_with_exceptions( size_type index ) const;
1043
1044
1045 void internal_assign_n(size_type n, const_pointer p) {
1046 internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
1047 }
1048
1049
1050
1051
1052
1053
1054
1055
1056 template<bool B> class is_integer_tag;
1057
1058
1059 template<class I>
1060 void internal_assign_range(I first, I last, is_integer_tag<true> *) {
1061 internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
1062 }
1063
1064 template<class I>
1065 void internal_assign_range(I first, I last, is_integer_tag<false> *) {
1066 internal_assign_iterators(first, last);
1067 }
1068
1069 template<class I>
1070 void internal_assign_iterators(I first, I last);
1071
1072
1073
1074
1075 static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
1076
1077
1078 static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
1079
1080
1081 static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
1082
1083 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1084
1085 static void __TBB_EXPORTED_FUNC move_array_if_noexcept( void* dst, const void* src, size_type n );
1086 #endif
1087
1088 #if __TBB_CPP11_RVALUE_REF_PRESENT
1089
1090 static void __TBB_EXPORTED_FUNC move_array( void* dst, const void* src, size_type n );
1091
1092
1093 static void __TBB_EXPORTED_FUNC move_assign_array( void* dst, const void* src, size_type n );
1094 #endif
1095
1096 template<typename Iterator>
1097 static void __TBB_EXPORTED_FUNC copy_range( void* dst, const void* p_type_erased_iterator, size_type n );
1098
1099
1100 static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
1101
1102
1103 static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
1104
1105
1106 class internal_loop_guide : internal::no_copy {
1107 public:
1108 const pointer array;
1109 const size_type n;
1110 size_type i;
1111
1112 static const T* as_const_pointer(const void *ptr) { return static_cast<const T *>(ptr); }
1113 static T* as_pointer(const void *src) { return static_cast<T*>(const_cast<void *>(src)); }
1114
1115 internal_loop_guide(size_type ntrials, void *ptr)
1116 : array(as_pointer(ptr)), n(ntrials), i(0) {}
1117 void init() { for(; i < n; ++i) new( &array[i] ) T(); }
1118 void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*as_const_pointer(src)); }
1119 void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(as_const_pointer(src)[i]); }
1120 void assign(const void *src) { for(; i < n; ++i) array[i] = as_const_pointer(src)[i]; }
1121 #if __TBB_CPP11_RVALUE_REF_PRESENT
1122 void move_assign(const void *src) { for(; i < n; ++i) array[i] = std::move(as_pointer(src)[i]); }
1123 void move_construct(const void *src) { for(; i < n; ++i) new( &array[i] ) T( std::move(as_pointer(src)[i]) ); }
1124 #endif
1125 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1126 void move_construct_if_noexcept(const void *src) { for(; i < n; ++i) new( &array[i] ) T( std::move_if_noexcept(as_pointer(src)[i]) ); }
1127 #endif
1128
1129
1130 template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
1131 ~internal_loop_guide() {
1132 if(i < n) {
1133 internal::handle_unconstructed_elements(array+i, n-i);
1134 }
1135 }
1136 };
1137
1138 struct push_back_helper : internal::no_copy{
1139 struct element_construction_guard : internal::no_copy{
1140 pointer element;
1141
1142 element_construction_guard(pointer an_element) : element (an_element){}
1143 void dismiss(){ element = NULL; }
1144 ~element_construction_guard(){
1145 if (element){
1146 internal::handle_unconstructed_elements(element, 1);
1147 }
1148 }
1149 };
1150
1151 concurrent_vector & v;
1152 size_type k;
1153 element_construction_guard g;
1154
1155 push_back_helper(concurrent_vector & vector) :
1156 v(vector),
1157 g (static_cast<T*>(v.internal_push_back(sizeof(T),k)))
1158 {}
1159
1160 pointer internal_push_back_result(){ return g.element;}
1161 iterator return_iterator_and_dismiss(){
1162 pointer ptr = g.element;
1163 g.dismiss();
1164 return iterator(v, k, ptr);
1165 }
1166 };
1167 };
1168
1169 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
1170
1171 template<typename I,
1172 typename T = typename std::iterator_traits<I>::value_type,
1173 typename A = cache_aligned_allocator<T>
1174 > concurrent_vector(I, I, const A& = A())
1175 -> concurrent_vector<T, A>;
1176
1177
1178 template<typename T, typename A1, typename A2>
1179 concurrent_vector(const concurrent_vector<T, A1> &, const A2 &)
1180 -> concurrent_vector<T, A2>;
1181
1182
1183 template<typename T, typename A = cache_aligned_allocator<T>
1184 > concurrent_vector(std::initializer_list<T>, const A& = A())
1185 -> concurrent_vector<T, A>;
1186 #endif
1187
1188 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1189 #pragma warning (push)
1190 #pragma warning (disable: 4701)
1191 #endif
1192 template<typename T, class A>
1193 void concurrent_vector<T, A>::shrink_to_fit() {
1194 internal_segments_table old;
1195 __TBB_TRY {
1196 internal_array_op2 copy_or_move_array =
1197 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1198 &move_array_if_noexcept
1199 #else
1200 ©_array
1201 #endif
1202 ;
1203 if( internal_compact( sizeof(T), &old, &destroy_array, copy_or_move_array ) )
1204 internal_free_segments( old.table, pointers_per_long_table, old.first_block );
1205 } __TBB_CATCH(...) {
1206 if( old.first_block )
1207 internal_free_segments( old.table, 1, old.first_block );
1208 __TBB_RETHROW();
1209 }
1210 }
1211 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1212 #pragma warning (pop)
1213 #endif
1214
1215 template<typename T, class A>
1216 void concurrent_vector<T, A>::internal_free_segments(segment_t table[], segment_index_t k, segment_index_t first_block) {
1217
1218 while( k > first_block ) {
1219 --k;
1220 segment_value_t segment_value = table[k].load<relaxed>();
1221 table[k].store<relaxed>(segment_not_used());
1222 if( segment_value == segment_allocated() )
1223 this->my_allocator.deallocate( (segment_value.pointer<T>()), segment_size(k) );
1224 }
1225 segment_value_t segment_value = table[0].load<relaxed>();
1226 if( segment_value == segment_allocated() ) {
1227 __TBB_ASSERT( first_block > 0, NULL );
1228 while(k > 0) table[--k].store<relaxed>(segment_not_used());
1229 this->my_allocator.deallocate( (segment_value.pointer<T>()), segment_size(first_block) );
1230 }
1231 }
1232
1233 template<typename T, class A>
1234 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
1235
1236 __TBB_ASSERT( index < my_early_size, "index out of bounds" );
1237 size_type j = index;
1238 segment_index_t k = segment_base_index_of( j );
1239 __TBB_ASSERT( my_segment.load<acquire>() != my_storage || k < pointers_per_short_table, "index is being allocated" );
1240
1241
1242
1243
1244 segment_value_t segment_value = my_segment[k].template load<relaxed>();
1245 __TBB_ASSERT( segment_value != segment_allocation_failed(), "the instance is broken by bad allocation. Use at() instead" );
1246 __TBB_ASSERT( segment_value != segment_not_used(), "index is being allocated" );
1247 return (( segment_value.pointer<T>()))[j];
1248 }
1249
1250 template<typename T, class A>
1251 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
1252 if( index >= my_early_size )
1253 internal::throw_exception(internal::eid_out_of_range);
1254 size_type j = index;
1255 segment_index_t k = segment_base_index_of( j );
1256
1257 if( my_segment.load<acquire>() == my_storage && k >= pointers_per_short_table )
1258 internal::throw_exception(internal::eid_segment_range_error);
1259
1260
1261
1262
1263 segment_value_t segment_value = my_segment[k].template load<relaxed>();
1264 enforce_segment_allocated(segment_value, internal::eid_index_range_error);
1265 return (segment_value.pointer<T>())[j];
1266 }
1267
1268 template<typename T, class A> template<class I>
1269 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
1270 __TBB_ASSERT(my_early_size == 0, NULL);
1271 size_type n = std::distance(first, last);
1272 if( !n ) return;
1273 internal_reserve(n, sizeof(T), max_size());
1274 my_early_size = n;
1275 segment_index_t k = 0;
1276
1277 size_type sz = segment_size( my_first_block );
1278 while( sz < n ) {
1279 internal_loop_guide loop(sz, my_segment[k].template load<relaxed>().template pointer<void>());
1280 loop.iterate(first);
1281 n -= sz;
1282 if( !k ) k = my_first_block;
1283 else { ++k; sz <<= 1; }
1284 }
1285 internal_loop_guide loop(n, my_segment[k].template load<relaxed>().template pointer<void>());
1286 loop.iterate(first);
1287 }
1288
1289 template<typename T, class A>
1290 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
1291 internal_loop_guide loop(n, begin); loop.init();
1292 }
1293
1294 template<typename T, class A>
1295 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
1296 internal_loop_guide loop(n, begin); loop.init(src);
1297 }
1298
1299 template<typename T, class A>
1300 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
1301 internal_loop_guide loop(n, dst); loop.copy(src);
1302 }
1303
1304 #if __TBB_CPP11_RVALUE_REF_PRESENT
1305 template<typename T, class A>
1306 void concurrent_vector<T, A>::move_array( void* dst, const void* src, size_type n ) {
1307 internal_loop_guide loop(n, dst); loop.move_construct(src);
1308 }
1309 template<typename T, class A>
1310 void concurrent_vector<T, A>::move_assign_array( void* dst, const void* src, size_type n ) {
1311 internal_loop_guide loop(n, dst); loop.move_assign(src);
1312 }
1313 #endif
1314
1315 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1316 template<typename T, class A>
1317 void concurrent_vector<T, A>::move_array_if_noexcept( void* dst, const void* src, size_type n ) {
1318 internal_loop_guide loop(n, dst); loop.move_construct_if_noexcept(src);
1319 }
1320 #endif
1321
1322 template<typename T, class A>
1323 template<typename I>
1324 void concurrent_vector<T, A>::copy_range( void* dst, const void* p_type_erased_iterator, size_type n ){
1325 internal_loop_guide loop(n, dst);
1326 loop.iterate( *(static_cast<I*>(const_cast<void*>(p_type_erased_iterator))) );
1327 }
1328
1329 template<typename T, class A>
1330 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
1331 internal_loop_guide loop(n, dst); loop.assign(src);
1332 }
1333
1334 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1335
1336 #pragma warning (push)
1337 #pragma warning (disable: 4189)
1338 #endif
1339 template<typename T, class A>
1340 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
1341 T* array = static_cast<T*>(begin);
1342 for( size_type j=n; j>0; --j )
1343 array[j-1].~T();
1344 }
1345 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1346 #pragma warning (pop)
1347 #endif
1348
1349
1350 template<typename T, class A1, class A2>
1351 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
1352
1353
1354 if(a.size() != b.size()) return false;
1355 typename concurrent_vector<T, A1>::const_iterator i(a.begin());
1356 typename concurrent_vector<T, A2>::const_iterator j(b.begin());
1357 for(; i != a.end(); ++i, ++j)
1358 if( !(*i == *j) ) return false;
1359 return true;
1360 }
1361
1362 template<typename T, class A1, class A2>
1363 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1364 { return !(a == b); }
1365
1366 template<typename T, class A1, class A2>
1367 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1368 { return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
1369
1370 template<typename T, class A1, class A2>
1371 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1372 { return b < a; }
1373
1374 template<typename T, class A1, class A2>
1375 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1376 { return !(b < a); }
1377
1378 template<typename T, class A1, class A2>
1379 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1380 { return !(a < b); }
1381
1382 template<typename T, class A>
1383 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
1384 { a.swap( b ); }
1385
1386 }
1387
1388 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1389 #pragma warning (pop)
1390 #endif
1391
1392
1393 #undef __TBB_concurrent_vector_H_include_area
1394 #include "internal/_warning_suppress_disable_notice.h"
1395
1396 #endif