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