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