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.