Shadowrun: Awakened 29 September 2011 - Build 871
concurrent_vector.h
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 #ifndef __TBB_concurrent_vector_H
00030 #define __TBB_concurrent_vector_H
00031 
00032 #include "tbb_stddef.h"
00033 #include "tbb_exception.h"
00034 #include "atomic.h"
00035 #include "cache_aligned_allocator.h"
00036 #include "blocked_range.h"
00037 #include "tbb_machine.h"
00038 #include <new>
00039 
00040 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00041     // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
00042     #pragma warning (push)
00043     #pragma warning (disable: 4530)
00044 #endif
00045 
00046 #include <algorithm>
00047 #include <iterator>
00048 
00049 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00050     #pragma warning (pop)
00051 #endif
00052 
00053 #if _MSC_VER==1500 && !__INTEL_COMPILER
00054     // VS2008/VC9 seems to have an issue; limits pull in math.h
00055     #pragma warning( push )
00056     #pragma warning( disable: 4985 )
00057 #endif
00058 #include <limits> /* std::numeric_limits */
00059 #if _MSC_VER==1500 && !__INTEL_COMPILER
00060     #pragma warning( pop )
00061 #endif
00062 
00063 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
00064     // Workaround for overzealous compiler warnings in /Wp64 mode
00065     #pragma warning (push)
00066     #pragma warning (disable: 4267)
00067 #endif
00068 
00069 namespace tbb {
00070 
00071 template<typename T, class A = cache_aligned_allocator<T> >
00072 class concurrent_vector;
00073 
00075 namespace internal {
00076 
00078     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
00079 
00081     void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src );
00082 
00084 
00085     class concurrent_vector_base_v3 {
00086     protected:
00087 
00088         // Basic types declarations
00089         typedef size_t segment_index_t;
00090         typedef size_t size_type;
00091 
00092         // Using enumerations due to Mac linking problems of static const variables
00093         enum {
00094             // Size constants
00095             default_initial_segments = 1, // 2 initial items
00097             pointers_per_short_table = 3, // to fit into 8 words of entire structure
00098             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
00099         };
00100 
00101         // Segment pointer. Can be zero-initialized
00102         struct segment_t {
00103             void* array;
00104 #if TBB_USE_ASSERT
00105             ~segment_t() {
00106                 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
00107             }
00108 #endif /* TBB_USE_ASSERT */
00109         };
00110  
00111         // Data fields
00112 
00114         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
00115 
00117         atomic<size_type> my_first_block;
00118 
00120         atomic<size_type> my_early_size;
00121 
00123         atomic<segment_t*> my_segment;
00124 
00126         segment_t my_storage[pointers_per_short_table];
00127 
00128         // Methods
00129 
00130         concurrent_vector_base_v3() {
00131             my_early_size = 0;
00132             my_first_block = 0; // here is not default_initial_segments
00133             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
00134                 my_storage[i].array = NULL;
00135             my_segment = my_storage;
00136         }
00137         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
00138 
00139         static segment_index_t segment_index_of( size_type index ) {
00140             return segment_index_t( __TBB_Log2( index|1 ) );
00141         }
00142 
00143         static segment_index_t segment_base( segment_index_t k ) {
00144             return (segment_index_t(1)<<k & ~segment_index_t(1));
00145         }
00146 
00147         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
00148             segment_index_t k = segment_index_of( index );
00149             index -= segment_base(k);
00150             return k;
00151         }
00152 
00153         static size_type segment_size( segment_index_t k ) {
00154             return segment_index_t(1)<<k; // fake value for k==0
00155         }
00156 
00158         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
00159 
00161         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
00162 
00164         struct internal_segments_table {
00165             segment_index_t first_block;
00166             void* table[pointers_per_long_table];
00167         };
00168 
00169         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
00170         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
00171         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
00172         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
00173         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
00174         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
00175         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
00176         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
00177         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
00178                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
00180         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
00181         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
00182 
00183         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
00184                                                     internal_array_op1 destroy, internal_array_op2 init );
00185         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 );
00186 
00188         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
00189 private:
00191         class helper;
00192         friend class helper;
00193     };
00194     
00195     typedef concurrent_vector_base_v3 concurrent_vector_base;
00196 
00198 
00200     template<typename Container, typename Value>
00201     class vector_iterator 
00202     {
00204         Container* my_vector;
00205 
00207         size_t my_index;
00208 
00210 
00211         mutable Value* my_item;
00212 
00213         template<typename C, typename T>
00214         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
00215 
00216         template<typename C, typename T, typename U>
00217         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00218 
00219         template<typename C, typename T, typename U>
00220         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00221 
00222         template<typename C, typename T, typename U>
00223         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
00224     
00225         template<typename C, typename U>
00226         friend class internal::vector_iterator;
00227 
00228 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00229         template<typename T, class A>
00230         friend class tbb::concurrent_vector;
00231 #else
00232 public: // workaround for MSVC
00233 #endif 
00234 
00235         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) : 
00236             my_vector(const_cast<Container*>(&vector)), 
00237             my_index(index), 
00238             my_item(static_cast<Value*>(ptr))
00239         {}
00240 
00241     public:
00243         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
00244 
00245         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
00246             my_vector(other.my_vector),
00247             my_index(other.my_index),
00248             my_item(other.my_item)
00249         {}
00250 
00251         vector_iterator operator+( ptrdiff_t offset ) const {
00252             return vector_iterator( *my_vector, my_index+offset );
00253         }
00254         vector_iterator &operator+=( ptrdiff_t offset ) {
00255             my_index+=offset;
00256             my_item = NULL;
00257             return *this;
00258         }
00259         vector_iterator operator-( ptrdiff_t offset ) const {
00260             return vector_iterator( *my_vector, my_index-offset );
00261         }
00262         vector_iterator &operator-=( ptrdiff_t offset ) {
00263             my_index-=offset;
00264             my_item = NULL;
00265             return *this;
00266         }
00267         Value& operator*() const {
00268             Value* item = my_item;
00269             if( !item ) {
00270                 item = my_item = &my_vector->internal_subscript(my_index);
00271             }
00272             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
00273             return *item;
00274         }
00275         Value& operator[]( ptrdiff_t k ) const {
00276             return my_vector->internal_subscript(my_index+k);
00277         }
00278         Value* operator->() const {return &operator*();}
00279 
00281         vector_iterator& operator++() {
00282             size_t k = ++my_index;
00283             if( my_item ) {
00284                 // Following test uses 2's-complement wizardry
00285                 if( (k& (k-2))==0 ) {
00286                     // k is a power of two that is at least k-2
00287                     my_item= NULL;
00288                 } else {
00289                     ++my_item;
00290                 }
00291             }
00292             return *this;
00293         }
00294 
00296         vector_iterator& operator--() {
00297             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" ); 
00298             size_t k = my_index--;
00299             if( my_item ) {
00300                 // Following test uses 2's-complement wizardry
00301                 if( (k& (k-2))==0 ) {
00302                     // k is a power of two that is at least k-2  
00303                     my_item= NULL;
00304                 } else {
00305                     --my_item;
00306                 }
00307             }
00308             return *this;
00309         }
00310 
00312         vector_iterator operator++(int) {
00313             vector_iterator result = *this;
00314             operator++();
00315             return result;
00316         }
00317 
00319         vector_iterator operator--(int) {
00320             vector_iterator result = *this;
00321             operator--();
00322             return result;
00323         }
00324 
00325         // STL support
00326 
00327         typedef ptrdiff_t difference_type;
00328         typedef Value value_type;
00329         typedef Value* pointer;
00330         typedef Value& reference;
00331         typedef std::random_access_iterator_tag iterator_category;
00332     };
00333 
00334     template<typename Container, typename T>
00335     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
00336         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
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 && i.my_vector == j.my_vector;
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 !(i==j);
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.my_index<j.my_index;
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     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00361         return !(i<j);
00362     }
00363 
00364     template<typename Container, typename T, typename U>
00365     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00366         return !(j<i);
00367     }
00368 
00369     template<typename Container, typename T, typename U>
00370     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
00371         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
00372     }
00373 
00374     template<typename T, class A>
00375     class allocator_base {
00376     public:
00377         typedef typename A::template
00378             rebind<T>::other allocator_type;
00379         allocator_type my_allocator;
00380 
00381         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
00382     };
00383 
00384 } // namespace internal
00386 
00388 
00449 template<typename T, class A>
00450 class concurrent_vector: protected internal::allocator_base<T, A>,
00451                          private internal::concurrent_vector_base {
00452 private:
00453     template<typename I>
00454     class generic_range_type: public blocked_range<I> {
00455     public:
00456         typedef T value_type;
00457         typedef T& reference;
00458         typedef const T& const_reference;
00459         typedef I iterator;
00460         typedef ptrdiff_t difference_type;
00461         generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {} 
00462         template<typename U>
00463         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {} 
00464         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
00465     };
00466 
00467     template<typename C, typename U>
00468     friend class internal::vector_iterator;
00469 public:
00470     //------------------------------------------------------------------------
00471     // STL compatible types
00472     //------------------------------------------------------------------------
00473     typedef internal::concurrent_vector_base_v3::size_type size_type;
00474     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
00475 
00476     typedef T value_type;
00477     typedef ptrdiff_t difference_type;
00478     typedef T& reference;
00479     typedef const T& const_reference;
00480     typedef T *pointer;
00481     typedef const T *const_pointer;
00482 
00483     typedef internal::vector_iterator<concurrent_vector,T> iterator;
00484     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
00485 
00486 #if !defined(_MSC_VER) || _CPPLIB_VER>=300 
00487     // Assume ISO standard definition of std::reverse_iterator
00488     typedef std::reverse_iterator<iterator> reverse_iterator;
00489     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00490 #else
00491     // Use non-standard std::reverse_iterator
00492     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
00493     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
00494 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
00495 
00496     //------------------------------------------------------------------------
00497     // Parallel algorithm support
00498     //------------------------------------------------------------------------
00499     typedef generic_range_type<iterator> range_type;
00500     typedef generic_range_type<const_iterator> const_range_type;
00501 
00502     //------------------------------------------------------------------------
00503     // STL compatible constructors & destructors
00504     //------------------------------------------------------------------------
00505 
00507     explicit concurrent_vector(const allocator_type &a = allocator_type())
00508         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00509     {
00510         vector_allocator_ptr = &internal_allocator;
00511     }
00512 
00514     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
00515         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00516     {
00517         vector_allocator_ptr = &internal_allocator;
00518         __TBB_TRY {
00519             internal_copy(vector, sizeof(T), &copy_array);
00520         } __TBB_CATCH(...) {
00521             segment_t *table = my_segment;
00522             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00523             __TBB_RETHROW();
00524         }
00525     }
00526 
00528     template<class M>
00529     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
00530         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
00531     {
00532         vector_allocator_ptr = &internal_allocator;
00533         __TBB_TRY {
00534             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
00535         } __TBB_CATCH(...) {
00536             segment_t *table = my_segment;
00537             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00538             __TBB_RETHROW();
00539         }
00540     }
00541 
00543     explicit concurrent_vector(size_type n)
00544     {
00545         vector_allocator_ptr = &internal_allocator;
00546         __TBB_TRY {
00547             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00548         } __TBB_CATCH(...) {
00549             segment_t *table = my_segment;
00550             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00551             __TBB_RETHROW();
00552         }
00553     }
00554 
00556     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
00557         : internal::allocator_base<T, A>(a)
00558     {
00559         vector_allocator_ptr = &internal_allocator;
00560         __TBB_TRY {
00561             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00562         } __TBB_CATCH(...) {
00563             segment_t *table = my_segment;
00564             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00565             __TBB_RETHROW();
00566         }
00567     }
00568 
00570     template<class I>
00571     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
00572         : internal::allocator_base<T, A>(a)
00573     {
00574         vector_allocator_ptr = &internal_allocator;
00575         __TBB_TRY {
00576             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00577         } __TBB_CATCH(...) {
00578             segment_t *table = my_segment;
00579             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00580             __TBB_RETHROW();
00581         }
00582     }
00583 
00585     concurrent_vector& operator=( const concurrent_vector& vector ) {
00586         if( this != &vector )
00587             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
00588         return *this;
00589     }
00590 
00592     template<class M>
00593     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
00594         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
00595             internal_assign(vector.internal_vector_base(),
00596                 sizeof(T), &destroy_array, &assign_array, &copy_array);
00597         return *this;
00598     }
00599 
00600     //------------------------------------------------------------------------
00601     // Concurrent operations
00602     //------------------------------------------------------------------------
00604 #if TBB_DEPRECATED
00605 
00606     size_type grow_by( size_type delta ) {
00607         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
00608     }
00609 #else
00610 
00611     iterator grow_by( size_type delta ) {
00612         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
00613     }
00614 #endif
00615 
00617 #if TBB_DEPRECATED
00618 
00619     size_type grow_by( size_type delta, const_reference t ) {
00620         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
00621     }
00622 #else
00623 
00624     iterator grow_by( size_type delta, const_reference t ) {
00625         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
00626     }
00627 #endif
00628 
00630 #if TBB_DEPRECATED
00631 
00633     void grow_to_at_least( size_type n ) {
00634         if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00635     };
00636 #else
00637 
00641     iterator grow_to_at_least( size_type n ) {
00642         size_type m=0;
00643         if( n ) {
00644             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
00645             if( m>n ) m=n;
00646         }
00647         return iterator(*this, m);
00648     };
00649 #endif
00650 
00652 #if TBB_DEPRECATED
00653     size_type push_back( const_reference item )
00654 #else
00655 
00656     iterator push_back( const_reference item )
00657 #endif
00658     {
00659         size_type k;
00660         void *ptr = internal_push_back(sizeof(T),k);
00661         internal_loop_guide loop(1, ptr);
00662         loop.init(&item);
00663 #if TBB_DEPRECATED
00664         return k;
00665 #else
00666         return iterator(*this, k, ptr);
00667 #endif
00668     }
00669 
00671 
00673     reference operator[]( size_type index ) {
00674         return internal_subscript(index);
00675     }
00676 
00678     const_reference operator[]( size_type index ) const {
00679         return internal_subscript(index);
00680     }
00681 
00683     reference at( size_type index ) {
00684         return internal_subscript_with_exceptions(index);
00685     }
00686 
00688     const_reference at( size_type index ) const {
00689         return internal_subscript_with_exceptions(index);
00690     }
00691 
00693     range_type range( size_t grainsize = 1) {
00694         return range_type( begin(), end(), grainsize );
00695     }
00696 
00698     const_range_type range( size_t grainsize = 1 ) const {
00699         return const_range_type( begin(), end(), grainsize );
00700     }
00701     //------------------------------------------------------------------------
00702     // Capacity
00703     //------------------------------------------------------------------------
00705     size_type size() const {
00706         size_type sz = my_early_size, cp = internal_capacity();
00707         return cp < sz ? cp : sz;
00708     }
00709 
00711     bool empty() const {return !my_early_size;}
00712 
00714     size_type capacity() const {return internal_capacity();}
00715 
00717 
00719     void reserve( size_type n ) {
00720         if( n )
00721             internal_reserve(n, sizeof(T), max_size());
00722     }
00723 
00725     void resize( size_type n ) {
00726         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
00727     }
00728     
00730     void resize( size_type n, const_reference t ) {
00731         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00732     }
00733    
00734 #if TBB_DEPRECATED 
00735 
00736     void compact() {shrink_to_fit();}
00737 #endif /* TBB_DEPRECATED */
00738 
00740     void shrink_to_fit();
00741 
00743     size_type max_size() const {return (~size_type(0))/sizeof(T);}
00744 
00745     //------------------------------------------------------------------------
00746     // STL support
00747     //------------------------------------------------------------------------
00748 
00750     iterator begin() {return iterator(*this,0);}
00752     iterator end() {return iterator(*this,size());}
00754     const_iterator begin() const {return const_iterator(*this,0);}
00756     const_iterator end() const {return const_iterator(*this,size());}
00758     const_iterator cbegin() const {return const_iterator(*this,0);}
00760     const_iterator cend() const {return const_iterator(*this,size());}
00762     reverse_iterator rbegin() {return reverse_iterator(end());}
00764     reverse_iterator rend() {return reverse_iterator(begin());}
00766     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
00768     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
00770     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
00772     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
00774     reference front() {
00775         __TBB_ASSERT( size()>0, NULL);
00776         return static_cast<T*>(my_segment[0].array)[0];
00777     }
00779     const_reference front() const {
00780         __TBB_ASSERT( size()>0, NULL);
00781         return static_cast<const T*>(my_segment[0].array)[0];
00782     }
00784     reference back() {
00785         __TBB_ASSERT( size()>0, NULL);
00786         return internal_subscript( size()-1 );
00787     }
00789     const_reference back() const {
00790         __TBB_ASSERT( size()>0, NULL);
00791         return internal_subscript( size()-1 );
00792     }
00794     allocator_type get_allocator() const { return this->my_allocator; }
00795 
00797     void assign(size_type n, const_reference t) {
00798         clear();
00799         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
00800     }
00801 
00803     template<class I>
00804     void assign(I first, I last) {
00805         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
00806     }
00807 
00809     void swap(concurrent_vector &vector) {
00810         if( this != &vector ) {
00811             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
00812             std::swap(this->my_allocator, vector.my_allocator);
00813         }
00814     }
00815 
00817 
00818     void clear() {
00819         internal_clear(&destroy_array);
00820     }
00821 
00823     ~concurrent_vector() {
00824         segment_t *table = my_segment;
00825         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
00826         // base class destructor call should be then
00827     }
00828 
00829     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
00830 private:
00832     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
00833         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
00834     }
00836     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
00837 
00839     T& internal_subscript( size_type index ) const;
00840 
00842     T& internal_subscript_with_exceptions( size_type index ) const;
00843 
00845     void internal_assign_n(size_type n, const_pointer p) {
00846         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
00847     }
00848 
00850     template<bool B> class is_integer_tag;
00851 
00853     template<class I>
00854     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
00855         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
00856     }
00858     template<class I>
00859     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
00860         internal_assign_iterators(first, last);
00861     }
00863     template<class I>
00864     void internal_assign_iterators(I first, I last);
00865 
00867     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
00868 
00870     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
00871 
00873     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
00874 
00876     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
00877 
00879     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
00880 
00882     class internal_loop_guide : internal::no_copy {
00883     public:
00884         const pointer array;
00885         const size_type n;
00886         size_type i;
00887         internal_loop_guide(size_type ntrials, void *ptr)
00888             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
00889         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
00890         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
00891         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
00892         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
00893         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
00894         ~internal_loop_guide() {
00895             if(i < n) // if exception raised, do zerroing on the rest of items
00896                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
00897         }
00898     };
00899 };
00900 
00901 template<typename T, class A>
00902 void concurrent_vector<T, A>::shrink_to_fit() {
00903     internal_segments_table old;
00904     __TBB_TRY {
00905         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
00906             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
00907     } __TBB_CATCH(...) {
00908         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
00909             internal_free_segments( old.table, 1, old.first_block );
00910         __TBB_RETHROW();
00911     }
00912 }
00913 
00914 template<typename T, class A>
00915 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
00916     // Free the arrays
00917     while( k > first_block ) {
00918         --k;
00919         T* array = static_cast<T*>(table[k]);
00920         table[k] = NULL;
00921         if( array > internal::vector_allocation_error_flag ) // check for correct segment pointer
00922             this->my_allocator.deallocate( array, segment_size(k) );
00923     }
00924     T* array = static_cast<T*>(table[0]);
00925     if( array > internal::vector_allocation_error_flag ) {
00926         __TBB_ASSERT( first_block > 0, NULL );
00927         while(k > 0) table[--k] = NULL;
00928         this->my_allocator.deallocate( array, segment_size(first_block) );
00929     }
00930 }
00931 
00932 template<typename T, class A>
00933 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
00934     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
00935     size_type j = index;
00936     segment_index_t k = segment_base_index_of( j );
00937     __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
00938     // no need in __TBB_load_with_acquire since thread works in own space or gets 
00939 #if TBB_USE_THREADING_TOOLS
00940     T* array = static_cast<T*>( tbb::internal::itt_load_pointer_v3(&my_segment[k].array));
00941 #else
00942     T* array = static_cast<T*>(my_segment[k].array);
00943 #endif /* TBB_USE_THREADING_TOOLS */
00944     __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
00945     __TBB_ASSERT( array, "index is being allocated" );
00946     return array[j];
00947 }
00948 
00949 template<typename T, class A>
00950 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
00951     if( index >= my_early_size )
00952         internal::throw_exception(internal::eid_out_of_range); // throw std::out_of_range
00953     size_type j = index;
00954     segment_index_t k = segment_base_index_of( j );
00955     if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
00956         internal::throw_exception(internal::eid_segment_range_error); // throw std::range_error
00957     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
00958     if( array <= internal::vector_allocation_error_flag ) // check for correct segment pointer
00959         internal::throw_exception(internal::eid_index_range_error); // throw std::range_error
00960     return static_cast<T*>(array)[j];
00961 }
00962 
00963 template<typename T, class A> template<class I>
00964 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
00965     __TBB_ASSERT(my_early_size == 0, NULL);
00966     size_type n = std::distance(first, last);
00967     if( !n ) return;
00968     internal_reserve(n, sizeof(T), max_size());
00969     my_early_size = n;
00970     segment_index_t k = 0;
00971     size_type sz = segment_size( my_first_block );
00972     while( sz < n ) {
00973         internal_loop_guide loop(sz, my_segment[k].array);
00974         loop.iterate(first);
00975         n -= sz;
00976         if( !k ) k = my_first_block;
00977         else { ++k; sz <<= 1; }
00978     }
00979     internal_loop_guide loop(n, my_segment[k].array);
00980     loop.iterate(first);
00981 }
00982 
00983 template<typename T, class A>
00984 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
00985     internal_loop_guide loop(n, begin); loop.init();
00986 }
00987 
00988 template<typename T, class A>
00989 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
00990     internal_loop_guide loop(n, begin); loop.init(src);
00991 }
00992 
00993 template<typename T, class A>
00994 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
00995     internal_loop_guide loop(n, dst); loop.copy(src);
00996 }
00997 
00998 template<typename T, class A>
00999 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
01000     internal_loop_guide loop(n, dst); loop.assign(src);
01001 }
01002 
01003 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
01004     // Workaround for overzealous compiler warning
01005     #pragma warning (push)
01006     #pragma warning (disable: 4189)
01007 #endif
01008 template<typename T, class A>
01009 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
01010     T* array = static_cast<T*>(begin);
01011     for( size_type j=n; j>0; --j )
01012         array[j-1].~T(); // destructors are supposed to not throw any exceptions
01013 }
01014 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 
01015     #pragma warning (pop)
01016 #endif // warning 4189 is back 
01017 
01018 // concurrent_vector's template functions
01019 template<typename T, class A1, class A2>
01020 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
01021     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
01022     if(a.size() != b.size()) return false;
01023     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
01024     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
01025     for(; i != a.end(); ++i, ++j)
01026         if( !(*i == *j) ) return false;
01027     return true;
01028 }
01029 
01030 template<typename T, class A1, class A2>
01031 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01032 {    return !(a == b); }
01033 
01034 template<typename T, class A1, class A2>
01035 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01036 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
01037 
01038 template<typename T, class A1, class A2>
01039 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01040 {    return b < a; }
01041 
01042 template<typename T, class A1, class A2>
01043 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01044 {    return !(b < a); }
01045 
01046 template<typename T, class A1, class A2>
01047 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
01048 {    return !(a < b); }
01049 
01050 template<typename T, class A>
01051 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
01052 {    a.swap( b ); }
01053 
01054 } // namespace tbb
01055 
01056 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
01057     #pragma warning (pop)
01058 #endif // warning 4267 is back
01059 
01060 #endif /* __TBB_concurrent_vector_H */

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net