concurrent_vector.h

00001 /*
00002     Copyright 2005-2009 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 <algorithm>
00026 #include <iterator>
00027 #include <new>
00028 #include <cstring>
00029 #include "atomic.h"
00030 #include "cache_aligned_allocator.h"
00031 #include "blocked_range.h"
00032 
00033 #include "tbb_machine.h"
00034 
00035 #if _MSC_VER==1500 && !__INTEL_COMPILER
00036     // VS2008/VC9 seems to have an issue; limits pull in math.h
00037     #pragma warning( push )
00038     #pragma warning( disable: 4985 )
00039 #endif
00040 #include <limits> /* std::numeric_limits */
00041 #if _MSC_VER==1500 && !__INTEL_COMPILER
00042     #pragma warning( pop )
00043 #endif
00044 
00045 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
00046     // Workaround for overzealous compiler warnings in /Wp64 mode
00047     #pragma warning (push)
00048     #pragma warning (disable: 4267)
00049 #endif
00050 
00051 namespace tbb {
00052 
00053 template<typename T, class A = cache_aligned_allocator<T> >
00054 class concurrent_vector;
00055 
00056 
00058 namespace internal {
00059 
00061     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
00063     void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src );
00064 
00066 
00067     class concurrent_vector_base_v3 {
00068     protected:
00069 
00070         // Basic types declarations
00071         typedef size_t segment_index_t;
00072         typedef size_t size_type;
00073 
00074         // Using enumerations due to Mac linking problems of static const variables
00075         enum {
00076             // Size constants
00077             default_initial_segments = 1, // 2 initial items
00079             pointers_per_short_table = 3, // to fit into 8 words of entire structure
00080             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
00081         };
00082 
00083         // Segment pointer. Can be zero-initialized
00084         struct segment_t {
00085             void* array;
00086 #if TBB_USE_ASSERT
00087             ~segment_t() {
00088                 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
00089             }
00090 #endif /* TBB_USE_ASSERT */
00091         };
00092  
00093         // Data fields
00094 
00096         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00097 
00099         atomic<size_type> my_first_block;
00100 
00102         atomic<size_type> my_early_size;
00103 
00105         atomic<segment_t*> my_segment;
00106 
00108         segment_t my_storage[pointers_per_short_table];
00109 
00110         // Methods
00111 
00112         concurrent_vector_base_v3() {
00113             my_early_size = 0;
00114             my_first_block = 0; // here is not default_initial_segments
00115             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00116                 my_storage[i].array = NULL;
00117             my_segment = my_storage;
00118         }
00119         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
00120 
00121         static segment_index_t segment_index_of( size_type index ) {
00122             return segment_index_t( __TBB_Log2( index|1 ) );
00123         }
00124 
00125         static segment_index_t segment_base( segment_index_t k ) {
00126             return (segment_index_t(1)<<k & ~segment_index_t(1));
00127         }
00128 
00129         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00130             segment_index_t k = segment_index_of( index );
00131             index -= segment_base(k);
00132             return k;
00133         }
00134 
00135         static size_type segment_size( segment_index_t k ) {
00136             return segment_index_t(1)<<k; // fake value for k==0
00137         }
00138 
00140         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
00141 
00143         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
00144 
00146         struct internal_segments_table {
00147             segment_index_t first_block;
00148             void* table[pointers_per_long_table];
00149         };
00150 
00151         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
00152         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
00153         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00154         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00155         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
00156         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
00157         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00158         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00159         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00160                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00161         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
00162         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
00163 
00164         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
00165                                                     internal_array_op1 destroy, internal_array_op2 init );
00166         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 );
00167 
00169         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00170 private:
00172         class helper;
00173         friend class helper;
00174     };
00175     
00176     typedef concurrent_vector_base_v3 concurrent_vector_base;
00177 
00179 
00181     template<typename Container, typename Value>
00182     class vector_iterator 
00183     {
00185         Container* my_vector;
00186 
00188         size_t my_index;
00189 
00191 
00192         mutable Value* my_item;
00193 
00194         template<typename C, typename T>
00195         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00196 
00197         template<typename C, typename T, typename U>
00198         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00199 
00200         template<typename C, typename T, typename U>
00201         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00202 
00203         template<typename C, typename T, typename U>
00204         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00205     
00206         template<typename C, typename U>
00207         friend class internal::vector_iterator;
00208 
00209 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00210         template<typename T, class A>
00211         friend class tbb::concurrent_vector;
00212 #else
00213 public: // workaround for MSVC
00214 #endif 
00215 
00216         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) : 
00217             my_vector(const_cast<Container*>(&vector)), 
00218             my_index(index), 
00219             my_item(static_cast<Value*>(ptr))
00220         {}
00221 
00222     public:
00224         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00225 
00226         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00227             my_vector(other.my_vector),
00228             my_index(other.my_index),
00229             my_item(other.my_item)
00230         {}
00231 
00232         vector_iterator operator+( ptrdiff_t offset ) const {
00233             return vector_iterator( *my_vector, my_index+offset );
00234         }
00235         vector_iterator &operator+=( ptrdiff_t offset ) {
00236             my_index+=offset;
00237             my_item = NULL;
00238             return *this;
00239         }
00240         vector_iterator operator-( ptrdiff_t offset ) const {
00241             return vector_iterator( *my_vector, my_index-offset );
00242         }
00243         vector_iterator &operator-=( ptrdiff_t offset ) {
00244             my_index-=offset;
00245             my_item = NULL;
00246             return *this;
00247         }
00248         Value& operator*() const {
00249             Value* item = my_item;
00250             if( !item ) {
00251                 item = my_item = &my_vector->internal_subscript(my_index);
00252             }
00253             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00254             return *item;
00255         }
00256         Value& operator[]( ptrdiff_t k ) const {
00257             return my_vector->internal_subscript(my_index+k);
00258         }
00259         Value* operator->() const {return &operator*();}
00260 
00262         vector_iterator& operator++() {
00263             size_t k = ++my_index;
00264             if( my_item ) {
00265                 // Following test uses 2's-complement wizardry
00266                 if( (k& (k-2))==0 ) {
00267                     // k is a power of two that is at least k-2
00268                     my_item= NULL;
00269                 } else {
00270                     ++my_item;
00271                 }
00272             }
00273             return *this;
00274         }
00275 
00277         vector_iterator& operator--() {
00278             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" ); 
00279             size_t k = my_index--;
00280             if( my_item ) {
00281                 // Following test uses 2's-complement wizardry
00282                 if( (k& (k-2))==0 ) {
00283                     // k is a power of two that is at least k-2  
00284                     my_item= NULL;
00285                 } else {
00286                     --my_item;
00287                 }
00288             }
00289             return *this;
00290         }
00291 
00293         vector_iterator operator++(int) {
00294             vector_iterator result = *this;
00295             operator++();
00296             return result;
00297         }
00298 
00300         vector_iterator operator--(int) {
00301             vector_iterator result = *this;
00302             operator--();
00303             return result;
00304         }
00305 
00306         // STL support
00307 
00308         typedef ptrdiff_t difference_type;
00309         typedef Value value_type;
00310         typedef Value* pointer;
00311         typedef Value& reference;
00312         typedef std::random_access_iterator_tag iterator_category;
00313     };
00314 
00315     template<typename Container, typename T>
00316     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00317         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
00318     }
00319 
00320     template<typename Container, typename T, typename U>
00321     bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00322         return i.my_index==j.my_index && i.my_vector == j.my_vector;
00323     }
00324 
00325     template<typename Container, typename T, typename U>
00326     bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00327         return !(i==j);
00328     }
00329 
00330     template<typename Container, typename T, typename U>
00331     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00332         return i.my_index<j.my_index;
00333     }
00334 
00335     template<typename Container, typename T, typename U>
00336     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00337         return j<i;
00338     }
00339 
00340     template<typename Container, typename T, typename U>
00341     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00342         return !(i<j);
00343     }
00344 
00345     template<typename Container, typename T, typename U>
00346     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00347         return !(j<i);
00348     }
00349 
00350     template<typename Container, typename T, typename U>
00351     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00352         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00353     }
00354 
00355     template<typename T, class A>
00356     class allocator_base {
00357     public:
00358         typedef typename A::template
00359             rebind<T>::other allocator_type;
00360         allocator_type my_allocator;
00361 
00362         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00363     };
00364 
00365 } // namespace internal
00367 
00369 
00430 template<typename T, class A>
00431 class concurrent_vector: protected internal::allocator_base<T, A>,
00432                          private internal::concurrent_vector_base {
00433 private:
00434     template<typename I>
00435     class generic_range_type: public blocked_range<I> {
00436     public:
00437         typedef T value_type;
00438         typedef T& reference;
00439         typedef const T& const_reference;
00440         typedef I iterator;
00441         typedef ptrdiff_t difference_type;
00442         generic_range_type( I begin_, I end_, size_t grainsize = 1) : blocked_range<I>(begin_,end_,grainsize) {} 
00443         template<typename U>
00444         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {} 
00445         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00446     };
00447 
00448     template<typename C, typename U>
00449     friend class internal::vector_iterator;
00450 public:
00451     //------------------------------------------------------------------------
00452     // STL compatible types
00453     //------------------------------------------------------------------------
00454     typedef internal::concurrent_vector_base_v3::size_type size_type;
00455     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00456 
00457     typedef T value_type;
00458     typedef ptrdiff_t difference_type;
00459     typedef T& reference;
00460     typedef const T& const_reference;
00461     typedef T *pointer;
00462     typedef const T *const_pointer;
00463 
00464     typedef internal::vector_iterator<concurrent_vector,T> iterator;
00465     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00466 
00467 #if !defined(_MSC_VER) || _CPPLIB_VER>=300 
00468     // Assume ISO standard definition of std::reverse_iterator
00469     typedef std::reverse_iterator<iterator> reverse_iterator;
00470     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00471 #else
00472     // Use non-standard std::reverse_iterator
00473     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00474     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00475 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
00476 
00477     //------------------------------------------------------------------------
00478     // Parallel algorithm support
00479     //------------------------------------------------------------------------
00480     typedef generic_range_type<iterator> range_type;
00481     typedef generic_range_type<const_iterator> const_range_type;
00482 
00483     //------------------------------------------------------------------------
00484     // STL compatible constructors & destructors
00485     //------------------------------------------------------------------------
00486 
00488     explicit concurrent_vector(const allocator_type &a = allocator_type())
00489         : internal::allocator_base<T, A>(a)
00490     {
00491         vector_allocator_ptr = &internal_allocator;
00492     }
00493 
00495     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00496         : internal::allocator_base<T, A>(a)
00497     {
00498         vector_allocator_ptr = &internal_allocator;
00499         try {
00500             internal_copy(vector, sizeof(T), &copy_array);
00501         } catch(...) {
00502             segment_t *table = my_segment;
00503             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00504             throw;
00505         }
00506     }
00507 
00509     template<class M>
00510     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00511         : internal::allocator_base<T, A>(a)
00512     {
00513         vector_allocator_ptr = &internal_allocator;
00514         try {
00515             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
00516         } catch(...) {
00517             segment_t *table = my_segment;
00518             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00519             throw;
00520         }
00521     }
00522 
00524     explicit concurrent_vector(size_type n)
00525     {
00526         vector_allocator_ptr = &internal_allocator;
00527         try {
00528             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00529         } catch(...) {
00530             segment_t *table = my_segment;
00531             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00532             throw;
00533         }
00534     }
00535 
00537     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00538         : internal::allocator_base<T, A>(a)
00539     {
00540         vector_allocator_ptr = &internal_allocator;
00541         try {
00542             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00543         } catch(...) {
00544             segment_t *table = my_segment;
00545             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00546             throw;
00547         }
00548     }
00549 
00551     template<class I>
00552     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00553         : internal::allocator_base<T, A>(a)
00554     {
00555         vector_allocator_ptr = &internal_allocator;
00556         try {
00557             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00558         } catch(...) {
00559             segment_t *table = my_segment;
00560             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00561             throw;
00562         }
00563     }
00564 
00566     concurrent_vector& operator=( const concurrent_vector& vector ) {
00567         if( this != &vector )
00568             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
00569         return *this;
00570     }
00571 
00573     template<class M>
00574     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00575         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00576             internal_assign(vector.internal_vector_base(),
00577                 sizeof(T), &destroy_array, &assign_array, &copy_array);
00578         return *this;
00579     }
00580 
00581     //------------------------------------------------------------------------
00582     // Concurrent operations
00583     //------------------------------------------------------------------------
00585 #if TBB_DEPRECATED
00586 
00587     size_type grow_by( size_type delta ) {
00588         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00589     }
00590 #else
00591 
00592     iterator grow_by( size_type delta ) {
00593         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
00594     }
00595 #endif
00596 
00598 #if TBB_DEPRECATED
00599 
00600     size_type grow_by( size_type delta, const_reference t ) {
00601         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00602     }
00603 #else
00604 
00605     iterator grow_by( size_type delta, const_reference t ) {
00606         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
00607     }
00608 #endif
00609 
00611 #if TBB_DEPRECATED
00612 
00614     void grow_to_at_least( size_type n ) {
00615         if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00616     };
00617 #else
00618 
00622     iterator grow_to_at_least( size_type n ) {
00623         size_type m=0;
00624         if( n ) {
00625             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00626             if( m>n ) m=n;
00627         }
00628         return iterator(*this, m);
00629     };
00630 #endif
00631 
00633 #if TBB_DEPRECATED
00634     size_type push_back( const_reference item )
00635 #else
00636 
00637     iterator push_back( const_reference item )
00638 #endif
00639     {
00640         size_type k;
00641         void *ptr = internal_push_back(sizeof(T),k);
00642         internal_loop_guide loop(1, ptr);
00643         loop.init(&item);
00644 #if TBB_DEPRECATED
00645         return k;
00646 #else
00647         return iterator(*this, k, ptr);
00648 #endif
00649     }
00650 
00652 
00654     reference operator[]( size_type index ) {
00655         return internal_subscript(index);
00656     }
00657 
00659     const_reference operator[]( size_type index ) const {
00660         return internal_subscript(index);
00661     }
00662 
00664     reference at( size_type index ) {
00665         return internal_subscript_with_exceptions(index);
00666     }
00667 
00669     const_reference at( size_type index ) const {
00670         return internal_subscript_with_exceptions(index);
00671     }
00672 
00674     range_type range( size_t grainsize = 1) {
00675         return range_type( begin(), end(), grainsize );
00676     }
00677 
00679     const_range_type range( size_t grainsize = 1 ) const {
00680         return const_range_type( begin(), end(), grainsize );
00681     }
00682     //------------------------------------------------------------------------
00683     // Capacity
00684     //------------------------------------------------------------------------
00686     size_type size() const {
00687         size_type sz = my_early_size, cp = internal_capacity();
00688         return cp < sz ? cp : sz;
00689     }
00690 
00692     bool empty() const {return !my_early_size;}
00693 
00695     size_type capacity() const {return internal_capacity();}
00696 
00698 
00700     void reserve( size_type n ) {
00701         if( n )
00702             internal_reserve(n, sizeof(T), max_size());
00703     }
00704 
00706     void resize( size_type n ) {
00707         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00708     }
00709     
00711     void resize( size_type n, const_reference t ) {
00712         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00713     }
00714    
00715 #if TBB_DEPRECATED 
00717     void compact() {shrink_to_fit();}
00718 #endif /* TBB_DEPRECATED */
00719 
00721     void shrink_to_fit();
00722 
00724     size_type max_size() const {return (~size_type(0))/sizeof(T);}
00725 
00726     //------------------------------------------------------------------------
00727     // STL support
00728     //------------------------------------------------------------------------
00729 
00731     iterator begin() {return iterator(*this,0);}
00733     iterator end() {return iterator(*this,size());}
00735     const_iterator begin() const {return const_iterator(*this,0);}
00737     const_iterator end() const {return const_iterator(*this,size());}
00739     const_iterator cbegin() const {return const_iterator(*this,0);}
00741     const_iterator cend() const {return const_iterator(*this,size());}
00743     reverse_iterator rbegin() {return reverse_iterator(end());}
00745     reverse_iterator rend() {return reverse_iterator(begin());}
00747     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00749     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00751     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
00753     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
00755     reference front() {
00756         __TBB_ASSERT( size()>0, NULL);
00757         return static_cast<T*>(my_segment[0].array)[0];
00758     }
00760     const_reference front() const {
00761         __TBB_ASSERT( size()>0, NULL);
00762         return static_cast<const T*>(my_segment[0].array)[0];
00763     }
00765     reference back() {
00766         __TBB_ASSERT( size()>0, NULL);
00767         return internal_subscript( size()-1 );
00768     }
00770     const_reference back() const {
00771         __TBB_ASSERT( size()>0, NULL);
00772         return internal_subscript( size()-1 );
00773     }
00775     allocator_type get_allocator() const { return this->my_allocator; }
00776 
00778     void assign(size_type n, const_reference t) {
00779         clear();
00780         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00781     }
00782 
00784     template<class I>
00785     void assign(I first, I last) {
00786         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00787     }
00788 
00790     void swap(concurrent_vector &vector) {
00791         if( this != &vector ) {
00792             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00793             std::swap(this->my_allocator, vector.my_allocator);
00794         }
00795     }
00796 
00798 
00799     void clear() {
00800         internal_clear(&destroy_array);
00801     }
00802 
00804     ~concurrent_vector() {
00805         segment_t *table = my_segment;
00806         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00807         // base class destructor call should be then
00808     }
00809 
00810     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00811 private:
00813     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00814         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00815     }
00817     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00818 
00820     T& internal_subscript( size_type index ) const;
00821 
00823     T& internal_subscript_with_exceptions( size_type index ) const;
00824 
00826     void internal_assign_n(size_type n, const_pointer p) {
00827         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
00828     }
00829 
00831     template<bool B> class is_integer_tag;
00832 
00834     template<class I>
00835     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
00836         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
00837     }
00839     template<class I>
00840     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
00841         internal_assign_iterators(first, last);
00842     }
00844     template<class I>
00845     void internal_assign_iterators(I first, I last);
00846 
00848     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
00849 
00851     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
00852 
00854     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
00855 
00857     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
00858 
00860     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
00861 
00863     class internal_loop_guide : internal::no_copy {
00864     public:
00865         const pointer array;
00866         const size_type n;
00867         size_type i;
00868         internal_loop_guide(size_type ntrials, void *ptr)
00869             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00870         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
00871         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00872         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00873         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00874         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00875         ~internal_loop_guide() {
00876             if(i < n) // if exception raised, do zerroing on the rest of items
00877                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00878         }
00879     };
00880 };
00881 
00882 template<typename T, class A>
00883 void concurrent_vector<T, A>::shrink_to_fit() {
00884     internal_segments_table old;
00885     try {
00886         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
00887             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
00888     } catch(...) {
00889         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
00890             internal_free_segments( old.table, 1, old.first_block );
00891         throw;
00892     }
00893 }
00894 
00895 template<typename T, class A>
00896 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00897     // Free the arrays
00898     while( k > first_block ) {
00899         --k;
00900         T* array = static_cast<T*>(table[k]);
00901         table[k] = NULL;
00902         if( array > internal::vector_allocation_error_flag ) // check for correct segment pointer
00903             this->my_allocator.deallocate( array, segment_size(k) );
00904     }
00905     T* array = static_cast<T*>(table[0]);
00906     if( array > internal::vector_allocation_error_flag ) {
00907         __TBB_ASSERT( first_block > 0, NULL );
00908         while(k > 0) table[--k] = NULL;
00909         this->my_allocator.deallocate( array, segment_size(first_block) );
00910     }
00911 }
00912 
00913 template<typename T, class A>
00914 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00915     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
00916     size_type j = index;
00917     segment_index_t k = segment_base_index_of( j );
00918     __TBB_ASSERT( my_segment != (segment_t*)my_storage || k < pointers_per_short_table, "index is being allocated" );
00919     // no need in __TBB_load_with_acquire since thread works in own space or gets 
00920 #if TBB_USE_THREADING_TOOLS
00921     T* array = static_cast<T*>( tbb::internal::itt_load_pointer_v3(&my_segment[k].array));
00922 #else
00923     T* array = static_cast<T*>(my_segment[k].array);
00924 #endif /* TBB_USE_THREADING_TOOLS */
00925     __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
00926     __TBB_ASSERT( array, "index is being allocated" );
00927     return array[j];
00928 }
00929 
00930 template<typename T, class A>
00931 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00932     if( index >= my_early_size )
00933         internal_throw_exception(0); // throw std::out_of_range
00934     size_type j = index;
00935     segment_index_t k = segment_base_index_of( j );
00936     if( my_segment == (segment_t*)my_storage && k >= pointers_per_short_table )
00937         internal_throw_exception(1); // throw std::range_error
00938     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
00939     if( array <= internal::vector_allocation_error_flag ) // check for correct segment pointer
00940         internal_throw_exception(2); // throw std::range_error
00941     return static_cast<T*>(array)[j];
00942 }
00943 
00944 template<typename T, class A> template<class I>
00945 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00946     __TBB_ASSERT(my_early_size == 0, NULL);
00947     size_type n = std::distance(first, last);
00948     if( !n ) return;
00949     internal_reserve(n, sizeof(T), max_size());
00950     my_early_size = n;
00951     segment_index_t k = 0;
00952     size_type sz = segment_size( my_first_block );
00953     while( sz < n ) {
00954         internal_loop_guide loop(sz, my_segment[k].array);
00955         loop.iterate(first);
00956         n -= sz;
00957         if( !k ) k = my_first_block;
00958         else { ++k; sz <<= 1; }
00959     }
00960     internal_loop_guide loop(n, my_segment[k].array);
00961     loop.iterate(first);
00962 }
00963 
00964 template<typename T, class A>
00965 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00966     internal_loop_guide loop(n, begin); loop.init();
00967 }
00968 
00969 template<typename T, class A>
00970 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00971     internal_loop_guide loop(n, begin); loop.init(src);
00972 }
00973 
00974 template<typename T, class A>
00975 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00976     internal_loop_guide loop(n, dst); loop.copy(src);
00977 }
00978 
00979 template<typename T, class A>
00980 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
00981     internal_loop_guide loop(n, dst); loop.assign(src);
00982 }
00983 
00984 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
00985     // Workaround for overzealous compiler warning
00986     #pragma warning (push)
00987     #pragma warning (disable: 4189)
00988 #endif
00989 template<typename T, class A>
00990 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
00991     T* array = static_cast<T*>(begin);
00992     for( size_type j=n; j>0; --j )
00993         array[j-1].~T(); // destructors are supposed to not throw any exceptions
00994 }
00995 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
00996     #pragma warning (pop)
00997 #endif // warning 4189 is back 
00998 
00999 // concurrent_vector's template functions
01000 template<typename T, class A1, class A2>
01001 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
01002     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
01003     if(a.size() != b.size()) return false;
01004     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
01005     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
01006     for(; i != a.end(); ++i, ++j)
01007         if( !(*i == *j) ) return false;
01008     return true;
01009 }
01010 
01011 template<typename T, class A1, class A2>
01012 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01013 {    return !(a == b); }
01014 
01015 template<typename T, class A1, class A2>
01016 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01017 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
01018 
01019 template<typename T, class A1, class A2>
01020 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01021 {    return b < a; }
01022 
01023 template<typename T, class A1, class A2>
01024 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01025 {    return !(b < a); }
01026 
01027 template<typename T, class A1, class A2>
01028 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01029 {    return !(a < b); }
01030 
01031 template<typename T, class A>
01032 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
01033 {    a.swap( b ); }
01034 
01035 } // namespace tbb
01036 
01037 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
01038     #pragma warning (pop)
01039 #endif // warning 4267 is back
01040 
01041 #endif /* __TBB_concurrent_vector_H */

Copyright © 2005-2009 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.