Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:54

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #ifndef __TBB_concurrent_vector_H
0018 #define __TBB_concurrent_vector_H
0019 
0020 #define __TBB_concurrent_vector_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022 
0023 #include "tbb_stddef.h"
0024 #include "tbb_exception.h"
0025 #include "atomic.h"
0026 #include "cache_aligned_allocator.h"
0027 #include "blocked_range.h"
0028 #include "tbb_machine.h"
0029 #include "tbb_profiling.h"
0030 #include <new>
0031 #include <cstring>   // for memset()
0032 #include __TBB_STD_SWAP_HEADER
0033 #include <algorithm>
0034 #include <iterator>
0035 
0036 #include "internal/_allocator_traits.h"
0037 
0038 #if _MSC_VER==1500 && !__INTEL_COMPILER
0039     // VS2008/VC9 seems to have an issue; limits pull in math.h
0040     #pragma warning( push )
0041     #pragma warning( disable: 4985 )
0042 #endif
0043 #include <limits> /* std::numeric_limits */
0044 #if _MSC_VER==1500 && !__INTEL_COMPILER
0045     #pragma warning( pop )
0046 #endif
0047 
0048 #if __TBB_INITIALIZER_LISTS_PRESENT
0049     #include <initializer_list>
0050 #endif
0051 
0052 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
0053     // Workaround for overzealous compiler warnings in /Wp64 mode
0054     #pragma warning (push)
0055 #if defined(_Wp64)
0056     #pragma warning (disable: 4267)
0057 #endif
0058     #pragma warning (disable: 4127) //warning C4127: conditional expression is constant
0059 #endif
0060 
0061 namespace tbb {
0062 
0063 template<typename T, class A = cache_aligned_allocator<T> >
0064 class concurrent_vector;
0065 
0066 //! @cond INTERNAL
0067 namespace internal {
0068 
0069     template<typename Container, typename Value>
0070     class vector_iterator;
0071 
0072     //! Bad allocation marker
0073     static void *const vector_allocation_error_flag = reinterpret_cast<void*>(size_t(63));
0074 
0075     //! Exception helper function
0076     template<typename T>
0077     void handle_unconstructed_elements(T* array, size_t n_of_elements){
0078         std::memset( static_cast<void*>(array), 0, n_of_elements * sizeof( T ) );
0079     }
0080 
0081     //! Base class of concurrent vector implementation.
0082     /** @ingroup containers */
0083     class concurrent_vector_base_v3 {
0084     protected:
0085 
0086         // Basic types declarations
0087         typedef size_t segment_index_t;
0088         typedef size_t size_type;
0089 
0090         // Using enumerations due to Mac linking problems of static const variables
0091         enum {
0092             // Size constants
0093             default_initial_segments = 1, // 2 initial items
0094             //! Number of slots for segment pointers inside the class
0095             pointers_per_short_table = 3, // to fit into 8 words of entire structure
0096             pointers_per_long_table = sizeof(segment_index_t) * 8 // one segment per bit
0097         };
0098 
0099         struct segment_not_used {};
0100         struct segment_allocated {};
0101         struct segment_allocation_failed {};
0102 
0103         class segment_t;
0104         class segment_value_t {
0105             void* array;
0106         private:
0107             //TODO: More elegant way to grant access to selected functions _only_?
0108             friend class segment_t;
0109             explicit segment_value_t(void* an_array):array(an_array) {}
0110         public:
0111             friend bool operator==(segment_value_t const& lhs, segment_not_used ) { return lhs.array == 0;}
0112             friend bool operator==(segment_value_t const& lhs, segment_allocated) { return lhs.array > internal::vector_allocation_error_flag;}
0113             friend bool operator==(segment_value_t const& lhs, segment_allocation_failed) { return lhs.array == internal::vector_allocation_error_flag;}
0114             template<typename argument_type>
0115             friend bool operator!=(segment_value_t const& lhs, argument_type arg) { return ! (lhs == arg);}
0116 
0117             template<typename T>
0118             T* pointer() const {  return static_cast<T*>(const_cast<void*>(array)); }
0119         };
0120 
0121         friend void enforce_segment_allocated(segment_value_t const& s, internal::exception_id exception = eid_bad_last_alloc){
0122             if(s != segment_allocated()){
0123                 internal::throw_exception(exception);
0124             }
0125         }
0126 
0127         // Segment pointer.
0128         class segment_t {
0129             atomic<void*> array;
0130         public:
0131             segment_t(){ store<relaxed>(segment_not_used());}
0132             //Copy ctor and assignment operator are defined to ease using of stl algorithms.
0133             //These algorithms usually not a synchronization point, so, semantic is
0134             //intentionally relaxed here.
0135             segment_t(segment_t const& rhs ){ array.store<relaxed>(rhs.array.load<relaxed>());}
0136 
0137             void swap(segment_t & rhs ){
0138                 tbb::internal::swap<relaxed>(array, rhs.array);
0139             }
0140 
0141             segment_t& operator=(segment_t const& rhs ){
0142                 array.store<relaxed>(rhs.array.load<relaxed>());
0143                 return *this;
0144             }
0145 
0146             template<memory_semantics M>
0147             segment_value_t load() const { return segment_value_t(array.load<M>());}
0148 
0149             template<memory_semantics M>
0150             void store(segment_not_used) {
0151                 array.store<M>(0);
0152             }
0153 
0154             template<memory_semantics M>
0155             void store(segment_allocation_failed) {
0156                 __TBB_ASSERT(load<relaxed>() != segment_allocated(),"transition from \"allocated\" to \"allocation failed\" state looks non-logical");
0157                 array.store<M>(internal::vector_allocation_error_flag);
0158             }
0159 
0160             template<memory_semantics M>
0161             void store(void* allocated_segment_pointer) __TBB_NOEXCEPT(true) {
0162                 __TBB_ASSERT(segment_value_t(allocated_segment_pointer) == segment_allocated(),
0163                      "other overloads of store should be used for marking segment as not_used or allocation_failed" );
0164                 array.store<M>(allocated_segment_pointer);
0165             }
0166 
0167 #if TBB_USE_ASSERT
0168             ~segment_t() {
0169                 __TBB_ASSERT(load<relaxed>() != segment_allocated(), "should have been freed by clear" );
0170             }
0171 #endif /* TBB_USE_ASSERT */
0172         };
0173         friend void swap(segment_t & , segment_t & ) __TBB_NOEXCEPT(true);
0174 
0175         // Data fields
0176 
0177         //! allocator function pointer
0178         void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t);
0179 
0180         //! count of segments in the first block
0181         atomic<size_type> my_first_block;
0182 
0183         //! Requested size of vector
0184         atomic<size_type> my_early_size;
0185 
0186         //! Pointer to the segments table
0187         atomic<segment_t*> my_segment;
0188 
0189         //! embedded storage of segment pointers
0190         segment_t my_storage[pointers_per_short_table];
0191 
0192         // Methods
0193 
0194         concurrent_vector_base_v3() {
0195             //Here the semantic is intentionally relaxed.
0196             //The reason this is next:
0197             //Object that is in middle of construction (i.e. its constructor is not yet finished)
0198             //cannot be used concurrently until the construction is finished.
0199             //Thus to flag other threads that construction is finished, some synchronization with
0200             //acquire-release semantic should be done by the (external) code that uses the vector.
0201             //So, no need to do the synchronization inside the vector.
0202 
0203             my_early_size.store<relaxed>(0);
0204             my_first_block.store<relaxed>(0); // here is not default_initial_segments
0205             my_segment.store<relaxed>(my_storage);
0206         }
0207 
0208         __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3();
0209 
0210         //these helpers methods use the fact that segments are allocated so
0211         //that every segment size is a (increasing) power of 2.
0212         //with one exception 0 segment has size of 2 as well segment 1;
0213         //e.g. size of segment with index of 3 is 2^3=8;
0214         static segment_index_t segment_index_of( size_type index ) {
0215             return segment_index_t( __TBB_Log2( index|1 ) );
0216         }
0217 
0218         static segment_index_t segment_base( segment_index_t k ) {
0219             return (segment_index_t(1)<<k & ~segment_index_t(1));
0220         }
0221 
0222         static inline segment_index_t segment_base_index_of( segment_index_t &index ) {
0223             segment_index_t k = segment_index_of( index );
0224             index -= segment_base(k);
0225             return k;
0226         }
0227 
0228         static size_type segment_size( segment_index_t k ) {
0229             return segment_index_t(1)<<k; // fake value for k==0
0230         }
0231 
0232 
0233         static bool is_first_element_in_segment(size_type element_index){
0234             //check if element_index is a power of 2 that is at least 2.
0235             //The idea is to detect if the iterator crosses a segment boundary,
0236             //and 2 is the minimal index for which it's true
0237             __TBB_ASSERT(element_index, "there should be no need to call "
0238                                         "is_first_element_in_segment for 0th element" );
0239             return is_power_of_two_at_least( element_index, 2 );
0240         }
0241 
0242         //! An operation on an n-element array starting at begin.
0243         typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n );
0244 
0245         //! An operation on n-element destination array and n-element source array.
0246         typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, const void* src, size_type n );
0247 
0248         //! Internal structure for compact()
0249         struct internal_segments_table {
0250             segment_index_t first_block;
0251             segment_t table[pointers_per_long_table];
0252         };
0253 
0254         void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size );
0255         size_type __TBB_EXPORTED_METHOD internal_capacity() const;
0256         void internal_grow( size_type start, size_type finish, size_type element_size, internal_array_op2 init, const void *src );
0257         size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src );
0258         void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_size, size_type& index );
0259         segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_array_op1 destroy );
0260         void* __TBB_EXPORTED_METHOD internal_compact( size_type element_size, void *table, internal_array_op1 destroy, internal_array_op2 copy );
0261         void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_base_v3& src, size_type element_size, internal_array_op2 copy );
0262         void __TBB_EXPORTED_METHOD internal_assign( const concurrent_vector_base_v3& src, size_type element_size,
0263                               internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy );
0264         //! Obsolete
0265         void __TBB_EXPORTED_METHOD internal_throw_exception(size_type) const;
0266         void __TBB_EXPORTED_METHOD internal_swap(concurrent_vector_base_v3& v);
0267 
0268         void __TBB_EXPORTED_METHOD internal_resize( size_type n, size_type element_size, size_type max_size, const void *src,
0269                                                     internal_array_op1 destroy, internal_array_op2 init );
0270         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 );
0271 
0272         //! Deprecated entry point for backwards compatibility to TBB 2.1.
0273         void __TBB_EXPORTED_METHOD internal_grow_to_at_least( size_type new_size, size_type element_size, internal_array_op2 init, const void *src );
0274 private:
0275         //! Private functionality
0276         class helper;
0277         friend class helper;
0278 
0279         template<typename Container, typename Value>
0280         friend class vector_iterator;
0281 
0282     };
0283 
0284     inline void swap(concurrent_vector_base_v3::segment_t & lhs, concurrent_vector_base_v3::segment_t & rhs) __TBB_NOEXCEPT(true) {
0285         lhs.swap(rhs);
0286     }
0287 
0288     typedef concurrent_vector_base_v3 concurrent_vector_base;
0289 
0290     //! Meets requirements of a forward iterator for STL and a Value for a blocked_range.*/
0291     /** Value is either the T or const T type of the container.
0292         @ingroup containers */
0293     template<typename Container, typename Value>
0294     class vector_iterator
0295     {
0296         //! concurrent_vector over which we are iterating.
0297         Container* my_vector;
0298 
0299         //! Index into the vector
0300         size_t my_index;
0301 
0302         //! Caches my_vector-&gt;internal_subscript(my_index)
0303         /** NULL if cached value is not available */
0304         mutable Value* my_item;
0305 
0306         template<typename C, typename T>
0307         friend vector_iterator<C,T> operator+( ptrdiff_t offset, const vector_iterator<C,T>& v );
0308 
0309         template<typename C, typename T, typename U>
0310         friend bool operator==( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0311 
0312         template<typename C, typename T, typename U>
0313         friend bool operator<( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0314 
0315         template<typename C, typename T, typename U>
0316         friend ptrdiff_t operator-( const vector_iterator<C,T>& i, const vector_iterator<C,U>& j );
0317 
0318         template<typename C, typename U>
0319         friend class internal::vector_iterator;
0320 
0321 #if !__TBB_TEMPLATE_FRIENDS_BROKEN
0322         template<typename T, class A>
0323         friend class tbb::concurrent_vector;
0324 #else
0325 public:
0326 #endif
0327 
0328         vector_iterator( const Container& vector, size_t index, void *ptr = 0 ) :
0329             my_vector(const_cast<Container*>(&vector)),
0330             my_index(index),
0331             my_item(static_cast<Value*>(ptr))
0332         {}
0333 
0334     public:
0335         //! Default constructor
0336         vector_iterator() : my_vector(NULL), my_index(~size_t(0)), my_item(NULL) {}
0337 
0338         vector_iterator( const vector_iterator<Container,typename Container::value_type>& other ) :
0339             my_vector(other.my_vector),
0340             my_index(other.my_index),
0341             my_item(other.my_item)
0342         {}
0343 
0344         vector_iterator& operator=( const vector_iterator<Container,typename Container::value_type>& other )
0345         {
0346             my_vector=other.my_vector;
0347             my_index=other.my_index;
0348             my_item=other.my_item;
0349             return *this;
0350         }
0351 
0352         vector_iterator operator+( ptrdiff_t offset ) const {
0353             return vector_iterator( *my_vector, my_index+offset );
0354         }
0355         vector_iterator &operator+=( ptrdiff_t offset ) {
0356             my_index+=offset;
0357             my_item = NULL;
0358             return *this;
0359         }
0360         vector_iterator operator-( ptrdiff_t offset ) const {
0361             return vector_iterator( *my_vector, my_index-offset );
0362         }
0363         vector_iterator &operator-=( ptrdiff_t offset ) {
0364             my_index-=offset;
0365             my_item = NULL;
0366             return *this;
0367         }
0368         Value& operator*() const {
0369             Value* item = my_item;
0370             if( !item ) {
0371                 item = my_item = &my_vector->internal_subscript(my_index);
0372             }
0373             __TBB_ASSERT( item==&my_vector->internal_subscript(my_index), "corrupt cache" );
0374             return *item;
0375         }
0376         Value& operator[]( ptrdiff_t k ) const {
0377             return my_vector->internal_subscript(my_index+k);
0378         }
0379         Value* operator->() const {return &operator*();}
0380 
0381         //! Pre increment
0382         vector_iterator& operator++() {
0383             size_t element_index = ++my_index;
0384             if( my_item ) {
0385                 //TODO: consider using of knowledge about "first_block optimization" here as well?
0386                 if( concurrent_vector_base::is_first_element_in_segment(element_index)) {
0387                     //if the iterator crosses a segment boundary, the pointer become invalid
0388                     //as possibly next segment is in another memory location
0389                     my_item= NULL;
0390                 } else {
0391                     ++my_item;
0392                 }
0393             }
0394             return *this;
0395         }
0396 
0397         //! Pre decrement
0398         vector_iterator& operator--() {
0399             __TBB_ASSERT( my_index>0, "operator--() applied to iterator already at beginning of concurrent_vector" );
0400             size_t element_index = my_index--;
0401             if( my_item ) {
0402                 if(concurrent_vector_base::is_first_element_in_segment(element_index)) {
0403                     //if the iterator crosses a segment boundary, the pointer become invalid
0404                     //as possibly next segment is in another memory location
0405                     my_item= NULL;
0406                 } else {
0407                     --my_item;
0408                 }
0409             }
0410             return *this;
0411         }
0412 
0413         //! Post increment
0414         vector_iterator operator++(int) {
0415             vector_iterator result = *this;
0416             operator++();
0417             return result;
0418         }
0419 
0420         //! Post decrement
0421         vector_iterator operator--(int) {
0422             vector_iterator result = *this;
0423             operator--();
0424             return result;
0425         }
0426 
0427         // STL support
0428 
0429         typedef ptrdiff_t difference_type;
0430         typedef Value value_type;
0431         typedef Value* pointer;
0432         typedef Value& reference;
0433         typedef std::random_access_iterator_tag iterator_category;
0434     };
0435 
0436     template<typename Container, typename T>
0437     vector_iterator<Container,T> operator+( ptrdiff_t offset, const vector_iterator<Container,T>& v ) {
0438         return vector_iterator<Container,T>( *v.my_vector, v.my_index+offset );
0439     }
0440 
0441     template<typename Container, typename T, typename U>
0442     bool operator==( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0443         return i.my_index==j.my_index && i.my_vector == j.my_vector;
0444     }
0445 
0446     template<typename Container, typename T, typename U>
0447     bool operator!=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0448         return !(i==j);
0449     }
0450 
0451     template<typename Container, typename T, typename U>
0452     bool operator<( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0453         return i.my_index<j.my_index;
0454     }
0455 
0456     template<typename Container, typename T, typename U>
0457     bool operator>( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0458         return j<i;
0459     }
0460 
0461     template<typename Container, typename T, typename U>
0462     bool operator>=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0463         return !(i<j);
0464     }
0465 
0466     template<typename Container, typename T, typename U>
0467     bool operator<=( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0468         return !(j<i);
0469     }
0470 
0471     template<typename Container, typename T, typename U>
0472     ptrdiff_t operator-( const vector_iterator<Container,T>& i, const vector_iterator<Container,U>& j ) {
0473         return ptrdiff_t(i.my_index)-ptrdiff_t(j.my_index);
0474     }
0475 
0476     template<typename T, class A>
0477     class allocator_base {
0478     public:
0479         typedef typename tbb::internal::allocator_rebind<A, T>::type allocator_type;
0480         allocator_type my_allocator;
0481         allocator_base(const allocator_type &a = allocator_type() ) : my_allocator(a) {}
0482     };
0483 
0484 } // namespace internal
0485 //! @endcond
0486 
0487 //! Concurrent vector container
0488 /** concurrent_vector is a container having the following main properties:
0489     - It provides random indexed access to its elements. The index of the first element is 0.
0490     - It ensures safe concurrent growing its size (different threads can safely append new elements).
0491     - Adding new elements does not invalidate existing iterators and does not change indices of existing items.
0492 
0493 @par Compatibility
0494     The class meets all Container Requirements and Reversible Container Requirements from
0495     C++ Standard (See ISO/IEC 14882:2003(E), clause 23.1). But it doesn't meet
0496     Sequence Requirements due to absence of insert() and erase() methods.
0497 
0498 @par Exception Safety
0499     Methods working with memory allocation and/or new elements construction can throw an
0500     exception if allocator fails to allocate memory or element's default constructor throws one.
0501     Concurrent vector's element of type T must conform to the following requirements:
0502     - Throwing an exception is forbidden for destructor of T.
0503     - Default constructor of T must not throw an exception OR its non-virtual destructor must safely work when its object memory is zero-initialized.
0504     .
0505     Otherwise, the program's behavior is undefined.
0506 @par
0507     If an exception happens inside growth or assignment operation, an instance of the vector becomes invalid unless it is stated otherwise in the method documentation.
0508     Invalid state means:
0509     - There are no guarantees that all items were initialized by a constructor. The rest of items is zero-filled, including item where exception happens.
0510     - An invalid vector instance cannot be repaired; it is unable to grow anymore.
0511     - Size and capacity reported by the vector are incorrect, and calculated as if the failed operation were successful.
0512     - Attempt to access not allocated elements using operator[] or iterators results in access violation or segmentation fault exception, and in case of using at() method a C++ exception is thrown.
0513     .
0514     If a concurrent grow operation successfully completes, all the elements it has added to the vector will remain valid and accessible even if one of subsequent grow operations fails.
0515 
0516 @par Fragmentation
0517     Unlike an STL vector, a concurrent_vector does not move existing elements if it needs
0518     to allocate more memory. The container is divided into a series of contiguous arrays of
0519     elements. The first reservation, growth, or assignment operation determines the size of
0520     the first array. Using small number of elements as initial size incurs fragmentation that
0521     may increase element access time. Internal layout can be optimized by method compact() that
0522     merges several smaller arrays into one solid.
0523 
0524 @par Changes since TBB 2.1
0525     - Fixed guarantees of concurrent_vector::size() and grow_to_at_least() methods to assure elements are allocated.
0526     - Methods end()/rbegin()/back() are partly thread-safe since they use size() to get the end of vector
0527     - Added resize() methods (not thread-safe)
0528     - Added cbegin/cend/crbegin/crend methods
0529     - Changed return type of methods grow* and push_back to iterator
0530 
0531 @par Changes since TBB 2.0
0532     - Implemented exception-safety guarantees
0533     - Added template argument for allocator
0534     - Added allocator argument in constructors
0535     - Faster index calculation
0536     - First growth call specifies a number of segments to be merged in the first allocation.
0537     - Fixed memory blow up for swarm of vector's instances of small size
0538     - Added grow_by(size_type n, const_reference t) growth using copying constructor to init new items.
0539     - Added STL-like constructors.
0540     - Added operators ==, < and derivatives
0541     - Added at() method, approved for using after an exception was thrown inside the vector
0542     - Added get_allocator() method.
0543     - Added assign() methods
0544     - Added compact() method to defragment first segments
0545     - Added swap() method
0546     - range() defaults on grainsize = 1 supporting auto grainsize algorithms.
0547 
0548     @ingroup containers */
0549 template<typename T, class A>
0550 class concurrent_vector: protected internal::allocator_base<T, A>,
0551                          private internal::concurrent_vector_base {
0552 private:
0553     template<typename I>
0554     class generic_range_type: public blocked_range<I> {
0555     public:
0556         typedef T value_type;
0557         typedef T& reference;
0558         typedef const T& const_reference;
0559         typedef I iterator;
0560         typedef ptrdiff_t difference_type;
0561         generic_range_type( I begin_, I end_, size_t grainsize_ = 1) : blocked_range<I>(begin_,end_,grainsize_) {}
0562         template<typename U>
0563         generic_range_type( const generic_range_type<U>& r) : blocked_range<I>(r.begin(),r.end(),r.grainsize()) {}
0564         generic_range_type( generic_range_type& r, split ) : blocked_range<I>(r,split()) {}
0565     };
0566 
0567     template<typename C, typename U>
0568     friend class internal::vector_iterator;
0569 
0570 public:
0571     //------------------------------------------------------------------------
0572     // STL compatible types
0573     //------------------------------------------------------------------------
0574     typedef internal::concurrent_vector_base_v3::size_type size_type;
0575     typedef typename internal::allocator_base<T, A>::allocator_type allocator_type;
0576 
0577     typedef T value_type;
0578     typedef ptrdiff_t difference_type;
0579     typedef T& reference;
0580     typedef const T& const_reference;
0581     typedef T *pointer;
0582     typedef const T *const_pointer;
0583 
0584     typedef internal::vector_iterator<concurrent_vector,T> iterator;
0585     typedef internal::vector_iterator<concurrent_vector,const T> const_iterator;
0586 
0587 #if !defined(_MSC_VER) || _CPPLIB_VER>=300
0588     // Assume ISO standard definition of std::reverse_iterator
0589     typedef std::reverse_iterator<iterator> reverse_iterator;
0590     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
0591 #else
0592     // Use non-standard std::reverse_iterator
0593     typedef std::reverse_iterator<iterator,T,T&,T*> reverse_iterator;
0594     typedef std::reverse_iterator<const_iterator,T,const T&,const T*> const_reverse_iterator;
0595 #endif /* defined(_MSC_VER) && (_MSC_VER<1300) */
0596 
0597     //------------------------------------------------------------------------
0598     // Parallel algorithm support
0599     //------------------------------------------------------------------------
0600     typedef generic_range_type<iterator> range_type;
0601     typedef generic_range_type<const_iterator> const_range_type;
0602 
0603     //------------------------------------------------------------------------
0604     // STL compatible constructors & destructors
0605     //------------------------------------------------------------------------
0606 
0607     //! Construct empty vector.
0608     explicit concurrent_vector(const allocator_type &a = allocator_type())
0609         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0610     {
0611         vector_allocator_ptr = &internal_allocator;
0612     }
0613 
0614     //Constructors are not required to have synchronization
0615     //(for more details see comment in the concurrent_vector_base constructor).
0616 #if __TBB_INITIALIZER_LISTS_PRESENT
0617     //! Constructor from initializer_list
0618     concurrent_vector(std::initializer_list<T> init_list, const allocator_type &a = allocator_type())
0619         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0620     {
0621         vector_allocator_ptr = &internal_allocator;
0622         __TBB_TRY {
0623             internal_assign_iterators(init_list.begin(), init_list.end());
0624         } __TBB_CATCH(...) {
0625             segment_t *table = my_segment.load<relaxed>();;
0626             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0627             __TBB_RETHROW();
0628         }
0629 
0630     }
0631 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
0632 
0633     //! Copying constructor
0634     concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() )
0635         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0636     {
0637         vector_allocator_ptr = &internal_allocator;
0638         __TBB_TRY {
0639             internal_copy(vector, sizeof(T), &copy_array);
0640         } __TBB_CATCH(...) {
0641             segment_t *table = my_segment.load<relaxed>();
0642             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0643             __TBB_RETHROW();
0644         }
0645     }
0646 
0647 #if __TBB_CPP11_RVALUE_REF_PRESENT
0648     //! Move constructor
0649     //TODO add __TBB_NOEXCEPT(true) and static_assert(std::has_nothrow_move_constructor<A>::value)
0650     concurrent_vector( concurrent_vector&& source)
0651         : internal::allocator_base<T, A>(std::move(source)), internal::concurrent_vector_base()
0652     {
0653         vector_allocator_ptr = &internal_allocator;
0654         concurrent_vector_base_v3::internal_swap(source);
0655     }
0656 
0657     concurrent_vector( concurrent_vector&& source, const allocator_type& a)
0658         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0659     {
0660         vector_allocator_ptr = &internal_allocator;
0661         //C++ standard requires instances of an allocator being compared for equality,
0662         //which means that memory allocated by one instance is possible to deallocate with the other one.
0663         if (a == source.my_allocator) {
0664             concurrent_vector_base_v3::internal_swap(source);
0665         } else {
0666             __TBB_TRY {
0667                 internal_copy(source, sizeof(T), &move_array);
0668             } __TBB_CATCH(...) {
0669                 segment_t *table = my_segment.load<relaxed>();
0670                 internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>());
0671                 __TBB_RETHROW();
0672             }
0673         }
0674     }
0675 
0676 #endif
0677 
0678     //! Copying constructor for vector with different allocator type
0679     template<class M>
0680     __TBB_DEPRECATED concurrent_vector( const concurrent_vector<T, M>& vector, const allocator_type& a = allocator_type() )
0681         : internal::allocator_base<T, A>(a), internal::concurrent_vector_base()
0682     {
0683         vector_allocator_ptr = &internal_allocator;
0684         __TBB_TRY {
0685             internal_copy(vector.internal_vector_base(), sizeof(T), &copy_array);
0686         } __TBB_CATCH(...) {
0687             segment_t *table = my_segment.load<relaxed>();
0688             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0689             __TBB_RETHROW();
0690         }
0691     }
0692 
0693     //! Construction with initial size specified by argument n
0694     explicit concurrent_vector(size_type n)
0695     {
0696         vector_allocator_ptr = &internal_allocator;
0697         __TBB_TRY {
0698             internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
0699         } __TBB_CATCH(...) {
0700             segment_t *table = my_segment.load<relaxed>();
0701             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0702             __TBB_RETHROW();
0703         }
0704     }
0705 
0706     //! Construction with initial size specified by argument n, initialization by copying of t, and given allocator instance
0707     concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type())
0708         : internal::allocator_base<T, A>(a)
0709     {
0710         vector_allocator_ptr = &internal_allocator;
0711         __TBB_TRY {
0712             internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0713         } __TBB_CATCH(...) {
0714             segment_t *table = my_segment.load<relaxed>();
0715             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0716             __TBB_RETHROW();
0717         }
0718     }
0719 
0720     //! Construction with copying iteration range and given allocator instance
0721     template<class I>
0722     concurrent_vector(I first, I last, const allocator_type &a = allocator_type())
0723         : internal::allocator_base<T, A>(a)
0724     {
0725         vector_allocator_ptr = &internal_allocator;
0726         __TBB_TRY {
0727             internal_assign_range(first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
0728         } __TBB_CATCH(...) {
0729             segment_t *table = my_segment.load<relaxed>();
0730             internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
0731             __TBB_RETHROW();
0732         }
0733     }
0734 
0735     //! Assignment
0736     concurrent_vector& operator=( const concurrent_vector& vector ) {
0737         if( this != &vector )
0738             internal_assign(vector, sizeof(T), &destroy_array, &assign_array, &copy_array);
0739         return *this;
0740     }
0741 
0742 #if __TBB_CPP11_RVALUE_REF_PRESENT
0743     //TODO: add __TBB_NOEXCEPT()
0744     //! Move assignment
0745     concurrent_vector& operator=( concurrent_vector&& other ) {
0746         __TBB_ASSERT(this != &other, "Move assignment to itself is prohibited ");
0747         typedef typename tbb::internal::allocator_traits<A>::propagate_on_container_move_assignment pocma_t;
0748         if(pocma_t::value || this->my_allocator == other.my_allocator) {
0749             concurrent_vector trash (std::move(*this));
0750             internal_swap(other);
0751             tbb::internal::allocator_move_assignment(this->my_allocator, other.my_allocator, pocma_t());
0752         } else {
0753             internal_assign(other, sizeof(T), &destroy_array, &move_assign_array, &move_array);
0754         }
0755         return *this;
0756     }
0757 #endif
0758     //TODO: add an template assignment operator? (i.e. with different element type)
0759 
0760     //! Assignment for vector with different allocator type
0761     template<class M>
0762     __TBB_DEPRECATED concurrent_vector& operator=( const concurrent_vector<T, M>& vector ) {
0763         if( static_cast<void*>( this ) != static_cast<const void*>( &vector ) )
0764             internal_assign(vector.internal_vector_base(),
0765                 sizeof(T), &destroy_array, &assign_array, &copy_array);
0766         return *this;
0767     }
0768 
0769 #if __TBB_INITIALIZER_LISTS_PRESENT
0770     //! Assignment for initializer_list
0771     concurrent_vector& operator=( std::initializer_list<T> init_list ) {
0772         internal_clear(&destroy_array);
0773         internal_assign_iterators(init_list.begin(), init_list.end());
0774         return *this;
0775     }
0776 #endif //#if __TBB_INITIALIZER_LISTS_PRESENT
0777 
0778     //------------------------------------------------------------------------
0779     // Concurrent operations
0780     //------------------------------------------------------------------------
0781     //! Grow by "delta" elements.
0782     /** Returns iterator pointing to the first new element. */
0783     iterator grow_by( size_type delta ) {
0784         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array, NULL ) : my_early_size.load());
0785     }
0786 
0787     //! Grow by "delta" elements using copying constructor.
0788     /** Returns iterator pointing to the first new element. */
0789     iterator grow_by( size_type delta, const_reference t ) {
0790         return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size.load());
0791     }
0792 
0793     /** Returns iterator pointing to the first new element. */
0794     template<typename I>
0795     iterator grow_by( I first, I last ) {
0796         typename std::iterator_traits<I>::difference_type delta = std::distance(first, last);
0797         __TBB_ASSERT( delta >= 0, NULL);
0798 
0799         return iterator(*this, delta ? internal_grow_by(delta, sizeof(T), &copy_range<I>, static_cast<const void*>(&first)) : my_early_size.load());
0800     }
0801 
0802 #if __TBB_INITIALIZER_LISTS_PRESENT
0803     /** Returns iterator pointing to the first new element. */
0804     iterator grow_by( std::initializer_list<T> init_list ) {
0805         return grow_by( init_list.begin(), init_list.end() );
0806     }
0807 #endif //#if __TBB_INITIALIZER_LISTS_PRESENT
0808 
0809     //! Append minimal sequence of elements such that size()>=n.
0810     /** The new elements are default constructed.  Blocks until all elements in range [0..n) are allocated.
0811         May return while other elements are being constructed by other threads.
0812         Returns iterator that points to beginning of appended sequence.
0813         If no elements were appended, returns iterator pointing to nth element. */
0814     iterator grow_to_at_least( size_type n ) {
0815         size_type m=0;
0816         if( n ) {
0817             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array, NULL );
0818             if( m>n ) m=n;
0819         }
0820         return iterator(*this, m);
0821     };
0822 
0823     /** Analogous to grow_to_at_least( size_type n ) with exception that the new
0824         elements are initialized by copying of t instead of default construction. */
0825     iterator grow_to_at_least( size_type n, const_reference t ) {
0826         size_type m=0;
0827         if( n ) {
0828             m = internal_grow_to_at_least_with_result( n, sizeof(T), &initialize_array_by, &t);
0829             if( m>n ) m=n;
0830         }
0831         return iterator(*this, m);
0832     };
0833 
0834     //! Push item
0835     /** Returns iterator pointing to the new element. */
0836     iterator push_back( const_reference item )
0837     {
0838         push_back_helper prolog(*this);
0839         new(prolog.internal_push_back_result()) T(item);
0840         return prolog.return_iterator_and_dismiss();
0841     }
0842 
0843 #if    __TBB_CPP11_RVALUE_REF_PRESENT
0844     //! Push item, move-aware
0845     /** Returns iterator pointing to the new element. */
0846     iterator push_back(  T&& item )
0847     {
0848         push_back_helper prolog(*this);
0849         new(prolog.internal_push_back_result()) T(std::move(item));
0850         return prolog.return_iterator_and_dismiss();
0851     }
0852 #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0853     //! Push item, create item "in place" with provided arguments
0854     /** Returns iterator pointing to the new element. */
0855     template<typename... Args>
0856     iterator emplace_back(  Args&&... args )
0857     {
0858         push_back_helper prolog(*this);
0859         new(prolog.internal_push_back_result()) T(std::forward<Args>(args)...);
0860         return prolog.return_iterator_and_dismiss();
0861     }
0862 #endif //__TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0863 #endif //__TBB_CPP11_RVALUE_REF_PRESENT
0864     //! Get reference to element at given index.
0865     /** This method is thread-safe for concurrent reads, and also while growing the vector,
0866         as long as the calling thread has checked that index < size(). */
0867     reference operator[]( size_type index ) {
0868         return internal_subscript(index);
0869     }
0870 
0871     //! Get const reference to element at given index.
0872     const_reference operator[]( size_type index ) const {
0873         return internal_subscript(index);
0874     }
0875 
0876     //! Get reference to element at given index. Throws exceptions on errors.
0877     reference at( size_type index ) {
0878         return internal_subscript_with_exceptions(index);
0879     }
0880 
0881     //! Get const reference to element at given index. Throws exceptions on errors.
0882     const_reference at( size_type index ) const {
0883         return internal_subscript_with_exceptions(index);
0884     }
0885 
0886     //! Get range for iterating with parallel algorithms
0887     range_type range( size_t grainsize = 1 ) {
0888         return range_type( begin(), end(), grainsize );
0889     }
0890 
0891     //! Get const range for iterating with parallel algorithms
0892     const_range_type range( size_t grainsize = 1 ) const {
0893         return const_range_type( begin(), end(), grainsize );
0894     }
0895 
0896     //------------------------------------------------------------------------
0897     // Capacity
0898     //------------------------------------------------------------------------
0899     //! Return size of vector. It may include elements under construction
0900     size_type size() const {
0901         size_type sz = my_early_size, cp = internal_capacity();
0902         return cp < sz ? cp : sz;
0903     }
0904 
0905     //! Return false if vector is not empty or has elements under construction at least.
0906     bool empty() const {return !my_early_size;}
0907 
0908     //! Maximum size to which array can grow without allocating more memory. Concurrent allocations are not included in the value.
0909     size_type capacity() const {return internal_capacity();}
0910 
0911     //! Allocate enough space to grow to size n without having to allocate more memory later.
0912     /** Like most of the methods provided for STL compatibility, this method is *not* thread safe.
0913         The capacity afterwards may be bigger than the requested reservation. */
0914     void reserve( size_type n ) {
0915         if( n )
0916             internal_reserve(n, sizeof(T), max_size());
0917     }
0918 
0919     //! Resize the vector. Not thread-safe.
0920     void resize( size_type n ) {
0921         internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array, &initialize_array );
0922     }
0923 
0924     //! Resize the vector, copy t for new elements. Not thread-safe.
0925     void resize( size_type n, const_reference t ) {
0926         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0927     }
0928 
0929     //! Optimize memory usage and fragmentation.
0930     void shrink_to_fit();
0931 
0932     //! Upper bound on argument to reserve.
0933     size_type max_size() const {return (~size_type(0))/sizeof(T);}
0934 
0935     //------------------------------------------------------------------------
0936     // STL support
0937     //------------------------------------------------------------------------
0938 
0939     //! start iterator
0940     iterator begin() {return iterator(*this,0);}
0941     //! end iterator
0942     iterator end() {return iterator(*this,size());}
0943     //! start const iterator
0944     const_iterator begin() const {return const_iterator(*this,0);}
0945     //! end const iterator
0946     const_iterator end() const {return const_iterator(*this,size());}
0947     //! start const iterator
0948     const_iterator cbegin() const {return const_iterator(*this,0);}
0949     //! end const iterator
0950     const_iterator cend() const {return const_iterator(*this,size());}
0951     //! reverse start iterator
0952     reverse_iterator rbegin() {return reverse_iterator(end());}
0953     //! reverse end iterator
0954     reverse_iterator rend() {return reverse_iterator(begin());}
0955     //! reverse start const iterator
0956     const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
0957     //! reverse end const iterator
0958     const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
0959     //! reverse start const iterator
0960     const_reverse_iterator crbegin() const {return const_reverse_iterator(end());}
0961     //! reverse end const iterator
0962     const_reverse_iterator crend() const {return const_reverse_iterator(begin());}
0963     //! the first item
0964     reference front() {
0965         __TBB_ASSERT( size()>0, NULL);
0966         const segment_value_t& segment_value = my_segment[0].template load<relaxed>();
0967         return (segment_value.template pointer<T>())[0];
0968     }
0969     //! the first item const
0970     const_reference front() const {
0971         __TBB_ASSERT( size()>0, NULL);
0972         const segment_value_t& segment_value = my_segment[0].template load<relaxed>();
0973         return (segment_value.template pointer<const T>())[0];
0974     }
0975     //! the last item
0976     reference back() {
0977         __TBB_ASSERT( size()>0, NULL);
0978         return internal_subscript( size()-1 );
0979     }
0980     //! the last item const
0981     const_reference back() const {
0982         __TBB_ASSERT( size()>0, NULL);
0983         return internal_subscript( size()-1 );
0984     }
0985     //! return allocator object
0986     allocator_type get_allocator() const { return this->my_allocator; }
0987 
0988     //! assign n items by copying t item
0989     void assign(size_type n, const_reference t) {
0990         clear();
0991         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(&t), &destroy_array, &initialize_array_by );
0992     }
0993 
0994     //! assign range [first, last)
0995     template<class I>
0996     void assign(I first, I last) {
0997         clear(); internal_assign_range( first, last, static_cast<is_integer_tag<std::numeric_limits<I>::is_integer> *>(0) );
0998     }
0999 
1000 #if __TBB_INITIALIZER_LISTS_PRESENT
1001     //! assigns an initializer list
1002     void assign(std::initializer_list<T> init_list) {
1003         clear(); internal_assign_iterators( init_list.begin(), init_list.end());
1004     }
1005 #endif //# __TBB_INITIALIZER_LISTS_PRESENT
1006 
1007     //! swap two instances
1008     void swap(concurrent_vector &vector) {
1009         typedef typename tbb::internal::allocator_traits<A>::propagate_on_container_swap pocs_t;
1010         if( this != &vector && (this->my_allocator == vector.my_allocator || pocs_t::value) ) {
1011             concurrent_vector_base_v3::internal_swap(static_cast<concurrent_vector_base_v3&>(vector));
1012             tbb::internal::allocator_swap(this->my_allocator, vector.my_allocator, pocs_t());
1013         }
1014     }
1015 
1016     //! Clear container while keeping memory allocated.
1017     /** To free up the memory, use in conjunction with method compact(). Not thread safe **/
1018     void clear() {
1019         internal_clear(&destroy_array);
1020     }
1021 
1022     //! Clear and destroy vector.
1023     ~concurrent_vector() {
1024         segment_t *table = my_segment.load<relaxed>();
1025         internal_free_segments( table, internal_clear(&destroy_array), my_first_block.load<relaxed>() );
1026         // base class destructor call should be then
1027     }
1028 
1029     const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; }
1030 private:
1031     //! Allocate k items
1032     static void *internal_allocator(internal::concurrent_vector_base_v3 &vb, size_t k) {
1033         return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.allocate(k);
1034     }
1035     //! Free k segments from table
1036     void internal_free_segments(segment_t table[], segment_index_t k, segment_index_t first_block);
1037 
1038     //! Get reference to element at given index.
1039     T& internal_subscript( size_type index ) const;
1040 
1041     //! Get reference to element at given index with errors checks
1042     T& internal_subscript_with_exceptions( size_type index ) const;
1043 
1044     //! assign n items by copying t
1045     void internal_assign_n(size_type n, const_pointer p) {
1046         internal_resize( n, sizeof(T), max_size(), static_cast<const void*>(p), &destroy_array, p? &initialize_array_by : &initialize_array );
1047     }
1048 
1049     //! True/false function override helper
1050     /* Functions declarations:
1051      *     void foo(is_integer_tag<true>*);
1052      *     void foo(is_integer_tag<false>*);
1053      * Usage example:
1054      *     foo(static_cast<is_integer_tag<std::numeric_limits<T>::is_integer>*>(0));
1055      */
1056     template<bool B> class is_integer_tag;
1057 
1058     //! assign integer items by copying when arguments are treated as iterators. See C++ Standard 2003 23.1.1p9
1059     template<class I>
1060     void internal_assign_range(I first, I last, is_integer_tag<true> *) {
1061         internal_assign_n(static_cast<size_type>(first), &static_cast<T&>(last));
1062     }
1063     //! inline proxy assign by iterators
1064     template<class I>
1065     void internal_assign_range(I first, I last, is_integer_tag<false> *) {
1066         internal_assign_iterators(first, last);
1067     }
1068     //! assign by iterators
1069     template<class I>
1070     void internal_assign_iterators(I first, I last);
1071 
1072     //these functions are marked __TBB_EXPORTED_FUNC as they are called from within the library
1073 
1074     //! Construct n instances of T, starting at "begin".
1075     static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const void*, size_type n );
1076 
1077     //! Copy-construct n instances of T, starting at "begin".
1078     static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n );
1079 
1080     //! Copy-construct n instances of T by copying single element pointed to by src, starting at "dst".
1081     static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n );
1082 
1083 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1084     //! Either opy or move-construct n instances of T, starting at "dst" by copying according element of src array.
1085     static void __TBB_EXPORTED_FUNC move_array_if_noexcept( void* dst, const void* src, size_type n );
1086 #endif //__TBB_MOVE_IF_NO_EXCEPT_PRESENT
1087 
1088 #if __TBB_CPP11_RVALUE_REF_PRESENT
1089     //! Move-construct n instances of T, starting at "dst" by copying according element of src array.
1090     static void __TBB_EXPORTED_FUNC move_array( void* dst, const void* src, size_type n );
1091 
1092     //! Move-assign (using operator=) n instances of T, starting at "dst" by assigning according element of src array.
1093     static void __TBB_EXPORTED_FUNC move_assign_array( void* dst, const void* src, size_type n );
1094 #endif
1095     //! Copy-construct n instances of T, starting at "dst" by iterator range of [p_type_erased_iterator, p_type_erased_iterator+n).
1096     template<typename Iterator>
1097     static void __TBB_EXPORTED_FUNC copy_range( void* dst, const void* p_type_erased_iterator, size_type n );
1098 
1099     //! Assign (using operator=) n instances of T, starting at "dst" by assigning according element of src array.
1100     static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* src, size_type n );
1101 
1102     //! Destroy n instances of T, starting at "begin".
1103     static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n );
1104 
1105     //! Exception-aware helper class for filling a segment by exception-danger operators of user class
1106     class internal_loop_guide : internal::no_copy {
1107     public:
1108         const pointer array;
1109         const size_type n;
1110         size_type i;
1111 
1112         static const T* as_const_pointer(const void *ptr) { return static_cast<const T *>(ptr); }
1113         static T* as_pointer(const void *src) { return static_cast<T*>(const_cast<void *>(src)); }
1114 
1115         internal_loop_guide(size_type ntrials, void *ptr)
1116             : array(as_pointer(ptr)), n(ntrials), i(0) {}
1117         void init() {   for(; i < n; ++i) new( &array[i] ) T(); }
1118         void init(const void *src) { for(; i < n; ++i) new( &array[i] ) T(*as_const_pointer(src)); }
1119         void copy(const void *src) { for(; i < n; ++i) new( &array[i] ) T(as_const_pointer(src)[i]); }
1120         void assign(const void *src) { for(; i < n; ++i) array[i] = as_const_pointer(src)[i]; }
1121 #if __TBB_CPP11_RVALUE_REF_PRESENT
1122         void move_assign(const void *src)       { for(; i < n; ++i) array[i]         =  std::move(as_pointer(src)[i]);   }
1123         void move_construct(const void *src)    { for(; i < n; ++i) new( &array[i] ) T( std::move(as_pointer(src)[i]) ); }
1124 #endif
1125 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1126         void move_construct_if_noexcept(const void *src)    { for(; i < n; ++i) new( &array[i] ) T( std::move_if_noexcept(as_pointer(src)[i]) ); }
1127 #endif //__TBB_MOVE_IF_NOEXCEPT_PRESENT
1128 
1129         //TODO: rename to construct_range
1130         template<class I> void iterate(I &src) { for(; i < n; ++i, ++src) new( &array[i] ) T( *src ); }
1131         ~internal_loop_guide() {
1132             if(i < n) {// if an exception was raised, fill the rest of items with zeros
1133                 internal::handle_unconstructed_elements(array+i, n-i);
1134             }
1135         }
1136     };
1137 
1138     struct push_back_helper : internal::no_copy{
1139         struct element_construction_guard : internal::no_copy{
1140             pointer element;
1141 
1142             element_construction_guard(pointer an_element) : element (an_element){}
1143             void dismiss(){ element = NULL; }
1144             ~element_construction_guard(){
1145                 if (element){
1146                     internal::handle_unconstructed_elements(element, 1);
1147                 }
1148             }
1149         };
1150 
1151         concurrent_vector & v;
1152         size_type k;
1153         element_construction_guard g;
1154 
1155         push_back_helper(concurrent_vector & vector) :
1156             v(vector),
1157             g (static_cast<T*>(v.internal_push_back(sizeof(T),k)))
1158         {}
1159 
1160         pointer internal_push_back_result(){ return g.element;}
1161         iterator return_iterator_and_dismiss(){
1162             pointer ptr = g.element;
1163             g.dismiss();
1164             return iterator(v, k, ptr);
1165         }
1166     };
1167 };
1168 
1169 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
1170 // Deduction guide for the constructor from two iterators
1171 template<typename I,
1172          typename T = typename std::iterator_traits<I>::value_type,
1173          typename A = cache_aligned_allocator<T>
1174 > concurrent_vector(I, I, const A& = A())
1175 -> concurrent_vector<T, A>;
1176 
1177 // Deduction guide for the constructor from a vector and allocator
1178 template<typename T, typename A1, typename A2>
1179 concurrent_vector(const concurrent_vector<T, A1> &, const A2 &)
1180 -> concurrent_vector<T, A2>;
1181 
1182 // Deduction guide for the constructor from an initializer_list
1183 template<typename T, typename A = cache_aligned_allocator<T>
1184 > concurrent_vector(std::initializer_list<T>, const A& = A())
1185 -> concurrent_vector<T, A>;
1186 #endif /* __TBB_CPP17_DEDUCTION_GUIDES_PRESENT */
1187 
1188 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1189 #pragma warning (push)
1190 #pragma warning (disable: 4701) // potentially uninitialized local variable "old"
1191 #endif
1192 template<typename T, class A>
1193 void concurrent_vector<T, A>::shrink_to_fit() {
1194     internal_segments_table old;
1195     __TBB_TRY {
1196         internal_array_op2 copy_or_move_array =
1197 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1198                 &move_array_if_noexcept
1199 #else
1200                 &copy_array
1201 #endif
1202         ;
1203         if( internal_compact( sizeof(T), &old, &destroy_array, copy_or_move_array ) )
1204             internal_free_segments( old.table, pointers_per_long_table, old.first_block ); // free joined and unnecessary segments
1205     } __TBB_CATCH(...) {
1206         if( old.first_block ) // free segment allocated for compacting. Only for support of exceptions in ctor of user T[ype]
1207             internal_free_segments( old.table, 1, old.first_block );
1208         __TBB_RETHROW();
1209     }
1210 }
1211 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1212 #pragma warning (pop)
1213 #endif // warning 4701 is back
1214 
1215 template<typename T, class A>
1216 void concurrent_vector<T, A>::internal_free_segments(segment_t table[], segment_index_t k, segment_index_t first_block) {
1217     // Free the arrays
1218     while( k > first_block ) {
1219         --k;
1220         segment_value_t segment_value = table[k].load<relaxed>();
1221         table[k].store<relaxed>(segment_not_used());
1222         if( segment_value == segment_allocated() ) // check for correct segment pointer
1223             this->my_allocator.deallocate( (segment_value.pointer<T>()), segment_size(k) );
1224     }
1225     segment_value_t segment_value = table[0].load<relaxed>();
1226     if( segment_value == segment_allocated() ) {
1227         __TBB_ASSERT( first_block > 0, NULL );
1228         while(k > 0) table[--k].store<relaxed>(segment_not_used());
1229         this->my_allocator.deallocate( (segment_value.pointer<T>()), segment_size(first_block) );
1230     }
1231 }
1232 
1233 template<typename T, class A>
1234 T& concurrent_vector<T, A>::internal_subscript( size_type index ) const {
1235     //TODO: unify both versions of internal_subscript
1236     __TBB_ASSERT( index < my_early_size, "index out of bounds" );
1237     size_type j = index;
1238     segment_index_t k = segment_base_index_of( j );
1239     __TBB_ASSERT( my_segment.load<acquire>() != my_storage || k < pointers_per_short_table, "index is being allocated" );
1240     //no need in load with acquire (load<acquire>) since thread works in own space or gets
1241     //the information about added elements via some form of external synchronization
1242     //TODO: why not make a load of my_segment relaxed as well ?
1243     //TODO: add an assertion that my_segment[k] is properly aligned to please ITT
1244     segment_value_t segment_value =  my_segment[k].template load<relaxed>();
1245     __TBB_ASSERT( segment_value != segment_allocation_failed(), "the instance is broken by bad allocation. Use at() instead" );
1246     __TBB_ASSERT( segment_value != segment_not_used(), "index is being allocated" );
1247     return (( segment_value.pointer<T>()))[j];
1248 }
1249 
1250 template<typename T, class A>
1251 T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type index ) const {
1252     if( index >= my_early_size )
1253         internal::throw_exception(internal::eid_out_of_range); // throw std::out_of_range
1254     size_type j = index;
1255     segment_index_t k = segment_base_index_of( j );
1256     //TODO: refactor this condition into separate helper function, e.g. fits_into_small_table
1257     if( my_segment.load<acquire>() == my_storage && k >= pointers_per_short_table )
1258         internal::throw_exception(internal::eid_segment_range_error); // throw std::range_error
1259     // no need in load with acquire (load<acquire>) since thread works in own space or gets
1260     //the information about added elements via some form of external synchronization
1261     //TODO: why not make a load of my_segment relaxed as well ?
1262     //TODO: add an assertion that my_segment[k] is properly aligned to please ITT
1263     segment_value_t segment_value =  my_segment[k].template load<relaxed>();
1264     enforce_segment_allocated(segment_value, internal::eid_index_range_error);
1265     return (segment_value.pointer<T>())[j];
1266 }
1267 
1268 template<typename T, class A> template<class I>
1269 void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) {
1270     __TBB_ASSERT(my_early_size == 0, NULL);
1271     size_type n = std::distance(first, last);
1272     if( !n ) return;
1273     internal_reserve(n, sizeof(T), max_size());
1274     my_early_size = n;
1275     segment_index_t k = 0;
1276     //TODO: unify segment iteration code with concurrent_base_v3::helper
1277     size_type sz = segment_size( my_first_block );
1278     while( sz < n ) {
1279         internal_loop_guide loop(sz, my_segment[k].template load<relaxed>().template pointer<void>());
1280         loop.iterate(first);
1281         n -= sz;
1282         if( !k ) k = my_first_block;
1283         else { ++k; sz <<= 1; }
1284     }
1285     internal_loop_guide loop(n, my_segment[k].template load<relaxed>().template pointer<void>());
1286     loop.iterate(first);
1287 }
1288 
1289 template<typename T, class A>
1290 void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) {
1291     internal_loop_guide loop(n, begin); loop.init();
1292 }
1293 
1294 template<typename T, class A>
1295 void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) {
1296     internal_loop_guide loop(n, begin); loop.init(src);
1297 }
1298 
1299 template<typename T, class A>
1300 void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_type n ) {
1301     internal_loop_guide loop(n, dst); loop.copy(src);
1302 }
1303 
1304 #if __TBB_CPP11_RVALUE_REF_PRESENT
1305 template<typename T, class A>
1306 void concurrent_vector<T, A>::move_array( void* dst, const void* src, size_type n ) {
1307     internal_loop_guide loop(n, dst); loop.move_construct(src);
1308 }
1309 template<typename T, class A>
1310 void concurrent_vector<T, A>::move_assign_array( void* dst, const void* src, size_type n ) {
1311     internal_loop_guide loop(n, dst); loop.move_assign(src);
1312 }
1313 #endif
1314 
1315 #if __TBB_MOVE_IF_NOEXCEPT_PRESENT
1316 template<typename T, class A>
1317 void concurrent_vector<T, A>::move_array_if_noexcept( void* dst, const void* src, size_type n ) {
1318     internal_loop_guide loop(n, dst); loop.move_construct_if_noexcept(src);
1319 }
1320 #endif //__TBB_MOVE_IF_NOEXCEPT_PRESENT
1321 
1322 template<typename T, class A>
1323 template<typename I>
1324 void concurrent_vector<T, A>::copy_range( void* dst, const void* p_type_erased_iterator, size_type n ){
1325     internal_loop_guide loop(n, dst);
1326     loop.iterate( *(static_cast<I*>(const_cast<void*>(p_type_erased_iterator))) );
1327 }
1328 
1329 template<typename T, class A>
1330 void concurrent_vector<T, A>::assign_array( void* dst, const void* src, size_type n ) {
1331     internal_loop_guide loop(n, dst); loop.assign(src);
1332 }
1333 
1334 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1335     // Workaround for overzealous compiler warning
1336     #pragma warning (push)
1337     #pragma warning (disable: 4189)
1338 #endif
1339 template<typename T, class A>
1340 void concurrent_vector<T, A>::destroy_array( void* begin, size_type n ) {
1341     T* array = static_cast<T*>(begin);
1342     for( size_type j=n; j>0; --j )
1343         array[j-1].~T(); // destructors are supposed to not throw any exceptions
1344 }
1345 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1346     #pragma warning (pop)
1347 #endif // warning 4189 is back
1348 
1349 // concurrent_vector's template functions
1350 template<typename T, class A1, class A2>
1351 inline bool operator==(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b) {
1352     //TODO: call size() only once per vector (in operator==)
1353     // Simply:    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
1354     if(a.size() != b.size()) return false;
1355     typename concurrent_vector<T, A1>::const_iterator i(a.begin());
1356     typename concurrent_vector<T, A2>::const_iterator j(b.begin());
1357     for(; i != a.end(); ++i, ++j)
1358         if( !(*i == *j) ) return false;
1359     return true;
1360 }
1361 
1362 template<typename T, class A1, class A2>
1363 inline bool operator!=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1364 {    return !(a == b); }
1365 
1366 template<typename T, class A1, class A2>
1367 inline bool operator<(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1368 {    return (std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end())); }
1369 
1370 template<typename T, class A1, class A2>
1371 inline bool operator>(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1372 {    return b < a; }
1373 
1374 template<typename T, class A1, class A2>
1375 inline bool operator<=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1376 {    return !(b < a); }
1377 
1378 template<typename T, class A1, class A2>
1379 inline bool operator>=(const concurrent_vector<T, A1> &a, const concurrent_vector<T, A2> &b)
1380 {    return !(a < b); }
1381 
1382 template<typename T, class A>
1383 inline void swap(concurrent_vector<T, A> &a, concurrent_vector<T, A> &b)
1384 {    a.swap( b ); }
1385 
1386 } // namespace tbb
1387 
1388 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
1389     #pragma warning (pop)
1390 #endif // warning 4267,4127 are back
1391 
1392 
1393 #undef __TBB_concurrent_vector_H_include_area
1394 #include "internal/_warning_suppress_disable_notice.h"
1395 
1396 #endif /* __TBB_concurrent_vector_H */