Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | Related Pages

concurrent_vector.h

00001 /*
00002     Copyright 2005-2008 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 <memory>
00028 #include <limits>
00029 #include <new>
00030 #include <cstring>
00031 #include "atomic.h"
00032 #include "cache_aligned_allocator.h"
00033 #include "blocked_range.h"
00034 
00035 #include "tbb_machine.h"
00036 
00037 #if defined(_MSC_VER) && defined(_Wp64)
00038     // Workaround for overzealous compiler warnings in /Wp64 mode
00039     #pragma warning (push)
00040     #pragma warning (disable: 4267)
00041 #endif /* _MSC_VER && _Wp64 */
00042 
00043 namespace tbb {
00044 
00045 template<typename T, class A = cache_aligned_allocator<T> >
00046 class concurrent_vector;
00047 
00049 #define __TBB_BAD_ALLOC reinterpret_cast<void*>(63)
00050 
00052 namespace internal {
00053 
00055 
00056     class concurrent_vector_base_v3 {
00057     protected:
00058 
00059         // Basic types declarations
00060         typedef size_t segment_index_t;
00061         typedef size_t size_type;
00062 
00063         // Using enumerations due to Mac linking problems of static const variables
00064         enum {
00065             // Size constants
00066             default_initial_segments = 1, // 2 initial items
00068             pointers_per_short_table = 3, // to fit into 8 words of entire structure
00069             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
00070         };
00071 
00072         // Segment pointer. Can be zero-initialized
00073         struct segment_t {
00074             void* array;
00075 #if TBB_DO_ASSERT
00076             ~segment_t() {
00077                 __TBB_ASSERT( array <= __TBB_BAD_ALLOC, "should have been freed by clear" );
00078             }
00079 #endif /* TBB_DO_ASSERT */
00080         };
00081  
00082         // Data fields
00083 
00085         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00086 
00088         atomic<size_type> my_first_block;
00089 
00091         atomic<size_type> my_early_size;
00092 
00094         atomic<segment_t*> my_segment;
00095 
00097         segment_t my_storage[pointers_per_short_table];
00098 
00099         // Methods
00100 
00101         concurrent_vector_base_v3() {
00102             my_early_size = 0;
00103             my_first_block = 0; // here is not default_initial_segments
00104             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00105                 my_storage[i].array = NULL;
00106             my_segment = my_storage;
00107         }
00108         ~concurrent_vector_base_v3();
00109 
00110         static segment_index_t segment_index_of( size_type index ) {
00111             return segment_index_t( __TBB_Log2( index|1 ) );
00112         }
00113 
00114         static segment_index_t segment_base( segment_index_t k ) {
00115             return (segment_index_t(1)<<k & ~segment_index_t(1));
00116         }
00117 
00118         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00119             segment_index_t k = segment_index_of( index );
00120             index -= segment_base(k);
00121             return k;
00122         }
00123 
00124         static size_type segment_size( segment_index_t k ) {
00125             return segment_index_t(1)<<k; // fake value for k==0
00126         }
00127 
00129         typedef void(*internal_array_op1)(void* begin, size_type n );
00130 
00132         typedef void(*internal_array_op2)(void* dst, const void* src, size_type n );
00133 
00135         struct internal_segments_table {
00136             segment_index_t first_block;
00137             void* table[pointers_per_long_table];
00138         };
00139 
00140         void internal_reserve( size_type n, size_type element_size, size_type max_size );
00141         size_type internal_capacity() const;
00142         void internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00143         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00144         size_type internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00145         void* internal_push_back( size_type element_size, size_type& index );
00146         segment_index_t internal_clear( internal_array_op1 destroy );
00147         void* internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00148         void internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00149         void internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00150                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00151         void internal_throw_exception(size_type) const;
00152         void internal_swap(concurrent_vector_base_v3& v);
00153 
00154 private:
00156         class helper;
00157         friend class helper;
00158     };
00159     
00160     typedef concurrent_vector_base_v3 concurrent_vector_base;
00161 
00162     //TODO[?]: deal with _Range_checked_iterator_tag of MSVC
00164 
00166     template<typename Container, typename Value>
00167     class vector_iterator 
00168 #if defined(_WIN64) && defined(_MSC_VER) 
00169         // Ensure that Microsoft's internal template function _Val_type works correctly.
00170         : public std::iterator<std::random_access_iterator_tag,Value>
00171 #endif /* defined(_WIN64) && defined(_MSC_VER) */
00172     {
00174         Container* my_vector;
00175 
00177         size_t my_index;
00178 
00180 
00181         mutable Value* my_item;
00182 
00183         template<typename C, typename T>
00184         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00185 
00186         template<typename C, typename T, typename U>
00187         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00188 
00189         template<typename C, typename T, typename U>
00190         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00191 
00192         template<typename C, typename T, typename U>
00193         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00194     
00195         template<typename C, typename U>
00196         friend class internal::vector_iterator;
00197 
00198 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00199         template<typename T, class A>
00200         friend class tbb::concurrent_vector;
00201 #else
00202 public: // workaround for MSVC
00203 #endif 
00204 
00205         vector_iterator( const Container& vector, size_t index ) : 
00206             my_vector(const_cast<Container*>(&vector)), 
00207             my_index(index), 
00208             my_item(NULL)
00209         {}
00210 
00211     public:
00213         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00214 
00215         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00216             my_vector(other.my_vector),
00217             my_index(other.my_index),
00218             my_item(other.my_item)
00219         {}
00220 
00221         vector_iterator operator+( ptrdiff_t offset ) const {
00222             return vector_iterator( *my_vector, my_index+offset );
00223         }
00224         vector_iterator operator+=( ptrdiff_t offset ) {
00225             my_index+=offset;
00226             my_item = NULL;
00227             return *this;
00228         }
00229         vector_iterator operator-( ptrdiff_t offset ) const {
00230             return vector_iterator( *my_vector, my_index-offset );
00231         }
00232         vector_iterator operator-=( ptrdiff_t offset ) {
00233             my_index-=offset;
00234             my_item = NULL;
00235             return *this;
00236         }
00237         Value& operator*() const {
00238             Value* item = my_item;
00239             if( !item ) {
00240                 item = my_item = &my_vector->internal_subscript(my_index);
00241             }
00242             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00243             return *item;
00244         }
00245         Value& operator[]( ptrdiff_t k ) const {
00246             return my_vector->internal_subscript(my_index+k);
00247         }
00248         Value* operator->() const {return &operator*();}
00249 
00251         vector_iterator& operator++() {
00252             size_t k = ++my_index;
00253             if( my_item ) {
00254                 // Following test uses 2's-complement wizardry
00255                 if( (k& (k-2))==0 ) {
00256                     // k is a power of two that is at least k-2
00257                     my_item= NULL;
00258                 } else {
00259                     ++my_item;
00260                 }
00261             }
00262             return *this;
00263         }
00264 
00266         vector_iterator& operator--() {
00267             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" ); 
00268             size_t k = my_index--;
00269             if( my_item ) {
00270                 // Following test uses 2's-complement wizardry
00271                 if( (k& (k-2))==0 ) {
00272                     // k is a power of two that is at least k-2  
00273                     my_item= NULL;
00274                 } else {
00275                     --my_item;
00276                 }
00277             }
00278             return *this;
00279         }
00280 
00282         vector_iterator operator++(int) {
00283             vector_iterator result = *this;
00284             operator++();
00285             return result;
00286         }
00287 
00289         vector_iterator operator--(int) {
00290             vector_iterator result = *this;
00291             operator--();
00292             return result;
00293         }
00294 
00295         // STL support
00296 
00297         typedef ptrdiff_t difference_type;
00298         typedef Value value_type;
00299         typedef Value* pointer;
00300         typedef Value& reference;
00301         typedef std::random_access_iterator_tag iterator_category;
00302     };
00303 
00304     template<typename Container, typename T>
00305     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00306         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
00307     }
00308 
00309     template<typename Container, typename T, typename U>
00310     bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00311         return i.my_index==j.my_index;
00312     }
00313 
00314     template<typename Container, typename T, typename U>
00315     bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00316         return !(i==j);
00317     }
00318 
00319     template<typename Container, typename T, typename U>
00320     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00321         return i.my_index<j.my_index;
00322     }
00323 
00324     template<typename Container, typename T, typename U>
00325     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00326         return j<i;
00327     }
00328 
00329     template<typename Container, typename T, typename U>
00330     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00331         return !(i<j);
00332     }
00333 
00334     template<typename Container, typename T, typename U>
00335     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00336         return !(j<i);
00337     }
00338 
00339     template<typename Container, typename T, typename U>
00340     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00341         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00342     }
00343 
00344     template<typename T, class A>
00345     class allocator_base {
00346     public:
00347         typedef typename A::template
00348             rebind<T>::other allocator_type;
00349         allocator_type my_allocator;
00350 
00351         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00352     };
00353 
00354 } // namespace internal
00356 
00358 
00413 template<typename T, class A>
00414 class concurrent_vector: protected internal::allocator_base<T, A>,
00415                          private internal::concurrent_vector_base_v3 {
00416 private:
00417     template<typename I>
00418     class generic_range_type: public blocked_range<I> {
00419     public:
00420         typedef T value_type;
00421         typedef T& reference;
00422         typedef const T& const_reference;
00423         typedef I iterator;
00424         typedef ptrdiff_t difference_type;
00425         generic_range_type( I begin_, I end_, size_t grainsize = 1) : blocked_range<I>(begin_,end_,grainsize) {} 
00426         template<typename U>
00427         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {} 
00428         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00429     };
00430 
00431     template<typename C, typename U>
00432     friend class internal::vector_iterator;
00433 public:
00434     //------------------------------------------------------------------------
00435     // STL compatible types
00436     //------------------------------------------------------------------------
00437     typedef internal::concurrent_vector_base_v3::size_type size_type;
00438     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00439 
00440     typedef T value_type;
00441     typedef ptrdiff_t difference_type;
00442     typedef T& reference;
00443     typedef const T& const_reference;
00444     typedef T *pointer;
00445     typedef const T *const_pointer;
00446 
00447     typedef internal::vector_iterator<concurrent_vector,T> iterator;
00448     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00449 
00450 #if !defined(_MSC_VER) || _CPPLIB_VER>=300 
00451     // Assume ISO standard definition of std::reverse_iterator
00452     typedef std::reverse_iterator<iterator> reverse_iterator;
00453     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00454 #else
00455     // Use non-standard std::reverse_iterator
00456     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00457     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00458 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
00459 
00460     //------------------------------------------------------------------------
00461     // Parallel algorithm support
00462     //------------------------------------------------------------------------
00463     typedef generic_range_type<iterator> range_type;
00464     typedef generic_range_type<const_iterator> const_range_type;
00465 
00466     //------------------------------------------------------------------------
00467     // STL compatible constructors & destructors
00468     //------------------------------------------------------------------------
00469 
00471     explicit concurrent_vector(const allocator_type &a = allocator_type())
00472         : internal::allocator_base<T, A>(a)
00473     {
00474         vector_allocator_ptr = &internal_allocator;
00475     }
00476 
00478     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00479         : internal::allocator_base<T, A>(a)
00480     {
00481         vector_allocator_ptr = &internal_allocator;
00482         internal_copy(vector, sizeof(T), &copy_array);
00483     }
00484 
00486     template<class M>
00487     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00488         : internal::allocator_base<T, A>(a)
00489     {
00490         vector_allocator_ptr = &internal_allocator;
00491         internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
00492     }
00493 
00495     explicit concurrent_vector(size_type n)
00496     {
00497         vector_allocator_ptr = &internal_allocator;
00498         if ( !n ) return;
00499         internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00500         __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00501         initialize_array(static_cast<T*>(my_segment[0].array), NULL, n);
00502     }
00503 
00505     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00506         : internal::allocator_base<T, A>(a)
00507     {
00508         vector_allocator_ptr = &internal_allocator;
00509         internal_assign( n, t );
00510     }
00511 
00513     template<class I>
00514     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00515         : internal::allocator_base<T, A>(a)
00516     {
00517         vector_allocator_ptr = &internal_allocator;
00518         internal_assign(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00519     }
00520 
00522     concurrent_vector& operator=( const concurrent_vector& vector ) {
00523         if( this != &vector )
00524             concurrent_vector_base_v3::internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
00525         return *this;
00526     }
00527 
00529     template<class M>
00530     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00531         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00532             concurrent_vector_base_v3::internal_assign(vector.internal_vector_base(),
00533                 sizeof(T), &destroy_array, &assign_array, &copy_array);
00534         return *this;
00535     }
00536 
00537     //------------------------------------------------------------------------
00538     // Concurrent operations
00539     //------------------------------------------------------------------------
00541 
00542     size_type grow_by( size_type delta ) {
00543         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00544     }
00545 
00547 
00548     size_type grow_by( size_type delta, const_reference t ) {
00549         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00550     }
00551 
00553     void grow_to_at_least( size_type n ) {
00554         if( my_early_size<n )
00555             internal_grow_to_at_least( n, sizeof(T), &initialize_array, NULL );
00556     };
00557 
00559     size_type push_back( const_reference item ) {
00560         size_type k;
00561         internal_loop_guide loop(1, internal_push_back(sizeof(T),k));
00562         loop.init(&item);
00563         return k;
00564     }
00565 
00567 
00569     reference operator[]( size_type index ) {
00570         return internal_subscript(index);
00571     }
00572 
00574     const_reference operator[]( size_type index ) const {
00575         return internal_subscript(index);
00576     }
00577 
00579     reference at( size_type index ) {
00580         return internal_subscript_with_exceptions(index);
00581     }
00582 
00584     const_reference at( size_type index ) const {
00585         return internal_subscript_with_exceptions(index);
00586     }
00587 
00589     range_type range( size_t grainsize = 1) {
00590         return range_type( begin(), end(), grainsize );
00591     }
00592 
00594     const_range_type range( size_t grainsize = 1 ) const {
00595         return const_range_type( begin(), end(), grainsize );
00596     }
00597     //------------------------------------------------------------------------
00598     // Capacity
00599     //------------------------------------------------------------------------
00601     size_type size() const {return my_early_size;}
00602 
00604     bool empty() const {return !my_early_size;}
00605 
00607     size_type capacity() const {return internal_capacity();}
00608 
00610 
00612     void reserve( size_type n ) {
00613         if( n )
00614             internal_reserve(n, sizeof(T), max_size());
00615     }
00616 
00618     void compact();
00619 
00621     size_type max_size() const {return (~size_type(0))/sizeof(T);}
00622 
00623     //------------------------------------------------------------------------
00624     // STL support
00625     //------------------------------------------------------------------------
00626 
00628     iterator begin() {return iterator(*this,0);}
00630     iterator end() {return iterator(*this,size());}
00632     const_iterator begin() const {return const_iterator(*this,0);}
00634     const_iterator end() const {return const_iterator(*this,size());}
00636     reverse_iterator rbegin() {return reverse_iterator(end());}
00638     reverse_iterator rend() {return reverse_iterator(begin());}
00640     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00642     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00644     reference front() {
00645         __TBB_ASSERT( size()>0, NULL);
00646         return static_cast<T*>(my_segment[0].array)[0];
00647     }
00649     const_reference front() const {
00650         __TBB_ASSERT( size()>0, NULL);
00651         return static_cast<const T*>(my_segment[0].array)[0];
00652     }
00654     reference back() {
00655         __TBB_ASSERT( size()>0, NULL);
00656         return internal_subscript( my_early_size-1 );
00657     }
00659     const_reference back() const {
00660         __TBB_ASSERT( size()>0, NULL);
00661         return internal_subscript( my_early_size-1 );
00662     }
00664     allocator_type get_allocator() const { return this->my_allocator; }
00665 
00667     void assign(size_type n, const_reference t) { clear(); internal_assign( n, t ); }
00668 
00670     template<class I>
00671     void assign(I first, I last) {
00672         clear(); internal_assign( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00673     }
00674 
00676     void swap(concurrent_vector &vector) {
00677         if( this != &vector ) {
00678             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00679             std::swap(this->my_allocator, vector.my_allocator);
00680         }
00681     }
00682 
00684     void clear() {
00685         segment_t *table = my_segment;
00686         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00687         my_first_block = 0; // here is not default_initial_segments
00688     }
00689 
00691     ~concurrent_vector() {
00692         clear();
00693         // base class destructor call should be then
00694     }
00695 
00696     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00697 private:
00699     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00700         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00701     }
00703     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00704 
00706     T& internal_subscript( size_type index ) const;
00707 
00709     T& internal_subscript_with_exceptions( size_type index ) const;
00710 
00712     void internal_assign(size_type n, const_reference t);
00713 
00715     template<bool B> class is_integer_tag;
00716 
00718     template<class I>
00719     void internal_assign(I first, I last, is_integer_tag<true> *) {
00720         internal_assign(static_cast<size_type>(first), static_cast<T>(last));
00721     }
00723     template<class I>
00724     void internal_assign(I first, I last, is_integer_tag<false> *) {
00725         internal_assign_iterators(first, last);
00726     }
00728     template<class I>
00729     void internal_assign_iterators(I first, I last);
00730 
00732     static void initialize_array( void* begin, const void*, size_type n );
00733 
00735     static void initialize_array_by( void* begin, const void* src, size_type n );
00736 
00738     static void copy_array( void* dst, const void* src, size_type n );
00739 
00741     static void assign_array( void* dst, const void* src, size_type n );
00742 
00744     static void destroy_array( void* begin, size_type n );
00745 
00747     class internal_loop_guide {
00748     public:
00749         const pointer array;
00750         const size_type n;
00751         size_type i;
00752         internal_loop_guide(size_type ntrials, void *ptr)
00753             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00754         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
00755         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00756         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00757         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00758         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00759         ~internal_loop_guide() {
00760             if(i < n) // if exception raised, do zerroing on the rest of items
00761                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00762         }
00763     };
00764 };
00765 
00766 template<typename T, class A>
00767 void concurrent_vector<T, A>::compact() {
00768     internal_segments_table old;
00769     try {
00770         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
00771             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
00772     } catch(...) {
00773         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
00774             internal_free_segments( old.table, 1, old.first_block );
00775         throw;
00776     }
00777 }
00778 
00779 template<typename T, class A>
00780 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00781     // Free the arrays
00782     while( k > first_block ) {
00783         --k;
00784         T* array = static_cast<T*>(table[k]);
00785         table[k] = NULL;
00786         if( array > __TBB_BAD_ALLOC ) // check for correct segment pointer
00787             this->my_allocator.deallocate( array, segment_size(k) );
00788     }
00789     T* array = static_cast<T*>(table[0]);
00790     if( array > __TBB_BAD_ALLOC ) {
00791         __TBB_ASSERT( first_block > 0, NULL );
00792         while(k > 0) table[--k] = NULL;
00793         this->my_allocator.deallocate( array, segment_size(first_block) );
00794     }
00795 }
00796 
00797 template<typename T, class A>
00798 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00799     __TBB_ASSERT( index<size(), "index out of bounds" );
00800     size_type j = index;
00801     segment_index_t k = segment_base_index_of( j );
00802     // no need in __TBB_load_with_acquire since thread works in own space or gets 
00803     return static_cast<T*>(my_segment[k].array)[j];
00804 }
00805 
00806 template<typename T, class A>
00807 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00808     if( index >= size() )
00809         internal_throw_exception(0); // throw std::out_of_range
00810     size_type j = index;
00811     segment_index_t k = segment_base_index_of( j );
00812     if( my_segment == (segment_t*)my_storage && k >= pointers_per_short_table )
00813         internal_throw_exception(1); // throw std::out_of_range
00814     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
00815     if( array <= __TBB_BAD_ALLOC ) // check for correct segment pointer
00816         internal_throw_exception(2); // throw std::range_error
00817     return static_cast<T*>(array)[j];
00818 }
00819 
00820 template<typename T, class A>
00821 void concurrent_vector<T, A>::internal_assign(size_type n, const_reference t)
00822 {
00823     if( !n ) return;
00824     internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00825     __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00826     initialize_array_by(static_cast<T*>(my_segment[0].array), static_cast<const void*>(&t), n);
00827 }
00828 
00829 template<typename T, class A> template<class I>
00830 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00831     size_type n = std::distance(first, last);
00832     if( !n ) return;
00833     internal_reserve(n, sizeof(T), max_size()); my_early_size = n;
00834     __TBB_ASSERT( my_first_block == segment_index_of(n-1)+1, NULL );
00835     internal_loop_guide loop(n, my_segment[0].array); loop.iterate(first);
00836 }
00837 
00838 template<typename T, class A>
00839 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00840     internal_loop_guide loop(n, begin); loop.init();
00841 }
00842 
00843 template<typename T, class A>
00844 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00845     internal_loop_guide loop(n, begin); loop.init(src);
00846 }
00847 
00848 template<typename T, class A>
00849 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00850     internal_loop_guide loop(n, dst); loop.copy(src);
00851 }
00852 
00853 template<typename T, class A>
00854 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
00855     internal_loop_guide loop(n, dst); loop.assign(src);
00856 }
00857 
00858 template<typename T, class A>
00859 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
00860     T* array = static_cast<T*>(begin);
00861     for( size_type j=n; j>0; --j )
00862         array[j-1].~T(); // destructors are supposed to not throw any exceptions
00863 }
00864 
00865 // concurrent_vector's template functions
00866 template<typename T, class A1, class A2>
00867 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
00868     //TODO[?]: deal with _Range_checked_iterator_tag of MSVC.
00869     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
00870     if(a.size() != b.size()) return false;
00871     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
00872     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
00873     for(; i != a.end(); ++i, ++j)
00874         if( !(*i == *j) ) return false;
00875     return true;
00876 }
00877 
00878 template<typename T, class A1, class A2>
00879 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00880 {    return !(a == b); }
00881 
00882 template<typename T, class A1, class A2>
00883 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00884 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
00885 
00886 template<typename T, class A1, class A2>
00887 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00888 {    return b < a; }
00889 
00890 template<typename T, class A1, class A2>
00891 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00892 {    return !(b < a); }
00893 
00894 template<typename T, class A1, class A2>
00895 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
00896 {    return !(a < b); }
00897 
00898 template<typename T, class A>
00899 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
00900 {    a.swap( b ); }
00901 
00902 } // namespace tbb
00903 
00904 #if defined(_MSC_VER) && defined(_Wp64)
00905     // Workaround for overzealous compiler warnings in /Wp64 mode
00906     #pragma warning (pop)
00907 #endif /* _MSC_VER && _Wp64 */
00908 
00909 #endif /* __TBB_concurrent_vector_H */

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