concurrent_vector.h

00001 /*
00002     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
00019 */
00020 
00021 #ifndef __TBB_concurrent_vector_H
00022 #define __TBB_concurrent_vector_H
00023 
00024 #include "tbb_stddef.h"
00025 #include "tbb_exception.h"
00026 #include "atomic.h"
00027 #include "cache_aligned_allocator.h"
00028 #include "blocked_range.h"
00029 #include "tbb_machine.h"
00030 #include "tbb_profiling.h"
00031 #include <new>
00032 
00033 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00034     // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
00035     #pragma warning (push)
00036     #pragma warning (disable: 4530)
00037 #endif
00038 
00039 #include <algorithm>
00040 #include <iterator>
00041 
00042 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00043     #pragma warning (pop)
00044 #endif
00045 
00046 #if _MSC_VER==1500 && !__INTEL_COMPILER
00047     // VS2008/VC9 seems to have an issue; limits pull in math.h
00048     #pragma warning( push )
00049     #pragma warning( disable: 4985 )
00050 #endif
00051 #include <limits> /* std::numeric_limits */
00052 #if _MSC_VER==1500 && !__INTEL_COMPILER
00053     #pragma warning( pop )
00054 #endif
00055 
00056 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
00057     // Workaround for overzealous compiler warnings in /Wp64 mode
00058     #pragma warning (push)
00059     #pragma warning (disable: 4267)
00060 #endif
00061 
00062 namespace tbb {
00063 
00064 template<typename T, class A = cache_aligned_allocator<T> >
00065 class concurrent_vector;
00066 
00068 namespace internal {
00069 
00071     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
00072 
00074 
00075     class concurrent_vector_base_v3 {
00076     protected:
00077 
00078         // Basic types declarations
00079         typedef size_t segment_index_t;
00080         typedef size_t size_type;
00081 
00082         // Using enumerations due to Mac linking problems of static const variables
00083         enum {
00084             // Size constants
00085             default_initial_segments = 1, // 2 initial items
00087             pointers_per_short_table = 3, // to fit into 8 words of entire structure
00088             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
00089         };
00090 
00091         // Segment pointer. Can be zero-initialized
00092         struct segment_t {
00093             void* array;
00094 #if TBB_USE_ASSERT
00095             ~segment_t() {
00096                 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
00097             }
00098 #endif /* TBB_USE_ASSERT */
00099         };
00100  
00101         // Data fields
00102 
00104         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00105 
00107         atomic<size_type> my_first_block;
00108 
00110         atomic<size_type> my_early_size;
00111 
00113         atomic<segment_t*> my_segment;
00114 
00116         segment_t my_storage[pointers_per_short_table];
00117 
00118         // Methods
00119 
00120         concurrent_vector_base_v3() {
00121             my_early_size = 0;
00122             my_first_block = 0; // here is not default_initial_segments
00123             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00124                 my_storage[i].array = NULL;
00125             my_segment = my_storage;
00126         }
00127         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
00128 
00129         static segment_index_t segment_index_of( size_type index ) {
00130             return segment_index_t( __TBB_Log2( index|1 ) );
00131         }
00132 
00133         static segment_index_t segment_base( segment_index_t k ) {
00134             return (segment_index_t(1)<<k & ~segment_index_t(1));
00135         }
00136 
00137         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00138             segment_index_t k = segment_index_of( index );
00139             index -= segment_base(k);
00140             return k;
00141         }
00142 
00143         static size_type segment_size( segment_index_t k ) {
00144             return segment_index_t(1)<<k; // fake value for k==0
00145         }
00146 
00148         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
00149 
00151         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
00152 
00154         struct internal_segments_table {
00155             segment_index_t first_block;
00156             void* table[pointers_per_long_table];
00157         };
00158 
00159         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
00160         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
00161         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00162         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00163         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
00164         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
00165         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00166         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00167         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00168                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00170         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
00171         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
00172 
00173         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
00174                                                     internal_array_op1 destroy, internal_array_op2 init );
00175         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 );
00176 
00178         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00179 private:
00181         class helper;
00182         friend class helper;
00183     };
00184     
00185     typedef concurrent_vector_base_v3 concurrent_vector_base;
00186 
00188 
00190     template<typename Container, typename Value>
00191     class vector_iterator 
00192     {
00194         Container* my_vector;
00195 
00197         size_t my_index;
00198 
00200 
00201         mutable Value* my_item;
00202 
00203         template<typename C, typename T>
00204         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00205 
00206         template<typename C, typename T, typename U>
00207         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00208 
00209         template<typename C, typename T, typename U>
00210         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00211 
00212         template<typename C, typename T, typename U>
00213         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00214     
00215         template<typename C, typename U>
00216         friend class internal::vector_iterator;
00217 
00218 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00219         template<typename T, class A>
00220         friend class tbb::concurrent_vector;
00221 #else
00222 public: // workaround for MSVC
00223 #endif 
00224 
00225         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) : 
00226             my_vector(const_cast<Container*>(&vector)), 
00227             my_index(index), 
00228             my_item(static_cast<Value*>(ptr))
00229         {}
00230 
00231     public:
00233         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00234 
00235         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00236             my_vector(other.my_vector),
00237             my_index(other.my_index),
00238             my_item(other.my_item)
00239         {}
00240 
00241         vector_iterator operator+( ptrdiff_t offset ) const {
00242             return vector_iterator( *my_vector, my_index+offset );
00243         }
00244         vector_iterator &operator+=( ptrdiff_t offset ) {
00245             my_index+=offset;
00246             my_item = NULL;
00247             return *this;
00248         }
00249         vector_iterator operator-( ptrdiff_t offset ) const {
00250             return vector_iterator( *my_vector, my_index-offset );
00251         }
00252         vector_iterator &operator-=( ptrdiff_t offset ) {
00253             my_index-=offset;
00254             my_item = NULL;
00255             return *this;
00256         }
00257         Value& operator*() const {
00258             Value* item = my_item;
00259             if( !item ) {
00260                 item = my_item = &my_vector->internal_subscript(my_index);
00261             }
00262             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00263             return *item;
00264         }
00265         Value& operator[]( ptrdiff_t k ) const {
00266             return my_vector->internal_subscript(my_index+k);
00267         }
00268         Value* operator->() const {return &operator*();}
00269 
00271         vector_iterator& operator++() {
00272             size_t k = ++my_index;
00273             if( my_item ) {
00274                 // Following test uses 2's-complement wizardry
00275                 if( (k& (k-2))==0 ) {
00276                     // k is a power of two that is at least k-2
00277                     my_item= NULL;
00278                 } else {
00279                     ++my_item;
00280                 }
00281             }
00282             return *this;
00283         }
00284 
00286         vector_iterator& operator--() {
00287             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" ); 
00288             size_t k = my_index--;
00289             if( my_item ) {
00290                 // Following test uses 2's-complement wizardry
00291                 if( (k& (k-2))==0 ) {
00292                     // k is a power of two that is at least k-2  
00293                     my_item= NULL;
00294                 } else {
00295                     --my_item;
00296                 }
00297             }
00298             return *this;
00299         }
00300 
00302         vector_iterator operator++(int) {
00303             vector_iterator result = *this;
00304             operator++();
00305             return result;
00306         }
00307 
00309         vector_iterator operator--(int) {
00310             vector_iterator result = *this;
00311             operator--();
00312             return result;
00313         }
00314 
00315         // STL support
00316 
00317         typedef ptrdiff_t difference_type;
00318         typedef Value value_type;
00319         typedef Value* pointer;
00320         typedef Value& reference;
00321         typedef std::random_access_iterator_tag iterator_category;
00322     };
00323 
00324     template<typename Container, typename T>
00325     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00326         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
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.my_index==j.my_index && i.my_vector == j.my_vector;
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 !(i==j);
00337     }
00338 
00339     template<typename Container, typename T, typename U>
00340     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00341         return i.my_index<j.my_index;
00342     }
00343 
00344     template<typename Container, typename T, typename U>
00345     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00346         return j<i;
00347     }
00348 
00349     template<typename Container, typename T, typename U>
00350     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00351         return !(i<j);
00352     }
00353 
00354     template<typename Container, typename T, typename U>
00355     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00356         return !(j<i);
00357     }
00358 
00359     template<typename Container, typename T, typename U>
00360     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00361         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00362     }
00363 
00364     template<typename T, class A>
00365     class allocator_base {
00366     public:
00367         typedef typename A::template
00368             rebind<T>::other allocator_type;
00369         allocator_type my_allocator;
00370 
00371         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00372     };
00373 
00374 } // namespace internal
00376 
00378 
00439 template<typename T, class A>
00440 class concurrent_vector: protected internal::allocator_base<T, A>,
00441                          private internal::concurrent_vector_base {
00442 private:
00443     template<typename I>
00444     class generic_range_type: public blocked_range<I> {
00445     public:
00446         typedef T value_type;
00447         typedef T& reference;
00448         typedef const T& const_reference;
00449         typedef I iterator;
00450         typedef ptrdiff_t difference_type;
00451         generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {} 
00452         template<typename U>
00453         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {} 
00454         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00455     };
00456 
00457     template<typename C, typename U>
00458     friend class internal::vector_iterator;
00459 public:
00460     //------------------------------------------------------------------------
00461     // STL compatible types
00462     //------------------------------------------------------------------------
00463     typedef internal::concurrent_vector_base_v3::size_type size_type;
00464     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00465 
00466     typedef T value_type;
00467     typedef ptrdiff_t difference_type;
00468     typedef T& reference;
00469     typedef const T& const_reference;
00470     typedef T *pointer;
00471     typedef const T *const_pointer;
00472 
00473     typedef internal::vector_iterator<concurrent_vector,T> iterator;
00474     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00475 
00476 #if !defined(_MSC_VER) || _CPPLIB_VER>=300 
00477     // Assume ISO standard definition of std::reverse_iterator
00478     typedef std::reverse_iterator<iterator> reverse_iterator;
00479     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00480 #else
00481     // Use non-standard std::reverse_iterator
00482     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00483     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00484 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
00485 
00486     //------------------------------------------------------------------------
00487     // Parallel algorithm support
00488     //------------------------------------------------------------------------
00489     typedef generic_range_type<iterator> range_type;
00490     typedef generic_range_type<const_iterator> const_range_type;
00491 
00492     //------------------------------------------------------------------------
00493     // STL compatible constructors & destructors
00494     //------------------------------------------------------------------------
00495 
00497     explicit concurrent_vector(const allocator_type &a = allocator_type())
00498         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00499     {
00500         vector_allocator_ptr = &internal_allocator;
00501     }
00502 
00504     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00505         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00506     {
00507         vector_allocator_ptr = &internal_allocator;
00508         __TBB_TRY {
00509             internal_copy(vector, sizeof(T), &copy_array);
00510         } __TBB_CATCH(...) {
00511             segment_t *table = my_segment;
00512             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00513             __TBB_RETHROW();
00514         }
00515     }
00516 
00518     template<class M>
00519     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00520         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00521     {
00522         vector_allocator_ptr = &internal_allocator;
00523         __TBB_TRY {
00524             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
00525         } __TBB_CATCH(...) {
00526             segment_t *table = my_segment;
00527             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00528             __TBB_RETHROW();
00529         }
00530     }
00531 
00533     explicit concurrent_vector(size_type n)
00534     {
00535         vector_allocator_ptr = &internal_allocator;
00536         __TBB_TRY {
00537             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00538         } __TBB_CATCH(...) {
00539             segment_t *table = my_segment;
00540             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00541             __TBB_RETHROW();
00542         }
00543     }
00544 
00546     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00547         : internal::allocator_base<T, A>(a)
00548     {
00549         vector_allocator_ptr = &internal_allocator;
00550         __TBB_TRY {
00551             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00552         } __TBB_CATCH(...) {
00553             segment_t *table = my_segment;
00554             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00555             __TBB_RETHROW();
00556         }
00557     }
00558 
00560     template<class I>
00561     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00562         : internal::allocator_base<T, A>(a)
00563     {
00564         vector_allocator_ptr = &internal_allocator;
00565         __TBB_TRY {
00566             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00567         } __TBB_CATCH(...) {
00568             segment_t *table = my_segment;
00569             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00570             __TBB_RETHROW();
00571         }
00572     }
00573 
00575     concurrent_vector& operator=( const concurrent_vector& vector ) {
00576         if( this != &vector )
00577             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
00578         return *this;
00579     }
00580 
00582     template<class M>
00583     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00584         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00585             internal_assign(vector.internal_vector_base(),
00586                 sizeof(T), &destroy_array, &assign_array, &copy_array);
00587         return *this;
00588     }
00589 
00590     //------------------------------------------------------------------------
00591     // Concurrent operations
00592     //------------------------------------------------------------------------
00594 #if TBB_DEPRECATED
00595 
00596     size_type grow_by( size_type delta ) {
00597         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00598     }
00599 #else
00600 
00601     iterator grow_by( size_type delta ) {
00602         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
00603     }
00604 #endif
00605 
00607 #if TBB_DEPRECATED
00608 
00609     size_type grow_by( size_type delta, const_reference t ) {
00610         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00611     }
00612 #else
00613 
00614     iterator grow_by( size_type delta, const_reference t ) {
00615         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
00616     }
00617 #endif
00618 
00620 #if TBB_DEPRECATED
00621 
00623     void grow_to_at_least( size_type n ) {
00624         if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00625     };
00626 #else
00627 
00631     iterator grow_to_at_least( size_type n ) {
00632         size_type m=0;
00633         if( n ) {
00634             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00635             if( m>n ) m=n;
00636         }
00637         return iterator(*this, m);
00638     };
00639 #endif
00640 
00642 #if TBB_DEPRECATED
00643     size_type push_back( const_reference item )
00644 #else
00645 
00646     iterator push_back( const_reference item )
00647 #endif
00648     {
00649         size_type k;
00650         void *ptr = internal_push_back(sizeof(T),k);
00651         internal_loop_guide loop(1, ptr);
00652         loop.init(&item);
00653 #if TBB_DEPRECATED
00654         return k;
00655 #else
00656         return iterator(*this, k, ptr);
00657 #endif
00658     }
00659 
00661 
00663     reference operator[]( size_type index ) {
00664         return internal_subscript(index);
00665     }
00666 
00668     const_reference operator[]( size_type index ) const {
00669         return internal_subscript(index);
00670     }
00671 
00673     reference at( size_type index ) {
00674         return internal_subscript_with_exceptions(index);
00675     }
00676 
00678     const_reference at( size_type index ) const {
00679         return internal_subscript_with_exceptions(index);
00680     }
00681 
00683     range_type range( size_t grainsize = 1) {
00684         return range_type( begin(), end(), grainsize );
00685     }
00686 
00688     const_range_type range( size_t grainsize = 1 ) const {
00689         return const_range_type( begin(), end(), grainsize );
00690     }
00691     //------------------------------------------------------------------------
00692     // Capacity
00693     //------------------------------------------------------------------------
00695     size_type size() const {
00696         size_type sz = my_early_size, cp = internal_capacity();
00697         return cp < sz ? cp : sz;
00698     }
00699 
00701     bool empty() const {return !my_early_size;}
00702 
00704     size_type capacity() const {return internal_capacity();}
00705 
00707 
00709     void reserve( size_type n ) {
00710         if( n )
00711             internal_reserve(n, sizeof(T), max_size());
00712     }
00713 
00715     void resize( size_type n ) {
00716         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00717     }
00718     
00720     void resize( size_type n, const_reference t ) {
00721         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00722     }
00723    
00724 #if TBB_DEPRECATED 
00726     void compact() {shrink_to_fit();}
00727 #endif /* TBB_DEPRECATED */
00728 
00730     void shrink_to_fit();
00731 
00733     size_type max_size() const {return (~size_type(0))/sizeof(T);}
00734 
00735     //------------------------------------------------------------------------
00736     // STL support
00737     //------------------------------------------------------------------------
00738 
00740     iterator begin() {return iterator(*this,0);}
00742     iterator end() {return iterator(*this,size());}
00744     const_iterator begin() const {return const_iterator(*this,0);}
00746     const_iterator end() const {return const_iterator(*this,size());}
00748     const_iterator cbegin() const {return const_iterator(*this,0);}
00750     const_iterator cend() const {return const_iterator(*this,size());}
00752     reverse_iterator rbegin() {return reverse_iterator(end());}
00754     reverse_iterator rend() {return reverse_iterator(begin());}
00756     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00758     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00760     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
00762     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
00764     reference front() {
00765         __TBB_ASSERT( size()>0, NULL);
00766         return static_cast<T*>(my_segment[0].array)[0];
00767     }
00769     const_reference front() const {
00770         __TBB_ASSERT( size()>0, NULL);
00771         return static_cast<const T*>(my_segment[0].array)[0];
00772     }
00774     reference back() {
00775         __TBB_ASSERT( size()>0, NULL);
00776         return internal_subscript( size()-1 );
00777     }
00779     const_reference back() const {
00780         __TBB_ASSERT( size()>0, NULL);
00781         return internal_subscript( size()-1 );
00782     }
00784     allocator_type get_allocator() const { return this->my_allocator; }
00785 
00787     void assign(size_type n, const_reference t) {
00788         clear();
00789         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00790     }
00791 
00793     template<class I>
00794     void assign(I first, I last) {
00795         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00796     }
00797 
00799     void swap(concurrent_vector &vector) {
00800         if( this != &vector ) {
00801             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00802             std::swap(this->my_allocator, vector.my_allocator);
00803         }
00804     }
00805 
00807 
00808     void clear() {
00809         internal_clear(&destroy_array);
00810     }
00811 
00813     ~concurrent_vector() {
00814         segment_t *table = my_segment;
00815         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00816         // base class destructor call should be then
00817     }
00818 
00819     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00820 private:
00822     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00823         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00824     }
00826     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00827 
00829     T& internal_subscript( size_type index ) const;
00830 
00832     T& internal_subscript_with_exceptions( size_type index ) const;
00833 
00835     void internal_assign_n(size_type n, const_pointer p) {
00836         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
00837     }
00838 
00840     template<bool B> class is_integer_tag;
00841 
00843     template<class I>
00844     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
00845         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
00846     }
00848     template<class I>
00849     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
00850         internal_assign_iterators(first, last);
00851     }
00853     template<class I>
00854     void internal_assign_iterators(I first, I last);
00855 
00857     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
00858 
00860     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
00861 
00863     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
00864 
00866     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
00867 
00869     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
00870 
00872     class internal_loop_guide : internal::no_copy {
00873     public:
00874         const pointer array;
00875         const size_type n;
00876         size_type i;
00877         internal_loop_guide(size_type ntrials, void *ptr)
00878             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00879         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
00880         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00881         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00882         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00883         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00884         ~internal_loop_guide() {
00885             if(i < n) // if exception raised, do zerroing on the rest of items
00886                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00887         }
00888     };
00889 };
00890 
00891 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
00892 #pragma warning (push)
00893 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
00894 #endif
00895 template<typename T, class A>
00896 void concurrent_vector<T, A>::shrink_to_fit() {
00897     internal_segments_table old;
00898     __TBB_TRY {
00899         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
00900             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
00901     } __TBB_CATCH(...) {
00902         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
00903             internal_free_segments( old.table, 1, old.first_block );
00904         __TBB_RETHROW();
00905     }
00906 }
00907 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
00908 #pragma warning (pop)
00909 #endif // warning 4701 is back 
00910 
00911 template<typename T, class A>
00912 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00913     // Free the arrays
00914     while( k > first_block ) {
00915         --k;
00916         T* array = static_cast<T*>(table[k]);
00917         table[k] = NULL;
00918         if( array > internal::vector_allocation_error_flag ) // check for correct segment pointer
00919             this->my_allocator.deallocate( array, segment_size(k) );
00920     }
00921     T* array = static_cast<T*>(table[0]);
00922     if( array > internal::vector_allocation_error_flag ) {
00923         __TBB_ASSERT( first_block > 0, NULL );
00924         while(k > 0) table[--k] = NULL;
00925         this->my_allocator.deallocate( array, segment_size(first_block) );
00926     }
00927 }
00928 
00929 template<typename T, class A>
00930 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00931     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
00932     size_type j = index;
00933     segment_index_t k = segment_base_index_of( j );
00934     __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
00935     // no need in __TBB_load_with_acquire since thread works in own space or gets 
00936     T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segment[k].array));
00937     __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
00938     __TBB_ASSERT( array, "index is being allocated" );
00939     return array[j];
00940 }
00941 
00942 template<typename T, class A>
00943 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00944     if( index >= my_early_size )
00945         internal::throw_exception(internal::eid_out_of_range); // throw std::out_of_range
00946     size_type j = index;
00947     segment_index_t k = segment_base_index_of( j );
00948     if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
00949         internal::throw_exception(internal::eid_segment_range_error); // throw std::range_error
00950     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
00951     if( array <= internal::vector_allocation_error_flag ) // check for correct segment pointer
00952         internal::throw_exception(internal::eid_index_range_error); // throw std::range_error
00953     return static_cast<T*>(array)[j];
00954 }
00955 
00956 template<typename T, class A> template<class I>
00957 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00958     __TBB_ASSERT(my_early_size == 0, NULL);
00959     size_type n = std::distance(first, last);
00960     if( !n ) return;
00961     internal_reserve(n, sizeof(T), max_size());
00962     my_early_size = n;
00963     segment_index_t k = 0;
00964     size_type sz = segment_size( my_first_block );
00965     while( sz < n ) {
00966         internal_loop_guide loop(sz, my_segment[k].array);
00967         loop.iterate(first);
00968         n -= sz;
00969         if( !k ) k = my_first_block;
00970         else { ++k; sz <<= 1; }
00971     }
00972     internal_loop_guide loop(n, my_segment[k].array);
00973     loop.iterate(first);
00974 }
00975 
00976 template<typename T, class A>
00977 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00978     internal_loop_guide loop(n, begin); loop.init();
00979 }
00980 
00981 template<typename T, class A>
00982 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00983     internal_loop_guide loop(n, begin); loop.init(src);
00984 }
00985 
00986 template<typename T, class A>
00987 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00988     internal_loop_guide loop(n, dst); loop.copy(src);
00989 }
00990 
00991 template<typename T, class A>
00992 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
00993     internal_loop_guide loop(n, dst); loop.assign(src);
00994 }
00995 
00996 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
00997     // Workaround for overzealous compiler warning
00998     #pragma warning (push)
00999     #pragma warning (disable: 4189)
01000 #endif
01001 template<typename T, class A>
01002 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
01003     T* array = static_cast<T*>(begin);
01004     for( size_type j=n; j>0; --j )
01005         array[j-1].~T(); // destructors are supposed to not throw any exceptions
01006 }
01007 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
01008     #pragma warning (pop)
01009 #endif // warning 4189 is back 
01010 
01011 // concurrent_vector's template functions
01012 template<typename T, class A1, class A2>
01013 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
01014     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
01015     if(a.size() != b.size()) return false;
01016     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
01017     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
01018     for(; i != a.end(); ++i, ++j)
01019         if( !(*i == *j) ) return false;
01020     return true;
01021 }
01022 
01023 template<typename T, class A1, class A2>
01024 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01025 {    return !(a == b); }
01026 
01027 template<typename T, class A1, class A2>
01028 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01029 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
01030 
01031 template<typename T, class A1, class A2>
01032 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01033 {    return b < a; }
01034 
01035 template<typename T, class A1, class A2>
01036 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01037 {    return !(b < a); }
01038 
01039 template<typename T, class A1, class A2>
01040 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01041 {    return !(a < b); }
01042 
01043 template<typename T, class A>
01044 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
01045 {    a.swap( b ); }
01046 
01047 } // namespace tbb
01048 
01049 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
01050     #pragma warning (pop)
01051 #endif // warning 4267 is back
01052 
01053 #endif /* __TBB_concurrent_vector_H */

Copyright © 2005-2011 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.