concurrent_vector.h

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

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