concurrent_vector.h

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