concurrent_vector.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# concurrent_vector.h

    00001 /*
    00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
    00003
    00004     The source code contained or described herein and all documents related
    00005     to the source code ("Material") are owned by Intel Corporation or its
    00006     suppliers or licensors.  Title to the Material remains with Intel
    00007     Corporation or its suppliers and licensors.  The Material is protected
    00008     by worldwide copyright laws and treaty provisions.  No part of the
    00009     Material may be used, copied, reproduced, modified, published, uploaded,
    00010     posted, transmitted, distributed, or disclosed in any way without
    00011     Intel's prior express written permission.
    00012
    00013     No license under any patent, copyright, trade secret or other
    00014     intellectual property right is granted to or conferred upon you by
    00015     disclosure or delivery of the Materials, either expressly, by
    00016     implication, inducement, estoppel or otherwise.  Any license under such
    00017     intellectual property rights must be express and approved by Intel in
    00018     writing.
    00019 */
    00020
    00021 #ifndef __TBB_concurrent_vector_H
    00022 #define __TBB_concurrent_vector_H
    00023
    00024 #include "tbb_stddef.h"
    00025 #include "tbb_exception.h"
    00026 #include "atomic.h"
    00027 #include "cache_aligned_allocator.h"
    00028 #include "blocked_range.h"
    00029 #include "tbb_machine.h"
    00030 #include "tbb_profiling.h"
    00031 #include <new>
    00032 #include <cstring>   // for memset()
    00033
    00034 #if !TBB_USE_EXCEPTIONS && _MSC_VER
    00035     // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
    00036     #pragma warning (push)
    00037     #pragma warning (disable: 4530)
    00038 #endif
    00039
    00040 #include <algorithm>
    00041 #include <iterator>
    00042
    00043 #if !TBB_USE_EXCEPTIONS && _MSC_VER
    00044     #pragma warning (pop)
    00045 #endif
    00046
    00047 #if _MSC_VER==1500 && !__INTEL_COMPILER
    00048     // VS2008/VC9 seems to have an issue; limits pull in math.h
    00049     #pragma warning( push )
    00050     #pragma warning( disable: 4985 )
    00051 #endif
    00052 #include <limits> /* std::numeric_limits */
    00053 #if _MSC_VER==1500 && !__INTEL_COMPILER
    00054     #pragma warning( pop )
    00055 #endif
    00056
    00057 #if __TBB_INITIALIZER_LISTS_PRESENT
    00058     #include <initializer_list>
    00059 #endif
    00060
    00061 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
    00062     // Workaround for overzealous compiler warnings in /Wp64 mode
    00063     #pragma warning (push)
    00064     #pragma warning (disable: 4267)
    00065 #endif
    00066
    00067 namespace tbb {
    00068
    00069 template<typename T, class A = cache_aligned_allocator<T> >
    00070 class concurrent_vector;
    00071
    00073 namespace internal {
    00074
    00076     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
    00077
    00079
    00080     class concurrent_vector_base_v3 {
    00081     protected:
    00082
    00083         // Basic types declarations
    00084         typedef size_t segment_index_t;
    00085         typedef size_t size_type;
    00086
    00087         // Using enumerations due to Mac linking problems of static const variables
    00088         enum {
    00089             // Size constants
    00090             default_initial_segments = 1, // 2 initial items
    00092             pointers_per_short_table = 3, // to fit into 8 words of entire structure
    00093             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
    00094         };
    00095
    00096         // Segment pointer. Can be zero-initialized
    00097         struct segment_t {
    00098             void* array;
    00099 #if TBB_USE_ASSERT
    00100             ~segment_t() {
    00101                 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
    00102             }
    00103 #endif /* TBB_USE_ASSERT */
    00104         };
    00105
    00106         // Data fields
    00107
    00109         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
    00110
    00112         atomic<size_type> my_first_block;
    00113
    00115         atomic<size_type> my_early_size;
    00116
    00118         atomic<segment_t*> my_segment;
    00119
    00121         segment_t my_storage[pointers_per_short_table];
    00122
    00123         // Methods
    00124
    00125         concurrent_vector_base_v3() {
    00126             my_early_size = 0;
    00127             my_first_block = 0; // here is not default_initial_segments
    00128             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
    00129                 my_storage[i].array = NULL;
    00130             my_segment = my_storage;
    00131         }
    00132         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
    00133
    00134         static segment_index_t segment_index_of( size_type index ) {
    00135             return segment_index_t( __TBB_Log2( index|1 ) );
    00136         }
    00137
    00138         static segment_index_t segment_base( segment_index_t k ) {
    00139             return (segment_index_t(1)<<k & ~segment_index_t(1));
    00140         }
    00141
    00142         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
    00143             segment_index_t k = segment_index_of( index );
    00144             index -= segment_base(k);
    00145             return k;
    00146         }
    00147
    00148         static size_type segment_size( segment_index_t k ) {
    00149             return segment_index_t(1)<<k; // fake value for k==0
    00150         }
    00151
    00153         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
    00154
    00156         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
    00157
    00159         struct internal_segments_table {
    00160             segment_index_t first_block;
    00161             void* table[pointers_per_long_table];
    00162         };
    00163
    00164         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
    00165         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
    00166         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
    00167         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
    00168         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
    00169         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
    00170         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
    00171         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
    00172         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
    00173                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
    00175         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
    00176         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
    00177
    00178         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
    00179                                                     internal_array_op1 destroy, internal_array_op2 init );
    00180         size_type __TBB_EXPORTED_METHOD internal_grow_to_at_least_with_result( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
    00181
    00183         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
    00184 private:
    00186         class helper;
    00187         friend class helper;
    00188     };
    00189
    00190     typedef concurrent_vector_base_v3 concurrent_vector_base;
    00191
    00193
    00195     template<typename Container, typename Value>
    00196     class vector_iterator
    00197     {
    00199         Container* my_vector;
    00200
    00202         size_t my_index;
    00203
    00205
    00206         mutable Value* my_item;
    00207
    00208         template<typename C, typename T>
    00209         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
    00210
    00211         template<typename C, typename T, typename U>
    00212         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
    00213
    00214         template<typename C, typename T, typename U>
    00215         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
    00216
    00217         template<typename C, typename T, typename U>
    00218         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
    00219
    00220         template<typename C, typename U>
    00221         friend class internal::vector_iterator;
    00222
    00223 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
    00224         template<typename T, class A>
    00225         friend class tbb::concurrent_vector;
    00226 #else
    00227 public: // workaround for MSVC
    00228 #endif
    00229
    00230         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
    00231             my_vector(const_cast<Container*>(&vector)),
    00232             my_index(index),
    00233             my_item(static_cast<Value*>(ptr))
    00234         {}
    00235
    00236     public:
    00238         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
    00239
    00240         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
    00241             my_vector(other.my_vector),
    00242             my_index(other.my_index),
    00243             my_item(other.my_item)
    00244         {}
    00245
    00246         vector_iterator operator+( ptrdiff_t offset ) const {
    00247             return vector_iterator( *my_vector, my_index+offset );
    00248         }
    00249         vector_iterator &operator+=( ptrdiff_t offset ) {
    00250             my_index+=offset;
    00251             my_item = NULL;
    00252             return *this;
    00253         }
    00254         vector_iterator operator-( ptrdiff_t offset ) const {
    00255             return vector_iterator( *my_vector, my_index-offset );
    00256         }
    00257         vector_iterator &operator-=( ptrdiff_t offset ) {
    00258             my_index-=offset;
    00259             my_item = NULL;
    00260             return *this;
    00261         }
    00262         Value& operator*() const {
    00263             Value* item = my_item;
    00264             if( !item ) {
    00265                 item = my_item = &my_vector->internal_subscript(my_index);
    00266             }
    00267             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
    00268             return *item;
    00269         }
    00270         Value& operator[]( ptrdiff_t k ) const {
    00271             return my_vector->internal_subscript(my_index+k);
    00272         }
    00273         Value* operator->() const {return &operator*();}
    00274
    00276         vector_iterator& operator++() {
    00277             size_t k = ++my_index;
    00278             if( my_item ) {
    00279                 // Following test uses 2's-complement wizardry
    00280                 if( (k& (k-2))==0 ) {
    00281                     // k is a power of two that is at least k-2
    00282                     my_item= NULL;
    00283                 } else {
    00284                     ++my_item;
    00285                 }
    00286             }
    00287             return *this;
    00288         }
    00289
    00291         vector_iterator& operator--() {
    00292             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
    00293             size_t k = my_index--;
    00294             if( my_item ) {
    00295                 // Following test uses 2's-complement wizardry
    00296                 if( (k& (k-2))==0 ) {
    00297                     // k is a power of two that is at least k-2
    00298                     my_item= NULL;
    00299                 } else {
    00300                     --my_item;
    00301                 }
    00302             }
    00303             return *this;
    00304         }
    00305
    00307         vector_iterator operator++(int) {
    00308             vector_iterator result = *this;
    00309             operator++();
    00310             return result;
    00311         }
    00312
    00314         vector_iterator operator--(int) {
    00315             vector_iterator result = *this;
    00316             operator--();
    00317             return result;
    00318         }
    00319
    00320         // STL support
    00321
    00322         typedef ptrdiff_t difference_type;
    00323         typedef Value value_type;
    00324         typedef Value* pointer;
    00325         typedef Value& reference;
    00326         typedef std::random_access_iterator_tag iterator_category;
    00327     };
    00328
    00329     template<typename Container, typename T>
    00330     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
    00331         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
    00332     }
    00333
    00334     template<typename Container, typename T, typename U>
    00335     bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00336         return i.my_index==j.my_index && i.my_vector == j.my_vector;
    00337     }
    00338
    00339     template<typename Container, typename T, typename U>
    00340     bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00341         return !(i==j);
    00342     }
    00343
    00344     template<typename Container, typename T, typename U>
    00345     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00346         return i.my_index<j.my_index;
    00347     }
    00348
    00349     template<typename Container, typename T, typename U>
    00350     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00351         return j<i;
    00352     }
    00353
    00354     template<typename Container, typename T, typename U>
    00355     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00356         return !(i<j);
    00357     }
    00358
    00359     template<typename Container, typename T, typename U>
    00360     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00361         return !(j<i);
    00362     }
    00363
    00364     template<typename Container, typename T, typename U>
    00365     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00366         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
    00367     }
    00368
    00369     template<typename T, class A>
    00370     class allocator_base {
    00371     public:
    00372         typedef typename A::template
    00373             rebind<T>::other allocator_type;
    00374         allocator_type my_allocator;
    00375
    00376         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
    00377     };
    00378
    00379 } // namespace internal
    00381
    00383
    00444 template<typename T, class A>
    00445 class concurrent_vector: protected internal::allocator_base<T, A>,
    00446                          private internal::concurrent_vector_base {
    00447 private:
    00448     template<typename I>
    00449     class generic_range_type: public blocked_range<I> {
    00450     public:
    00451         typedef T value_type;
    00452         typedef T& reference;
    00453         typedef const T& const_reference;
    00454         typedef I iterator;
    00455         typedef ptrdiff_t difference_type;
    00456         generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
    00457         template<typename U>
    00458         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
    00459         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
    00460     };
    00461
    00462     template<typename C, typename U>
    00463     friend class internal::vector_iterator;
    00464 public:
    00465     //------------------------------------------------------------------------
    00466     // STL compatible types
    00467     //------------------------------------------------------------------------
    00468     typedef internal::concurrent_vector_base_v3::size_type size_type;
    00469     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
    00470
    00471     typedef T value_type;
    00472     typedef ptrdiff_t difference_type;
    00473     typedef T& reference;
    00474     typedef const T& const_reference;
    00475     typedef T *pointer;
    00476     typedef const T *const_pointer;
    00477
    00478     typedef internal::vector_iterator<concurrent_vector,T> iterator;
    00479     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
    00480
    00481 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
    00482     // Assume ISO standard definition of std::reverse_iterator
    00483     typedef std::reverse_iterator<iterator> reverse_iterator;
    00484     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    00485 #else
    00486     // Use non-standard std::reverse_iterator
    00487     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
    00488     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
    00489 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
    00490
    00491     //------------------------------------------------------------------------
    00492     // Parallel algorithm support
    00493     //------------------------------------------------------------------------
    00494     typedef generic_range_type<iterator> range_type;
    00495     typedef generic_range_type<const_iterator> const_range_type;
    00496
    00497     //------------------------------------------------------------------------
    00498     // STL compatible constructors & destructors
    00499     //------------------------------------------------------------------------
    00500
    00502     explicit concurrent_vector(const allocator_type &a = allocator_type())
    00503         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00504     {
    00505         vector_allocator_ptr = &internal_allocator;
    00506     }
    00507
    00508 #if __TBB_INITIALIZER_LISTS_PRESENT
    00510     concurrent_vector(std::initializer_list<T> init_list, const allocator_type &a = allocator_type())
    00511         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00512     {
    00513         vector_allocator_ptr = &internal_allocator;
    00514         __TBB_TRY {
    00515             internal_assign_iterators(init_list.begin(), init_list.end());
    00516         } __TBB_CATCH(...) {
    00517             segment_t *table = my_segment;
    00518             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00519             __TBB_RETHROW();
    00520         }
    00521
    00522     }
    00523 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
    00524
    00526     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
    00527         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00528     {
    00529         vector_allocator_ptr = &internal_allocator;
    00530         __TBB_TRY {
    00531             internal_copy(vector, sizeof(T), &copy_array);
    00532         } __TBB_CATCH(...) {
    00533             segment_t *table = my_segment;
    00534             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00535             __TBB_RETHROW();
    00536         }
    00537     }
    00538
    00540     template<class M>
    00541     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
    00542         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00543     {
    00544         vector_allocator_ptr = &internal_allocator;
    00545         __TBB_TRY {
    00546             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
    00547         } __TBB_CATCH(...) {
    00548             segment_t *table = my_segment;
    00549             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00550             __TBB_RETHROW();
    00551         }
    00552     }
    00553
    00555     explicit concurrent_vector(size_type n)
    00556     {
    00557         vector_allocator_ptr = &internal_allocator;
    00558         __TBB_TRY {
    00559             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
    00560         } __TBB_CATCH(...) {
    00561             segment_t *table = my_segment;
    00562             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00563             __TBB_RETHROW();
    00564         }
    00565     }
    00566
    00568     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
    00569         : internal::allocator_base<T, A>(a)
    00570     {
    00571         vector_allocator_ptr = &internal_allocator;
    00572         __TBB_TRY {
    00573             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00574         } __TBB_CATCH(...) {
    00575             segment_t *table = my_segment;
    00576             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00577             __TBB_RETHROW();
    00578         }
    00579     }
    00580
    00582     template<class I>
    00583     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
    00584         : internal::allocator_base<T, A>(a)
    00585     {
    00586         vector_allocator_ptr = &internal_allocator;
    00587         __TBB_TRY {
    00588             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
    00589         } __TBB_CATCH(...) {
    00590             segment_t *table = my_segment;
    00591             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00592             __TBB_RETHROW();
    00593         }
    00594     }
    00595
    00597     concurrent_vector& operator=( const concurrent_vector& vector ) {
    00598         if( this != &vector )
    00599             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
    00600         return *this;
    00601     }
    00602
    00603     //TODO: add an template assignment operator? (i.e. with different element type)
    00604
    00606     template<class M>
    00607     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
    00608         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
    00609             internal_assign(vector.internal_vector_base(),
    00610                 sizeof(T), &destroy_array, &assign_array, &copy_array);
    00611         return *this;
    00612     }
    00613
    00614 #if __TBB_INITIALIZER_LISTS_PRESENT
    00616     concurrent_vector& operator=( const std::initializer_list<T> & init_list) {
    00617         internal_clear(&destroy_array);
    00618         internal_assign_iterators(init_list.begin(), init_list.end());
    00619         return *this;
    00620     }
    00621 #endif //#if __TBB_INITIALIZER_LISTS_PRESENT
    00622
    00623     //------------------------------------------------------------------------
    00624     // Concurrent operations
    00625     //------------------------------------------------------------------------
    00626     //TODO: consider adding overload of grow_by accepting range of iterators:  grow_by(iterator,iterator)
    00627     //TODO: consider adding overload of grow_by accepting initializer_list:  grow_by(std::initializer_list<T>), as a analogy to std::vector::insert(initializer_list)
    00629 #if TBB_DEPRECATED
    00630
    00631     size_type grow_by( size_type delta ) {
    00632         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
    00633     }
    00634 #else
    00635
    00636     iterator grow_by( size_type delta ) {
    00637         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
    00638     }
    00639 #endif
    00640
    00642 #if TBB_DEPRECATED
    00643
    00644     size_type grow_by( size_type delta, const_reference t ) {
    00645         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
    00646     }
    00647 #else
    00648
    00649     iterator grow_by( size_type delta, const_reference t ) {
    00650         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
    00651     }
    00652 #endif
    00653
    00655 #if TBB_DEPRECATED
    00656
    00658     void grow_to_at_least( size_type n ) {
    00659         if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
    00660     };
    00661 #else
    00662
    00666     iterator grow_to_at_least( size_type n ) {
    00667         size_type m=0;
    00668         if( n ) {
    00669             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
    00670             if( m>n ) m=n;
    00671         }
    00672         return iterator(*this, m);
    00673     };
    00674 #endif
    00675
    00677 #if TBB_DEPRECATED
    00678     size_type push_back( const_reference item )
    00679 #else
    00680
    00681     iterator push_back( const_reference item )
    00682 #endif
    00683     {
    00684         size_type k;
    00685         void *ptr = internal_push_back(sizeof(T),k);
    00686         internal_loop_guide loop(1, ptr);
    00687         loop.init(&item);
    00688 #if TBB_DEPRECATED
    00689         return k;
    00690 #else
    00691         return iterator(*this, k, ptr);
    00692 #endif
    00693     }
    00694
    00696
    00698     reference operator[]( size_type index ) {
    00699         return internal_subscript(index);
    00700     }
    00701
    00703     const_reference operator[]( size_type index ) const {
    00704         return internal_subscript(index);
    00705     }
    00706
    00708     reference at( size_type index ) {
    00709         return internal_subscript_with_exceptions(index);
    00710     }
    00711
    00713     const_reference at( size_type index ) const {
    00714         return internal_subscript_with_exceptions(index);
    00715     }
    00716
    00718     range_type range( size_t grainsize = 1 ) {
    00719         return range_type( begin(), end(), grainsize );
    00720     }
    00721
    00723     const_range_type range( size_t grainsize = 1 ) const {
    00724         return const_range_type( begin(), end(), grainsize );
    00725     }
    00726
    00727     //------------------------------------------------------------------------
    00728     // Capacity
    00729     //------------------------------------------------------------------------
    00731     size_type size() const {
    00732         size_type sz = my_early_size, cp = internal_capacity();
    00733         return cp < sz ? cp : sz;
    00734     }
    00735
    00737     bool empty() const {return !my_early_size;}
    00738
    00740     size_type capacity() const {return internal_capacity();}
    00741
    00743
    00745     void reserve( size_type n ) {
    00746         if( n )
    00747             internal_reserve(n, sizeof(T), max_size());
    00748     }
    00749
    00751     void resize( size_type n ) {
    00752         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
    00753     }
    00754
    00756     void resize( size_type n, const_reference t ) {
    00757         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00758     }
    00759
    00760 #if TBB_DEPRECATED
    00762     void compact() {shrink_to_fit();}
    00763 #endif /* TBB_DEPRECATED */
    00764
    00766     void shrink_to_fit();
    00767
    00769     size_type max_size() const {return (~size_type(0))/sizeof(T);}
    00770
    00771     //------------------------------------------------------------------------
    00772     // STL support
    00773     //------------------------------------------------------------------------
    00774
    00776     iterator begin() {return iterator(*this,0);}
    00778     iterator end() {return iterator(*this,size());}
    00780     const_iterator begin() const {return const_iterator(*this,0);}
    00782     const_iterator end() const {return const_iterator(*this,size());}
    00784     const_iterator cbegin() const {return const_iterator(*this,0);}
    00786     const_iterator cend() const {return const_iterator(*this,size());}
    00788     reverse_iterator rbegin() {return reverse_iterator(end());}
    00790     reverse_iterator rend() {return reverse_iterator(begin());}
    00792     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
    00794     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
    00796     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
    00798     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
    00800     reference front() {
    00801         __TBB_ASSERT( size()>0, NULL);
    00802         return static_cast<T*>(my_segment[0].array)[0];
    00803     }
    00805     const_reference front() const {
    00806         __TBB_ASSERT( size()>0, NULL);
    00807         return static_cast<const T*>(my_segment[0].array)[0];
    00808     }
    00810     reference back() {
    00811         __TBB_ASSERT( size()>0, NULL);
    00812         return internal_subscript( size()-1 );
    00813     }
    00815     const_reference back() const {
    00816         __TBB_ASSERT( size()>0, NULL);
    00817         return internal_subscript( size()-1 );
    00818     }
    00820     allocator_type get_allocator() const { return this->my_allocator; }
    00821
    00823     void assign(size_type n, const_reference t) {
    00824         clear();
    00825         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00826     }
    00827
    00829     template<class I>
    00830     void assign(I first, I last) {
    00831         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
    00832     }
    00833
    00834 #if __TBB_INITIALIZER_LISTS_PRESENT
    00836     void assign(std::initializer_list<T> init_list) {
    00837         clear(); internal_assign_iterators( init_list.begin(), init_list.end());
    00838     }
    00839 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
    00840
    00842     void swap(concurrent_vector &vector) {
    00843         if( this != &vector ) {
    00844             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
    00845             std::swap(this->my_allocator, vector.my_allocator);
    00846         }
    00847     }
    00848
    00850
    00851     void clear() {
    00852         internal_clear(&destroy_array);
    00853     }
    00854
    00856     ~concurrent_vector() {
    00857         segment_t *table = my_segment;
    00858         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00859         // base class destructor call should be then
    00860     }
    00861
    00862     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
    00863 private:
    00865     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
    00866         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
    00867     }
    00869     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
    00870
    00872     T& internal_subscript( size_type index ) const;
    00873
    00875     T& internal_subscript_with_exceptions( size_type index ) const;
    00876
    00878     void internal_assign_n(size_type n, const_pointer p) {
    00879         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
    00880     }
    00881
    00883     template<bool B> class is_integer_tag;
    00884
    00886     template<class I>
    00887     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
    00888         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
    00889     }
    00891     template<class I>
    00892     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
    00893         internal_assign_iterators(first, last);
    00894     }
    00896     template<class I>
    00897     void internal_assign_iterators(I first, I last);
    00898
    00900     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
    00901
    00903     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
    00904
    00906     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
    00907
    00909     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
    00910
    00912     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
    00913
    00915     class internal_loop_guide : internal::no_copy {
    00916     public:
    00917         const pointer array;
    00918         const size_type n;
    00919         size_type i;
    00920         internal_loop_guide(size_type ntrials, void *ptr)
    00921             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
    00922         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
    00923         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
    00924         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
    00925         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
    00926         //TODO: rename to construct_range
    00927         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
    00928         ~internal_loop_guide() {
    00929             if(i < n) // if exception raised, do zeroing on the rest of items
    00930                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
    00931         }
    00932     };
    00933 };
    00934
    00935 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    00936 #pragma warning (push)
    00937 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
    00938 #endif
    00939 template<typename T, class A>
    00940 void concurrent_vector<T, A>::shrink_to_fit() {
    00941     internal_segments_table old;
    00942     __TBB_TRY {
    00943         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
    00944             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
    00945     } __TBB_CATCH(...) {
    00946         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
    00947             internal_free_segments( old.table, 1, old.first_block );
    00948         __TBB_RETHROW();
    00949     }
    00950 }
    00951 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    00952 #pragma warning (pop)
    00953 #endif // warning 4701 is back
    00954
    00955 template<typename T, class A>
    00956 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
    00957     // Free the arrays
    00958     while( k > first_block ) {
    00959         --k;
    00960         T* array = static_cast<T*>(table[k]);
    00961         table[k] = NULL;
    00962         if( array > internal::vector_allocation_error_flag ) // check for correct segment pointer
    00963             this->my_allocator.deallocate( array, segment_size(k) );
    00964     }
    00965     T* array = static_cast<T*>(table[0]);
    00966     if( array > internal::vector_allocation_error_flag ) {
    00967         __TBB_ASSERT( first_block > 0, NULL );
    00968         while(k > 0) table[--k] = NULL;
    00969         this->my_allocator.deallocate( array, segment_size(first_block) );
    00970     }
    00971 }
    00972
    00973 template<typename T, class A>
    00974 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
    00975     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
    00976     size_type j = index;
    00977     segment_index_t k = segment_base_index_of( j );
    00978     __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
    00979     // no need in __TBB_load_with_acquire since thread works in own space or gets
    00980     T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segment[k].array));
    00981     __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
    00982     __TBB_ASSERT( array, "index is being allocated" );
    00983     return array[j];
    00984 }
    00985
    00986 template<typename T, class A>
    00987 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
    00988     if( index >= my_early_size )
    00989         internal::throw_exception(internal::eid_out_of_range); // throw std::out_of_range
    00990     size_type j = index;
    00991     segment_index_t k = segment_base_index_of( j );
    00992     if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
    00993         internal::throw_exception(internal::eid_segment_range_error); // throw std::range_error
    00994     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
    00995     if( array <= internal::vector_allocation_error_flag ) // check for correct segment pointer
    00996         internal::throw_exception(internal::eid_index_range_error); // throw std::range_error
    00997     return static_cast<T*>(array)[j];
    00998 }
    00999
    01000 template<typename T, class A> template<class I>
    01001 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
    01002     __TBB_ASSERT(my_early_size == 0, NULL);
    01003     size_type n = std::distance(first, last);
    01004     if( !n ) return;
    01005     internal_reserve(n, sizeof(T), max_size());
    01006     my_early_size = n;
    01007     segment_index_t k = 0;
    01008     size_type sz = segment_size( my_first_block );
    01009     while( sz < n ) {
    01010         internal_loop_guide loop(sz, my_segment[k].array);
    01011         loop.iterate(first);
    01012         n -= sz;
    01013         if( !k ) k = my_first_block;
    01014         else { ++k; sz <<= 1; }
    01015     }
    01016     internal_loop_guide loop(n, my_segment[k].array);
    01017     loop.iterate(first);
    01018 }
    01019
    01020 template<typename T, class A>
    01021 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
    01022     internal_loop_guide loop(n, begin); loop.init();
    01023 }
    01024
    01025 template<typename T, class A>
    01026 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
    01027     internal_loop_guide loop(n, begin); loop.init(src);
    01028 }
    01029
    01030 template<typename T, class A>
    01031 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
    01032     internal_loop_guide loop(n, dst); loop.copy(src);
    01033 }
    01034
    01035 template<typename T, class A>
    01036 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
    01037     internal_loop_guide loop(n, dst); loop.assign(src);
    01038 }
    01039
    01040 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    01041     // Workaround for overzealous compiler warning
    01042     #pragma warning (push)
    01043     #pragma warning (disable: 4189)
    01044 #endif
    01045 template<typename T, class A>
    01046 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
    01047     T* array = static_cast<T*>(begin);
    01048     for( size_type j=n; j>0; --j )
    01049         array[j-1].~T(); // destructors are supposed to not throw any exceptions
    01050 }
    01051 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    01052     #pragma warning (pop)
    01053 #endif // warning 4189 is back
    01054
    01055 // concurrent_vector's template functions
    01056 template<typename T, class A1, class A2>
    01057 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
    01058     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
    01059     if(a.size() != b.size()) return false;
    01060     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
    01061     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
    01062     for(; i != a.end(); ++i, ++j)
    01063         if( !(*i == *j) ) return false;
    01064     return true;
    01065 }
    01066
    01067 template<typename T, class A1, class A2>
    01068 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01069 {    return !(a == b); }
    01070
    01071 template<typename T, class A1, class A2>
    01072 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01073 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
    01074
    01075 template<typename T, class A1, class A2>
    01076 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01077 {    return b < a; }
    01078
    01079 template<typename T, class A1, class A2>
    01080 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01081 {    return !(b < a); }
    01082
    01083 template<typename T, class A1, class A2>
    01084 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01085 {    return !(a < b); }
    01086
    01087 template<typename T, class A>
    01088 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
    01089 {    a.swap( b ); }
    01090
    01091 } // namespace tbb
    01092
    01093 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
    01094     #pragma warning (pop)
    01095 #endif // warning 4267 is back
    01096
    01097 #endif /* __TBB_concurrent_vector_H */

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.