- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# concurrent_vector.h

    00001 /*
    00002     Copyright 2005-2012 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 "tbb_profiling.h"
    00039 #include <new>
    00040 #include <cstring>   // for memset()
    00041
    00042 #if !TBB_USE_EXCEPTIONS && _MSC_VER
    00043     // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers
    00044     #pragma warning (push)
    00045     #pragma warning (disable: 4530)
    00046 #endif
    00047
    00048 #include <algorithm>
    00049 #include <iterator>
    00050
    00051 #if !TBB_USE_EXCEPTIONS && _MSC_VER
    00052     #pragma warning (pop)
    00053 #endif
    00054
    00055 #if _MSC_VER==1500 && !__INTEL_COMPILER
    00056     // VS2008/VC9 seems to have an issue; limits pull in math.h
    00057     #pragma warning( push )
    00058     #pragma warning( disable: 4985 )
    00059 #endif
    00060 #include <limits> /* std::numeric_limits */
    00061 #if _MSC_VER==1500 && !__INTEL_COMPILER
    00062     #pragma warning( pop )
    00063 #endif
    00064
    00065 #if __TBB_INITIALIZER_LISTS_PRESENT
    00066     #include <initializer_list>
    00067 #endif
    00068
    00069 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
    00070     // Workaround for overzealous compiler warnings in /Wp64 mode
    00071     #pragma warning (push)
    00072     #pragma warning (disable: 4267)
    00073 #endif
    00074
    00075 namespace tbb {
    00076
    00077 template<typename T, class A = cache_aligned_allocator<T> >
    00078 class concurrent_vector;
    00079
    00081 namespace internal {
    00082
    00084     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
    00085
    00087
    00088     class concurrent_vector_base_v3 {
    00089     protected:
    00090
    00091         // Basic types declarations
    00092         typedef size_t segment_index_t;
    00093         typedef size_t size_type;
    00094
    00095         // Using enumerations due to Mac linking problems of static const variables
    00096         enum {
    00097             // Size constants
    00098             default_initial_segments = 1, // 2 initial items
    00100             pointers_per_short_table = 3, // to fit into 8 words of entire structure
    00101             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
    00102         };
    00103
    00104         // Segment pointer. Can be zero-initialized
    00105         struct segment_t {
    00106             void* array;
    00107 #if TBB_USE_ASSERT
    00108             ~segment_t() {
    00109                 __TBB_ASSERT( array <= internal::vector_allocation_error_flag, "should have been freed by clear" );
    00110             }
    00111 #endif /* TBB_USE_ASSERT */
    00112         };
    00113
    00114         // Data fields
    00115
    00117         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
    00118
    00120         atomic<size_type> my_first_block;
    00121
    00123         atomic<size_type> my_early_size;
    00124
    00126         atomic<segment_t*> my_segment;
    00127
    00129         segment_t my_storage[pointers_per_short_table];
    00130
    00131         // Methods
    00132
    00133         concurrent_vector_base_v3() {
    00134             my_early_size = 0;
    00135             my_first_block = 0; // here is not default_initial_segments
    00136             for( segment_index_t i = 0; i < pointers_per_short_table; i++)
    00137                 my_storage[i].array = NULL;
    00138             my_segment = my_storage;
    00139         }
    00140         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
    00141
    00142         static segment_index_t segment_index_of( size_type index ) {
    00143             return segment_index_t( __TBB_Log2( index|1 ) );
    00144         }
    00145
    00146         static segment_index_t segment_base( segment_index_t k ) {
    00147             return (segment_index_t(1)<<k & ~segment_index_t(1));
    00148         }
    00149
    00150         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
    00151             segment_index_t k = segment_index_of( index );
    00152             index -= segment_base(k);
    00153             return k;
    00154         }
    00155
    00156         static size_type segment_size( segment_index_t k ) {
    00157             return segment_index_t(1)<<k; // fake value for k==0
    00158         }
    00159
    00161         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
    00162
    00164         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
    00165
    00167         struct internal_segments_table {
    00168             segment_index_t first_block;
    00169             void* table[pointers_per_long_table];
    00170         };
    00171
    00172         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
    00173         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
    00174         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
    00175         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
    00176         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
    00177         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
    00178         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
    00179         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
    00180         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
    00181                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
    00183         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
    00184         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
    00185
    00186         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
    00187                                                     internal_array_op1 destroy, internal_array_op2 init );
    00188         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 );
    00189
    00191         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
    00192 private:
    00194         class helper;
    00195         friend class helper;
    00196     };
    00197
    00198     typedef concurrent_vector_base_v3 concurrent_vector_base;
    00199
    00201
    00203     template<typename Container, typename Value>
    00204     class vector_iterator
    00205     {
    00207         Container* my_vector;
    00208
    00210         size_t my_index;
    00211
    00213
    00214         mutable Value* my_item;
    00215
    00216         template<typename C, typename T>
    00217         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
    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 bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
    00224
    00225         template<typename C, typename T, typename U>
    00226         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
    00227
    00228         template<typename C, typename U>
    00229         friend class internal::vector_iterator;
    00230
    00231 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
    00232         template<typename T, class A>
    00233         friend class tbb::concurrent_vector;
    00234 #else
    00235 public: // workaround for MSVC
    00236 #endif
    00237
    00238         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
    00239             my_vector(const_cast<Container*>(&vector)),
    00240             my_index(index),
    00241             my_item(static_cast<Value*>(ptr))
    00242         {}
    00243
    00244     public:
    00246         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
    00247
    00248         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
    00249             my_vector(other.my_vector),
    00250             my_index(other.my_index),
    00251             my_item(other.my_item)
    00252         {}
    00253
    00254         vector_iterator operator+( ptrdiff_t offset ) const {
    00255             return vector_iterator( *my_vector, my_index+offset );
    00256         }
    00257         vector_iterator &operator+=( ptrdiff_t offset ) {
    00258             my_index+=offset;
    00259             my_item = NULL;
    00260             return *this;
    00261         }
    00262         vector_iterator operator-( ptrdiff_t offset ) const {
    00263             return vector_iterator( *my_vector, my_index-offset );
    00264         }
    00265         vector_iterator &operator-=( ptrdiff_t offset ) {
    00266             my_index-=offset;
    00267             my_item = NULL;
    00268             return *this;
    00269         }
    00270         Value& operator*() const {
    00271             Value* item = my_item;
    00272             if( !item ) {
    00273                 item = my_item = &my_vector->internal_subscript(my_index);
    00274             }
    00275             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
    00276             return *item;
    00277         }
    00278         Value& operator[]( ptrdiff_t k ) const {
    00279             return my_vector->internal_subscript(my_index+k);
    00280         }
    00281         Value* operator->() const {return &operator*();}
    00282
    00284         vector_iterator& operator++() {
    00285             size_t k = ++my_index;
    00286             if( my_item ) {
    00287                 // Following test uses 2's-complement wizardry
    00288                 if( (k& (k-2))==0 ) {
    00289                     // k is a power of two that is at least k-2
    00290                     my_item= NULL;
    00291                 } else {
    00292                     ++my_item;
    00293                 }
    00294             }
    00295             return *this;
    00296         }
    00297
    00299         vector_iterator& operator--() {
    00300             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
    00301             size_t k = my_index--;
    00302             if( my_item ) {
    00303                 // Following test uses 2's-complement wizardry
    00304                 if( (k& (k-2))==0 ) {
    00305                     // k is a power of two that is at least k-2
    00306                     my_item= NULL;
    00307                 } else {
    00308                     --my_item;
    00309                 }
    00310             }
    00311             return *this;
    00312         }
    00313
    00315         vector_iterator operator++(int) {
    00316             vector_iterator result = *this;
    00317             operator++();
    00318             return result;
    00319         }
    00320
    00322         vector_iterator operator--(int) {
    00323             vector_iterator result = *this;
    00324             operator--();
    00325             return result;
    00326         }
    00327
    00328         // STL support
    00329
    00330         typedef ptrdiff_t difference_type;
    00331         typedef Value value_type;
    00332         typedef Value* pointer;
    00333         typedef Value& reference;
    00334         typedef std::random_access_iterator_tag iterator_category;
    00335     };
    00336
    00337     template<typename Container, typename T>
    00338     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
    00339         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
    00340     }
    00341
    00342     template<typename Container, typename T, typename U>
    00343     bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00344         return i.my_index==j.my_index && i.my_vector == j.my_vector;
    00345     }
    00346
    00347     template<typename Container, typename T, typename U>
    00348     bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00349         return !(i==j);
    00350     }
    00351
    00352     template<typename Container, typename T, typename U>
    00353     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00354         return i.my_index<j.my_index;
    00355     }
    00356
    00357     template<typename Container, typename T, typename U>
    00358     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00359         return j<i;
    00360     }
    00361
    00362     template<typename Container, typename T, typename U>
    00363     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00364         return !(i<j);
    00365     }
    00366
    00367     template<typename Container, typename T, typename U>
    00368     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00369         return !(j<i);
    00370     }
    00371
    00372     template<typename Container, typename T, typename U>
    00373     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
    00374         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
    00375     }
    00376
    00377     template<typename T, class A>
    00378     class allocator_base {
    00379     public:
    00380         typedef typename A::template
    00381             rebind<T>::other allocator_type;
    00382         allocator_type my_allocator;
    00383
    00384         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
    00385     };
    00386
    00387 } // namespace internal
    00389
    00391
    00452 template<typename T, class A>
    00453 class concurrent_vector: protected internal::allocator_base<T, A>,
    00454                          private internal::concurrent_vector_base {
    00455 private:
    00456     template<typename I>
    00457     class generic_range_type: public blocked_range<I> {
    00458     public:
    00459         typedef T value_type;
    00460         typedef T& reference;
    00461         typedef const T& const_reference;
    00462         typedef I iterator;
    00463         typedef ptrdiff_t difference_type;
    00464         generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
    00465         template<typename U>
    00466         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
    00467         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
    00468     };
    00469
    00470     template<typename C, typename U>
    00471     friend class internal::vector_iterator;
    00472 public:
    00473     //------------------------------------------------------------------------
    00474     // STL compatible types
    00475     //------------------------------------------------------------------------
    00476     typedef internal::concurrent_vector_base_v3::size_type size_type;
    00477     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
    00478
    00479     typedef T value_type;
    00480     typedef ptrdiff_t difference_type;
    00481     typedef T& reference;
    00482     typedef const T& const_reference;
    00483     typedef T *pointer;
    00484     typedef const T *const_pointer;
    00485
    00486     typedef internal::vector_iterator<concurrent_vector,T> iterator;
    00487     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
    00488
    00489 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
    00490     // Assume ISO standard definition of std::reverse_iterator
    00491     typedef std::reverse_iterator<iterator> reverse_iterator;
    00492     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    00493 #else
    00494     // Use non-standard std::reverse_iterator
    00495     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
    00496     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
    00497 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
    00498
    00499     //------------------------------------------------------------------------
    00500     // Parallel algorithm support
    00501     //------------------------------------------------------------------------
    00502     typedef generic_range_type<iterator> range_type;
    00503     typedef generic_range_type<const_iterator> const_range_type;
    00504
    00505     //------------------------------------------------------------------------
    00506     // STL compatible constructors & destructors
    00507     //------------------------------------------------------------------------
    00508
    00510     explicit concurrent_vector(const allocator_type &a = allocator_type())
    00511         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00512     {
    00513         vector_allocator_ptr = &internal_allocator;
    00514     }
    00515
    00516 #if __TBB_INITIALIZER_LISTS_PRESENT
    00518     concurrent_vector(std::initializer_list<T> init_list, const allocator_type &a = allocator_type())
    00519         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00520     {
    00521         vector_allocator_ptr = &internal_allocator;
    00522         __TBB_TRY {
    00523             internal_assign_iterators(init_list.begin(), init_list.end());
    00524         } __TBB_CATCH(...) {
    00525             segment_t *table = my_segment;
    00526             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00527             __TBB_RETHROW();
    00528         }
    00529
    00530     }
    00531 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
    00532
    00534     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
    00535         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00536     {
    00537         vector_allocator_ptr = &internal_allocator;
    00538         __TBB_TRY {
    00539             internal_copy(vector, sizeof(T), &copy_array);
    00540         } __TBB_CATCH(...) {
    00541             segment_t *table = my_segment;
    00542             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00543             __TBB_RETHROW();
    00544         }
    00545     }
    00546
    00548     template<class M>
    00549     concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
    00550         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
    00551     {
    00552         vector_allocator_ptr = &internal_allocator;
    00553         __TBB_TRY {
    00554             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
    00555         } __TBB_CATCH(...) {
    00556             segment_t *table = my_segment;
    00557             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00558             __TBB_RETHROW();
    00559         }
    00560     }
    00561
    00563     explicit concurrent_vector(size_type n)
    00564     {
    00565         vector_allocator_ptr = &internal_allocator;
    00566         __TBB_TRY {
    00567             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
    00568         } __TBB_CATCH(...) {
    00569             segment_t *table = my_segment;
    00570             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00571             __TBB_RETHROW();
    00572         }
    00573     }
    00574
    00576     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
    00577         : internal::allocator_base<T, A>(a)
    00578     {
    00579         vector_allocator_ptr = &internal_allocator;
    00580         __TBB_TRY {
    00581             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00582         } __TBB_CATCH(...) {
    00583             segment_t *table = my_segment;
    00584             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00585             __TBB_RETHROW();
    00586         }
    00587     }
    00588
    00590     template<class I>
    00591     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
    00592         : internal::allocator_base<T, A>(a)
    00593     {
    00594         vector_allocator_ptr = &internal_allocator;
    00595         __TBB_TRY {
    00596             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
    00597         } __TBB_CATCH(...) {
    00598             segment_t *table = my_segment;
    00599             internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00600             __TBB_RETHROW();
    00601         }
    00602     }
    00603
    00605     concurrent_vector& operator=( const concurrent_vector& vector ) {
    00606         if( this != &vector )
    00607             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
    00608         return *this;
    00609     }
    00610
    00611     //TODO: add an template assignment operator? (i.e. with different element type)
    00612
    00614     template<class M>
    00615     concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
    00616         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
    00617             internal_assign(vector.internal_vector_base(),
    00618                 sizeof(T), &destroy_array, &assign_array, &copy_array);
    00619         return *this;
    00620     }
    00621
    00622 #if __TBB_INITIALIZER_LISTS_PRESENT
    00624     concurrent_vector& operator=( const std::initializer_list<T> & init_list) {
    00625         internal_clear(&destroy_array);
    00626         internal_assign_iterators(init_list.begin(), init_list.end());
    00627         return *this;
    00628     }
    00629 #endif //#if __TBB_INITIALIZER_LISTS_PRESENT
    00630
    00631     //------------------------------------------------------------------------
    00632     // Concurrent operations
    00633     //------------------------------------------------------------------------
    00634     //TODO: consider adding overload of grow_by accepting range of iterators:  grow_by(iterator,iterator)
    00635     //TODO: consider adding overload of grow_by accepting initializer_list:  grow_by(std::initializer_list<T>), as a analogy to std::vector::insert(initializer_list)
    00637 #if TBB_DEPRECATED
    00638
    00639     size_type grow_by( size_type delta ) {
    00640         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size;
    00641     }
    00642 #else
    00643
    00644     iterator grow_by( size_type delta ) {
    00645         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size);
    00646     }
    00647 #endif
    00648
    00650 #if TBB_DEPRECATED
    00651
    00652     size_type grow_by( size_type delta, const_reference t ) {
    00653         return delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size;
    00654     }
    00655 #else
    00656
    00657     iterator grow_by( size_type delta, const_reference t ) {
    00658         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size);
    00659     }
    00660 #endif
    00661
    00663 #if TBB_DEPRECATED
    00664
    00666     void grow_to_at_least( size_type n ) {
    00667         if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
    00668     };
    00669 #else
    00670
    00674     iterator grow_to_at_least( size_type n ) {
    00675         size_type m=0;
    00676         if( n ) {
    00677             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
    00678             if( m>n ) m=n;
    00679         }
    00680         return iterator(*this, m);
    00681     };
    00682 #endif
    00683
    00685 #if TBB_DEPRECATED
    00686     size_type push_back( const_reference item )
    00687 #else
    00688
    00689     iterator push_back( const_reference item )
    00690 #endif
    00691     {
    00692         size_type k;
    00693         void *ptr = internal_push_back(sizeof(T),k);
    00694         internal_loop_guide loop(1, ptr);
    00695         loop.init(&item);
    00696 #if TBB_DEPRECATED
    00697         return k;
    00698 #else
    00699         return iterator(*this, k, ptr);
    00700 #endif
    00701     }
    00702
    00704
    00706     reference operator[]( size_type index ) {
    00707         return internal_subscript(index);
    00708     }
    00709
    00711     const_reference operator[]( size_type index ) const {
    00712         return internal_subscript(index);
    00713     }
    00714
    00716     reference at( size_type index ) {
    00717         return internal_subscript_with_exceptions(index);
    00718     }
    00719
    00721     const_reference at( size_type index ) const {
    00722         return internal_subscript_with_exceptions(index);
    00723     }
    00724
    00726     range_type range( size_t grainsize = 1 ) {
    00727         return range_type( begin(), end(), grainsize );
    00728     }
    00729
    00731     const_range_type range( size_t grainsize = 1 ) const {
    00732         return const_range_type( begin(), end(), grainsize );
    00733     }
    00734
    00735     //------------------------------------------------------------------------
    00736     // Capacity
    00737     //------------------------------------------------------------------------
    00739     size_type size() const {
    00740         size_type sz = my_early_size, cp = internal_capacity();
    00741         return cp < sz ? cp : sz;
    00742     }
    00743
    00745     bool empty() const {return !my_early_size;}
    00746
    00748     size_type capacity() const {return internal_capacity();}
    00749
    00751
    00753     void reserve( size_type n ) {
    00754         if( n )
    00755             internal_reserve(n, sizeof(T), max_size());
    00756     }
    00757
    00759     void resize( size_type n ) {
    00760         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
    00761     }
    00762
    00764     void resize( size_type n, const_reference t ) {
    00765         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00766     }
    00767
    00768 #if TBB_DEPRECATED
    00770     void compact() {shrink_to_fit();}
    00771 #endif /* TBB_DEPRECATED */
    00772
    00774     void shrink_to_fit();
    00775
    00777     size_type max_size() const {return (~size_type(0))/sizeof(T);}
    00778
    00779     //------------------------------------------------------------------------
    00780     // STL support
    00781     //------------------------------------------------------------------------
    00782
    00784     iterator begin() {return iterator(*this,0);}
    00786     iterator end() {return iterator(*this,size());}
    00788     const_iterator begin() const {return const_iterator(*this,0);}
    00790     const_iterator end() const {return const_iterator(*this,size());}
    00792     const_iterator cbegin() const {return const_iterator(*this,0);}
    00794     const_iterator cend() const {return const_iterator(*this,size());}
    00796     reverse_iterator rbegin() {return reverse_iterator(end());}
    00798     reverse_iterator rend() {return reverse_iterator(begin());}
    00800     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
    00802     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
    00804     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
    00806     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
    00808     reference front() {
    00809         __TBB_ASSERT( size()>0, NULL);
    00810         return static_cast<T*>(my_segment[0].array)[0];
    00811     }
    00813     const_reference front() const {
    00814         __TBB_ASSERT( size()>0, NULL);
    00815         return static_cast<const T*>(my_segment[0].array)[0];
    00816     }
    00818     reference back() {
    00819         __TBB_ASSERT( size()>0, NULL);
    00820         return internal_subscript( size()-1 );
    00821     }
    00823     const_reference back() const {
    00824         __TBB_ASSERT( size()>0, NULL);
    00825         return internal_subscript( size()-1 );
    00826     }
    00828     allocator_type get_allocator() const { return this->my_allocator; }
    00829
    00831     void assign(size_type n, const_reference t) {
    00832         clear();
    00833         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
    00834     }
    00835
    00837     template<class I>
    00838     void assign(I first, I last) {
    00839         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
    00840     }
    00841
    00842 #if __TBB_INITIALIZER_LISTS_PRESENT
    00844     void assign(std::initializer_list<T> init_list) {
    00845         clear(); internal_assign_iterators( init_list.begin(), init_list.end());
    00846     }
    00847 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
    00848
    00850     void swap(concurrent_vector &vector) {
    00851         if( this != &vector ) {
    00852             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
    00853             std::swap(this->my_allocator, vector.my_allocator);
    00854         }
    00855     }
    00856
    00858
    00859     void clear() {
    00860         internal_clear(&destroy_array);
    00861     }
    00862
    00864     ~concurrent_vector() {
    00865         segment_t *table = my_segment;
    00866         internal_free_segments( reinterpret_cast<void**>(table), internal_clear(&destroy_array), my_first_block );
    00867         // base class destructor call should be then
    00868     }
    00869
    00870     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
    00871 private:
    00873     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
    00874         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
    00875     }
    00877     void internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block);
    00878
    00880     T& internal_subscript( size_type index ) const;
    00881
    00883     T& internal_subscript_with_exceptions( size_type index ) const;
    00884
    00886     void internal_assign_n(size_type n, const_pointer p) {
    00887         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
    00888     }
    00889
    00891     template<bool B> class is_integer_tag;
    00892
    00894     template<class I>
    00895     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
    00896         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
    00897     }
    00899     template<class I>
    00900     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
    00901         internal_assign_iterators(first, last);
    00902     }
    00904     template<class I>
    00905     void internal_assign_iterators(I first, I last);
    00906
    00908     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
    00909
    00911     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
    00912
    00914     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
    00915
    00917     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
    00918
    00920     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
    00921
    00923     class internal_loop_guide : internal::no_copy {
    00924     public:
    00925         const pointer array;
    00926         const size_type n;
    00927         size_type i;
    00928         internal_loop_guide(size_type ntrials, void *ptr)
    00929             : array(static_cast<pointer>(ptr)), n(ntrials), i(0) {}
    00930         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
    00931         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*static_cast<const T*>(src)); }
    00932         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(static_cast<const T*>(src)[i]); }
    00933         void assign(const void *src) { for(; i < n; ++i) array[i] = static_cast<const T*>(src)[i]; }
    00934         //TODO: rename to construct_range
    00935         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
    00936         ~internal_loop_guide() {
    00937             if(i < n) // if exception raised, do zeroing on the rest of items
    00938                 std::memset(array+i, 0, (n-i)*sizeof(value_type));
    00939         }
    00940     };
    00941 };
    00942
    00943 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    00944 #pragma warning (push)
    00945 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
    00946 #endif
    00947 template<typename T, class A>
    00948 void concurrent_vector<T, A>::shrink_to_fit() {
    00949     internal_segments_table old;
    00950     __TBB_TRY {
    00951         if( internal_compact( sizeof(T), &old, &destroy_array, &copy_array ) )
    00952             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
    00953     } __TBB_CATCH(...) {
    00954         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
    00955             internal_free_segments( old.table, 1, old.first_block );
    00956         __TBB_RETHROW();
    00957     }
    00958 }
    00959 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    00960 #pragma warning (pop)
    00961 #endif // warning 4701 is back
    00962
    00963 template<typename T, class A>
    00964 void concurrent_vector<T, A>::internal_free_segments(void *table[], segment_index_t k, segment_index_t first_block) {
    00965     // Free the arrays
    00966     while( k > first_block ) {
    00967         --k;
    00968         T* array = static_cast<T*>(table[k]);
    00969         table[k] = NULL;
    00970         if( array > internal::vector_allocation_error_flag ) // check for correct segment pointer
    00971             this->my_allocator.deallocate( array, segment_size(k) );
    00972     }
    00973     T* array = static_cast<T*>(table[0]);
    00974     if( array > internal::vector_allocation_error_flag ) {
    00975         __TBB_ASSERT( first_block > 0, NULL );
    00976         while(k > 0) table[--k] = NULL;
    00977         this->my_allocator.deallocate( array, segment_size(first_block) );
    00978     }
    00979 }
    00980
    00981 template<typename T, class A>
    00982 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
    00983     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
    00984     size_type j = index;
    00985     segment_index_t k = segment_base_index_of( j );
    00986     __TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_short_table, "index is being allocated" );
    00987     // no need in __TBB_load_with_acquire since thread works in own space or gets
    00988     T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segment[k].array));
    00989     __TBB_ASSERT( array != internal::vector_allocation_error_flag, "the instance is broken by bad allocation. Use at() instead" );
    00990     __TBB_ASSERT( array, "index is being allocated" );
    00991     return array[j];
    00992 }
    00993
    00994 template<typename T, class A>
    00995 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
    00996     if( index >= my_early_size )
    00997         internal::throw_exception(internal::eid_out_of_range); // throw std::out_of_range
    00998     size_type j = index;
    00999     segment_index_t k = segment_base_index_of( j );
    01000     if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_table )
    01001         internal::throw_exception(internal::eid_segment_range_error); // throw std::range_error
    01002     void *array = my_segment[k].array; // no need in __TBB_load_with_acquire
    01003     if( array <= internal::vector_allocation_error_flag ) // check for correct segment pointer
    01004         internal::throw_exception(internal::eid_index_range_error); // throw std::range_error
    01005     return static_cast<T*>(array)[j];
    01006 }
    01007
    01008 template<typename T, class A> template<class I>
    01009 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
    01010     __TBB_ASSERT(my_early_size == 0, NULL);
    01011     size_type n = std::distance(first, last);
    01012     if( !n ) return;
    01013     internal_reserve(n, sizeof(T), max_size());
    01014     my_early_size = n;
    01015     segment_index_t k = 0;
    01016     size_type sz = segment_size( my_first_block );
    01017     while( sz < n ) {
    01018         internal_loop_guide loop(sz, my_segment[k].array);
    01019         loop.iterate(first);
    01020         n -= sz;
    01021         if( !k ) k = my_first_block;
    01022         else { ++k; sz <<= 1; }
    01023     }
    01024     internal_loop_guide loop(n, my_segment[k].array);
    01025     loop.iterate(first);
    01026 }
    01027
    01028 template<typename T, class A>
    01029 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
    01030     internal_loop_guide loop(n, begin); loop.init();
    01031 }
    01032
    01033 template<typename T, class A>
    01034 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
    01035     internal_loop_guide loop(n, begin); loop.init(src);
    01036 }
    01037
    01038 template<typename T, class A>
    01039 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
    01040     internal_loop_guide loop(n, dst); loop.copy(src);
    01041 }
    01042
    01043 template<typename T, class A>
    01044 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
    01045     internal_loop_guide loop(n, dst); loop.assign(src);
    01046 }
    01047
    01048 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    01049     // Workaround for overzealous compiler warning
    01050     #pragma warning (push)
    01051     #pragma warning (disable: 4189)
    01052 #endif
    01053 template<typename T, class A>
    01054 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
    01055     T* array = static_cast<T*>(begin);
    01056     for( size_type j=n; j>0; --j )
    01057         array[j-1].~T(); // destructors are supposed to not throw any exceptions
    01058 }
    01059 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
    01060     #pragma warning (pop)
    01061 #endif // warning 4189 is back
    01062
    01063 // concurrent_vector's template functions
    01064 template<typename T, class A1, class A2>
    01065 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
    01066     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
    01067     if(a.size() != b.size()) return false;
    01068     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
    01069     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
    01070     for(; i != a.end(); ++i, ++j)
    01071         if( !(*i == *j) ) return false;
    01072     return true;
    01073 }
    01074
    01075 template<typename T, class A1, class A2>
    01076 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01077 {    return !(a == b); }
    01078
    01079 template<typename T, class A1, class A2>
    01080 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01081 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
    01082
    01083 template<typename T, class A1, class A2>
    01084 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01085 {    return b < a; }
    01086
    01087 template<typename T, class A1, class A2>
    01088 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01089 {    return !(b < a); }
    01090
    01091 template<typename T, class A1, class A2>
    01092 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
    01093 {    return !(a < b); }
    01094
    01095 template<typename T, class A>
    01096 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
    01097 {    a.swap( b ); }
    01098
    01099 } // namespace tbb
    01100
    01101 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_Wp64)
    01102     #pragma warning (pop)
    01103 #endif // warning 4267 is back
    01104
    01105 #endif /* __TBB_concurrent_vector_H */

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