1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10
11 #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP
12 #define BOOST_CONTAINER_CONTAINER_VECTOR_HPP
13
14 #ifndef BOOST_CONFIG_HPP
15 # include <boost/config.hpp>
16 #endif
17
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 # pragma once
20 #endif
21
22 #include <boost/container/detail/config_begin.hpp>
23 #include <boost/container/detail/workaround.hpp>
24
25 // container
26 #include <boost/container/container_fwd.hpp>
27 #include <boost/container/allocator_traits.hpp>
28 #include <boost/container/new_allocator.hpp> //new_allocator
29 #include <boost/container/throw_exception.hpp>
30 #include <boost/container/options.hpp>
31 // container detail
32 #include <boost/container/detail/advanced_insert_int.hpp>
33 #include <boost/container/detail/algorithm.hpp> //equal()
34 #include <boost/container/detail/alloc_helpers.hpp>
35 #include <boost/container/detail/allocation_type.hpp>
36 #include <boost/container/detail/copy_move_algo.hpp>
37 #include <boost/container/detail/destroyers.hpp>
38 #include <boost/container/detail/iterator.hpp>
39 #include <boost/container/detail/iterators.hpp>
40 #include <boost/move/detail/iterator_to_raw_pointer.hpp>
41 #include <boost/container/detail/mpl.hpp>
42 #include <boost/container/detail/next_capacity.hpp>
43 #include <boost/container/detail/value_functors.hpp>
44 #include <boost/move/detail/to_raw_pointer.hpp>
45 #include <boost/container/detail/type_traits.hpp>
46 #include <boost/container/detail/version_type.hpp>
47 // intrusive
48 #include <boost/intrusive/pointer_traits.hpp>
49 // move
50 #include <boost/move/adl_move_swap.hpp>
51 #include <boost/move/iterator.hpp>
52 #include <boost/move/traits.hpp>
53 #include <boost/move/utility_core.hpp>
54 // move/detail
55 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
56 #include <boost/move/detail/fwd_macros.hpp>
57 #endif
58 #include <boost/move/detail/move_helpers.hpp>
59 // move/algo
60 #include <boost/move/algo/adaptive_merge.hpp>
61 #include <boost/move/algo/unique.hpp>
62 #include <boost/move/algo/predicate.hpp>
63 #include <boost/move/algo/detail/set_difference.hpp>
64 // other
65 #include <boost/core/no_exceptions_support.hpp>
66 #include <boost/assert.hpp>
67 #include <boost/cstdint.hpp>
68
69 //std
70 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
71 #include <initializer_list> //for std::initializer_list
72 #endif
73
74 namespace boost {
75 namespace container {
76
77 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
78
79
80 template <class Pointer, bool IsConst>
81 class vec_iterator
82 {
83 public:
84 typedef std::random_access_iterator_tag iterator_category;
85 typedef typename boost::intrusive::pointer_traits<Pointer>::element_type value_type;
86 typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type difference_type;
87 typedef typename dtl::if_c
88 < IsConst
89 , typename boost::intrusive::pointer_traits<Pointer>::template
90 rebind_pointer<const value_type>::type
91 , Pointer
92 >::type pointer;
93 typedef typename boost::intrusive::pointer_traits<pointer> ptr_traits;
94 typedef typename ptr_traits::reference reference;
95
96 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
97 private:
98 Pointer m_ptr;
99
100 class nat
101 {
102 public:
get_ptr() const103 Pointer get_ptr() const
104 { return Pointer(); }
105 };
106 typedef typename dtl::if_c< IsConst
107 , vec_iterator<Pointer, false>
108 , nat>::type nonconst_iterator;
109
110 public:
111 BOOST_CONTAINER_FORCEINLINE
get_ptr() const112 const Pointer &get_ptr() const BOOST_NOEXCEPT_OR_NOTHROW
113 { return m_ptr; }
114
115 BOOST_CONTAINER_FORCEINLINE
get_ptr()116 Pointer &get_ptr() BOOST_NOEXCEPT_OR_NOTHROW
117 { return m_ptr; }
118
vec_iterator(Pointer ptr)119 BOOST_CONTAINER_FORCEINLINE explicit vec_iterator(Pointer ptr) BOOST_NOEXCEPT_OR_NOTHROW
120 : m_ptr(ptr)
121 {}
122 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
123
124 public:
125
126 //Constructors
vec_iterator()127 BOOST_CONTAINER_FORCEINLINE vec_iterator() BOOST_NOEXCEPT_OR_NOTHROW
128 : m_ptr() //Value initialization to achieve "null iterators" (N3644)
129 {}
130
vec_iterator(const vec_iterator & other)131 BOOST_CONTAINER_FORCEINLINE vec_iterator(const vec_iterator& other) BOOST_NOEXCEPT_OR_NOTHROW
132 : m_ptr(other.get_ptr())
133 {}
134
vec_iterator(const nonconst_iterator & other)135 BOOST_CONTAINER_FORCEINLINE vec_iterator(const nonconst_iterator &other) BOOST_NOEXCEPT_OR_NOTHROW
136 : m_ptr(other.get_ptr())
137 {}
138
operator =(const vec_iterator & other)139 BOOST_CONTAINER_FORCEINLINE vec_iterator & operator=(const vec_iterator& other) BOOST_NOEXCEPT_OR_NOTHROW
140 { m_ptr = other.get_ptr(); return *this; }
141
142 //Pointer like operators
143 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator *() const144 reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW
145 { BOOST_ASSERT(!!m_ptr); return *m_ptr; }
146
147 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator ->() const148 pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW
149 { return m_ptr; }
150
151 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator [](difference_type off) const152 reference operator[](difference_type off) const BOOST_NOEXCEPT_OR_NOTHROW
153 { BOOST_ASSERT(!!m_ptr); return m_ptr[off]; }
154
155 //Increment / Decrement
operator ++()156 BOOST_CONTAINER_FORCEINLINE vec_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW
157 { BOOST_ASSERT(!!m_ptr); ++m_ptr; return *this; }
158
operator ++(int)159 BOOST_CONTAINER_FORCEINLINE vec_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW
160 { BOOST_ASSERT(!!m_ptr); return vec_iterator(m_ptr++); }
161
operator --()162 BOOST_CONTAINER_FORCEINLINE vec_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW
163 { BOOST_ASSERT(!!m_ptr); --m_ptr; return *this; }
164
operator --(int)165 BOOST_CONTAINER_FORCEINLINE vec_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW
166 { BOOST_ASSERT(!!m_ptr); return vec_iterator(m_ptr--); }
167
168 //Arithmetic
operator +=(difference_type off)169 BOOST_CONTAINER_FORCEINLINE vec_iterator& operator+=(difference_type off) BOOST_NOEXCEPT_OR_NOTHROW
170 { BOOST_ASSERT(m_ptr || !off); m_ptr += off; return *this; }
171
operator -=(difference_type off)172 BOOST_CONTAINER_FORCEINLINE vec_iterator& operator-=(difference_type off) BOOST_NOEXCEPT_OR_NOTHROW
173 { BOOST_ASSERT(m_ptr || !off); m_ptr -= off; return *this; }
174
175 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator +(const vec_iterator & x,difference_type off)176 friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW
177 { BOOST_ASSERT(x.m_ptr || !off); return vec_iterator(x.m_ptr+off); }
178
179 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator +(difference_type off,vec_iterator right)180 friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_NOEXCEPT_OR_NOTHROW
181 { BOOST_ASSERT(right.m_ptr || !off); right.m_ptr += off; return right; }
182
183 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator -(vec_iterator left,difference_type off)184 friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_NOEXCEPT_OR_NOTHROW
185 { BOOST_ASSERT(left.m_ptr || !off); left.m_ptr -= off; return left; }
186
187 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator -(const vec_iterator & left,const vec_iterator & right)188 friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_NOEXCEPT_OR_NOTHROW
189 { return left.m_ptr - right.m_ptr; }
190
191 //Comparison operators
192 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator ==(const vec_iterator & l,const vec_iterator & r)193 friend bool operator== (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
194 { return l.m_ptr == r.m_ptr; }
195
196 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator !=(const vec_iterator & l,const vec_iterator & r)197 friend bool operator!= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
198 { return l.m_ptr != r.m_ptr; }
199
200 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator <(const vec_iterator & l,const vec_iterator & r)201 friend bool operator< (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
202 { return l.m_ptr < r.m_ptr; }
203
204 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator <=(const vec_iterator & l,const vec_iterator & r)205 friend bool operator<= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
206 { return l.m_ptr <= r.m_ptr; }
207
208 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator >(const vec_iterator & l,const vec_iterator & r)209 friend bool operator> (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
210 { return l.m_ptr > r.m_ptr; }
211
212 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator >=(const vec_iterator & l,const vec_iterator & r)213 friend bool operator>= (const vec_iterator& l, const vec_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
214 { return l.m_ptr >= r.m_ptr; }
215 };
216
217 template<class BiDirPosConstIt, class BiDirValueIt>
218 struct vector_insert_ordered_cursor
219 {
220 typedef typename iterator_traits<BiDirPosConstIt>::value_type size_type;
221 typedef typename iterator_traits<BiDirValueIt>::reference reference;
222
vector_insert_ordered_cursorboost::container::vector_insert_ordered_cursor223 BOOST_CONTAINER_FORCEINLINE vector_insert_ordered_cursor(BiDirPosConstIt posit, BiDirValueIt valueit)
224 : last_position_it(posit), last_value_it(valueit)
225 {}
226
operator --boost::container::vector_insert_ordered_cursor227 void operator --()
228 {
229 --last_value_it;
230 --last_position_it;
231 while(this->get_pos() == size_type(-1)){
232 --last_value_it;
233 --last_position_it;
234 }
235 }
236
get_posboost::container::vector_insert_ordered_cursor237 BOOST_CONTAINER_FORCEINLINE size_type get_pos() const
238 { return *last_position_it; }
239
get_valboost::container::vector_insert_ordered_cursor240 BOOST_CONTAINER_FORCEINLINE reference get_val()
241 { return *last_value_it; }
242
243 BiDirPosConstIt last_position_it;
244 BiDirValueIt last_value_it;
245 };
246
247 struct initial_capacity_t{};
248
249 template<class Pointer, bool IsConst>
vector_iterator_get_ptr(const vec_iterator<Pointer,IsConst> & it)250 BOOST_CONTAINER_FORCEINLINE const Pointer &vector_iterator_get_ptr(const vec_iterator<Pointer, IsConst> &it) BOOST_NOEXCEPT_OR_NOTHROW
251 { return it.get_ptr(); }
252
253 template<class Pointer, bool IsConst>
get_ptr(vec_iterator<Pointer,IsConst> & it)254 BOOST_CONTAINER_FORCEINLINE Pointer &get_ptr(vec_iterator<Pointer, IsConst> &it) BOOST_NOEXCEPT_OR_NOTHROW
255 { return it.get_ptr(); }
256
257 struct vector_uninitialized_size_t {};
258 static const vector_uninitialized_size_t vector_uninitialized_size = vector_uninitialized_size_t();
259
260 template <class T>
261 struct vector_value_traits_base
262 {
263 static const bool trivial_dctr = dtl::is_trivially_destructible<T>::value;
264 static const bool trivial_dctr_after_move = has_trivial_destructor_after_move<T>::value;
265 };
266
267 template <class Allocator>
268 struct vector_value_traits
269 : public vector_value_traits_base<typename Allocator::value_type>
270 {
271 typedef vector_value_traits_base<typename Allocator::value_type> base_t;
272 //This is the anti-exception array destructor
273 //to deallocate values already constructed
274 typedef typename dtl::if_c
275 <base_t::trivial_dctr
276 ,dtl::null_scoped_destructor_n<Allocator>
277 ,dtl::scoped_destructor_n<Allocator>
278 >::type ArrayDestructor;
279 //This is the anti-exception array deallocator
280 typedef dtl::scoped_array_deallocator<Allocator> ArrayDeallocator;
281 };
282
283 //!This struct deallocates and allocated memory
284 template < class Allocator
285 , class StoredSizeType
286 , class AllocatorVersion = typename dtl::version<Allocator>::type
287 >
288 struct vector_alloc_holder
289 : public Allocator
290 {
291 private:
292 BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder)
293
294 public:
295 typedef Allocator allocator_type;
296 typedef StoredSizeType stored_size_type;
297 typedef boost::container::allocator_traits<allocator_type> allocator_traits_type;
298 typedef typename allocator_traits_type::pointer pointer;
299 typedef typename allocator_traits_type::size_type size_type;
300 typedef typename allocator_traits_type::value_type value_type;
301
302 BOOST_CONTAINER_FORCEINLINE
is_propagable_fromboost::container::vector_alloc_holder303 static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator)
304 {
305 (void)propagate_allocator; (void)p; (void)to_alloc; (void)from_alloc;
306 const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value ||
307 !allocator_traits_type::storage_is_unpropagable(from_alloc, p);
308 return all_storage_propagable && (propagate_allocator || allocator_traits_type::equal(from_alloc, to_alloc));
309 }
310
311 BOOST_CONTAINER_FORCEINLINE
are_swap_propagableboost::container::vector_alloc_holder312 static bool are_swap_propagable(const allocator_type &l_a, pointer l_p, const allocator_type &r_a, pointer r_p, bool const propagate_allocator)
313 {
314 (void)propagate_allocator; (void)l_p; (void)r_p; (void)l_a; (void)r_a;
315 const bool all_storage_propagable = !allocator_traits_type::is_partially_propagable::value ||
316 !(allocator_traits_type::storage_is_unpropagable(l_a, l_p) || allocator_traits_type::storage_is_unpropagable(r_a, r_p));
317 return all_storage_propagable && (propagate_allocator || allocator_traits_type::equal(l_a, r_a));
318 }
319
320 //Constructor, does not throw
321 vector_alloc_holder()
BOOST_NOEXCEPT_IFboost::container::vector_alloc_holder322 BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)
323 : allocator_type(), m_start(), m_size(), m_capacity()
324 {}
325
326 //Constructor, does not throw
327 template<class AllocConvertible>
vector_alloc_holderboost::container::vector_alloc_holder328 explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_NOEXCEPT_OR_NOTHROW
329 : allocator_type(boost::forward<AllocConvertible>(a)), m_start(), m_size(), m_capacity()
330 {}
331
332 //Constructor, does not throw
333 template<class AllocConvertible, class SizeType>
vector_alloc_holderboost::container::vector_alloc_holder334 vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, SizeType initial_size)
335 : allocator_type(boost::forward<AllocConvertible>(a))
336 , m_start()
337 //Size is initialized here so vector should only call uninitialized_xxx after this
338 , m_size(static_cast<stored_size_type>(initial_size))
339 , m_capacity()
340 {
341 if (initial_size > size_type(-1)){
342 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
343 }
344 else if(initial_size){
345 pointer reuse = pointer();
346 size_type final_cap = static_cast<size_type>(initial_size);
347 m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse);
348 this->set_stored_capacity(final_cap);
349 }
350 }
351
352 //Constructor, does not throw
353 template<class SizeType>
vector_alloc_holderboost::container::vector_alloc_holder354 vector_alloc_holder(vector_uninitialized_size_t, SizeType initial_size)
355 : allocator_type()
356 , m_start()
357 //Size is initialized here so vector should only call uninitialized_xxx after this
358 , m_size(static_cast<stored_size_type>(initial_size))
359 , m_capacity()
360 {
361 if (initial_size > size_type(-1)){
362 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
363 }
364 else if(initial_size){
365 pointer reuse = pointer();
366 size_type final_cap = initial_size;
367 m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse);
368 this->set_stored_capacity(final_cap);
369 }
370 }
371
vector_alloc_holderboost::container::vector_alloc_holder372 vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_NOEXCEPT_OR_NOTHROW
373 : allocator_type(BOOST_MOVE_BASE(allocator_type, holder))
374 , m_start(holder.m_start)
375 , m_size(holder.m_size)
376 , m_capacity(holder.m_capacity)
377 {
378 holder.m_start = pointer();
379 holder.m_size = holder.m_capacity = 0;
380 }
381
vector_alloc_holderboost::container::vector_alloc_holder382 vector_alloc_holder(initial_capacity_t, pointer p, size_type n)
383 BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)
384 : allocator_type()
385 , m_start(p)
386 , m_size()
387 //n is guaranteed to fit into stored_size_type
388 , m_capacity(static_cast<stored_size_type>(n))
389 {}
390
391 template<class AllocFwd>
vector_alloc_holderboost::container::vector_alloc_holder392 vector_alloc_holder(initial_capacity_t, pointer p, size_type n, BOOST_FWD_REF(AllocFwd) a)
393 : allocator_type(::boost::forward<AllocFwd>(a))
394 , m_start(p)
395 , m_size()
396 , m_capacity(n)
397 {}
398
~vector_alloc_holderboost::container::vector_alloc_holder399 BOOST_CONTAINER_FORCEINLINE ~vector_alloc_holder() BOOST_NOEXCEPT_OR_NOTHROW
400 {
401 if(this->m_capacity){
402 this->deallocate(this->m_start, this->m_capacity);
403 }
404 }
405
set_stored_sizeboost::container::vector_alloc_holder406 BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
407 { this->m_size = static_cast<stored_size_type>(s); }
408
dec_stored_sizeboost::container::vector_alloc_holder409 BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
410 { this->m_size -= static_cast<stored_size_type>(s); }
411
inc_stored_sizeboost::container::vector_alloc_holder412 BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
413 { this->m_size += static_cast<stored_size_type>(s); }
414
set_stored_capacityboost::container::vector_alloc_holder415 BOOST_CONTAINER_FORCEINLINE void set_stored_capacity(size_type c) BOOST_NOEXCEPT_OR_NOTHROW
416 { this->m_capacity = static_cast<stored_size_type>(c); }
417
allocation_commandboost::container::vector_alloc_holder418 BOOST_CONTAINER_FORCEINLINE pointer allocation_command(boost::container::allocation_type command,
419 size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
420 {
421 typedef typename dtl::version<allocator_type>::type alloc_version;
422 return this->priv_allocation_command(alloc_version(), command, limit_size, prefer_in_recvd_out_size, reuse);
423 }
424
allocateboost::container::vector_alloc_holder425 BOOST_CONTAINER_FORCEINLINE pointer allocate(size_type n)
426 {
427 const size_type max_alloc = allocator_traits_type::max_size(this->alloc());
428 const size_type max = max_alloc <= stored_size_type(-1) ? max_alloc : stored_size_type(-1);
429 if ( max < n )
430 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
431
432 return allocator_traits_type::allocate(this->alloc(), n);
433 }
434
deallocateboost::container::vector_alloc_holder435 BOOST_CONTAINER_FORCEINLINE void deallocate(const pointer &p, size_type n)
436 {
437 allocator_traits_type::deallocate(this->alloc(), p, n);
438 }
439
try_expand_fwdboost::container::vector_alloc_holder440 bool try_expand_fwd(size_type at_least)
441 {
442 //There is not enough memory, try to expand the old one
443 const size_type new_cap = this->capacity() + at_least;
444 size_type real_cap = new_cap;
445 pointer reuse = this->start();
446 bool const success = !!this->allocation_command(expand_fwd, new_cap, real_cap, reuse);
447 //Check for forward expansion
448 if(success){
449 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
450 ++this->num_expand_fwd;
451 #endif
452 this->capacity(real_cap);
453 }
454 return success;
455 }
456
457 template<class GrowthFactorType>
next_capacityboost::container::vector_alloc_holder458 size_type next_capacity(size_type additional_objects) const
459 {
460 BOOST_ASSERT(additional_objects > size_type(this->m_capacity - this->m_size));
461 size_type max = allocator_traits_type::max_size(this->alloc());
462 (clamp_by_stored_size_type<size_type>)(max, stored_size_type());
463 const size_type remaining_cap = max - size_type(this->m_capacity);
464 const size_type min_additional_cap = additional_objects - size_type(this->m_capacity - this->m_size);
465
466 if ( remaining_cap < min_additional_cap )
467 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
468
469 return GrowthFactorType()( size_type(this->m_capacity), min_additional_cap, max);
470 }
471
472 pointer m_start;
473 stored_size_type m_size;
474 stored_size_type m_capacity;
475
swap_resourcesboost::container::vector_alloc_holder476 void swap_resources(vector_alloc_holder &x) BOOST_NOEXCEPT_OR_NOTHROW
477 {
478 boost::adl_move_swap(this->m_start, x.m_start);
479 boost::adl_move_swap(this->m_size, x.m_size);
480 boost::adl_move_swap(this->m_capacity, x.m_capacity);
481 }
482
steal_resourcesboost::container::vector_alloc_holder483 void steal_resources(vector_alloc_holder &x) BOOST_NOEXCEPT_OR_NOTHROW
484 {
485 this->m_start = x.m_start;
486 this->m_size = x.m_size;
487 this->m_capacity = x.m_capacity;
488 x.m_start = pointer();
489 x.m_size = x.m_capacity = 0;
490 }
491
allocboost::container::vector_alloc_holder492 BOOST_CONTAINER_FORCEINLINE allocator_type &alloc() BOOST_NOEXCEPT_OR_NOTHROW
493 { return *this; }
494
allocboost::container::vector_alloc_holder495 BOOST_CONTAINER_FORCEINLINE const allocator_type &alloc() const BOOST_NOEXCEPT_OR_NOTHROW
496 { return *this; }
497
startboost::container::vector_alloc_holder498 BOOST_CONTAINER_FORCEINLINE const pointer &start() const BOOST_NOEXCEPT_OR_NOTHROW
499 { return m_start; }
capacityboost::container::vector_alloc_holder500 BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW
501 { return m_capacity; }
startboost::container::vector_alloc_holder502 BOOST_CONTAINER_FORCEINLINE void start(const pointer &p) BOOST_NOEXCEPT_OR_NOTHROW
503 { m_start = p; }
capacityboost::container::vector_alloc_holder504 BOOST_CONTAINER_FORCEINLINE void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW
505 { BOOST_ASSERT( c <= stored_size_type(-1)); this->set_stored_capacity(c); }
506
on_capacity_overflowboost::container::vector_alloc_holder507 static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow()
508 { }
509
510 private:
priv_first_allocationboost::container::vector_alloc_holder511 void priv_first_allocation(size_type cap)
512 {
513 if(cap){
514 pointer reuse = pointer();
515 m_start = this->allocation_command(allocate_new, cap, cap, reuse);
516 m_capacity = cap;
517 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
518 ++this->num_alloc;
519 #endif
520 }
521 }
522
priv_allocation_commandboost::container::vector_alloc_holder523 pointer priv_allocation_command(version_1, boost::container::allocation_type command,
524 size_type limit_size,
525 size_type &prefer_in_recvd_out_size,
526 pointer &reuse)
527 {
528 (void)command;
529 BOOST_ASSERT( (command & allocate_new));
530 BOOST_ASSERT(!(command & nothrow_allocation));
531 //First detect overflow on smaller stored_size_types
532 if (limit_size > stored_size_type(-1)){
533 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
534 }
535 (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type());
536 pointer const p = this->allocate(prefer_in_recvd_out_size);
537 reuse = pointer();
538 return p;
539 }
540
priv_allocation_commandboost::container::vector_alloc_holder541 pointer priv_allocation_command(version_2, boost::container::allocation_type command,
542 size_type limit_size,
543 size_type &prefer_in_recvd_out_size,
544 pointer &reuse)
545 {
546 //First detect overflow on smaller stored_size_types
547 if (limit_size > stored_size_type(-1)){
548 boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
549 }
550 (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type());
551 //Allocate memory
552 pointer p = this->alloc().allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);
553 //If after allocation prefer_in_recvd_out_size is not representable by stored_size_type, truncate it.
554 (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type());
555 return p;
556 }
557 };
558
559 //!This struct deallocates and allocated memory
560 template <class Allocator, class StoredSizeType>
561 struct vector_alloc_holder<Allocator, StoredSizeType, version_0>
562 : public Allocator
563 {
564 private:
565 BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder)
566
567 public:
568 typedef Allocator allocator_type;
569 typedef boost::container::
570 allocator_traits<allocator_type> allocator_traits_type;
571 typedef typename allocator_traits_type::pointer pointer;
572 typedef typename allocator_traits_type::size_type size_type;
573 typedef typename allocator_traits_type::value_type value_type;
574 typedef StoredSizeType stored_size_type;
575
576 template <class OtherAllocator, class OtherStoredSizeType, class OtherAllocatorVersion>
577 friend struct vector_alloc_holder;
578
579 //Constructor, does not throw
580 vector_alloc_holder()
BOOST_NOEXCEPT_IFboost::container::vector_alloc_holder581 BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)
582 : allocator_type(), m_size()
583 {}
584
585 //Constructor, does not throw
586 template<class AllocConvertible>
vector_alloc_holderboost::container::vector_alloc_holder587 explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_NOEXCEPT_OR_NOTHROW
588 : allocator_type(boost::forward<AllocConvertible>(a)), m_size()
589 {}
590
591 //Constructor, does not throw
592 template<class AllocConvertible>
vector_alloc_holderboost::container::vector_alloc_holder593 vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
594 : allocator_type(boost::forward<AllocConvertible>(a))
595 , m_size(initial_size) //Size is initialized here...
596 {
597 //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor
598 this->priv_first_allocation(initial_size);
599 }
600
601 //Constructor, does not throw
vector_alloc_holderboost::container::vector_alloc_holder602 vector_alloc_holder(vector_uninitialized_size_t, size_type initial_size)
603 : allocator_type()
604 , m_size(initial_size) //Size is initialized here...
605 {
606 //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor
607 this->priv_first_allocation(initial_size);
608 }
609
vector_alloc_holderboost::container::vector_alloc_holder610 vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder)
611 : allocator_type(BOOST_MOVE_BASE(allocator_type, holder))
612 , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this
613 {
614 ::boost::container::uninitialized_move_alloc_n
615 (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), m_size, boost::movelib::to_raw_pointer(this->start()));
616 ::boost::container::destroy_alloc_n
617 (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), m_size);
618 holder.m_size = 0;
619 }
620
621 template<class OtherAllocator, class OtherStoredSizeType, class OtherAllocatorVersion>
vector_alloc_holderboost::container::vector_alloc_holder622 vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder<OtherAllocator, OtherStoredSizeType, OtherAllocatorVersion> BOOST_RV_REF_END holder)
623 : allocator_type()
624 , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort
625 {
626 //Different allocator type so we must check we have enough storage
627 const size_type n = holder.m_size;
628 this->priv_first_allocation(n);
629 ::boost::container::uninitialized_move_alloc_n
630 (this->alloc(), boost::movelib::to_raw_pointer(holder.start()), n, boost::movelib::to_raw_pointer(this->start()));
631 }
632
on_capacity_overflowboost::container::vector_alloc_holder633 static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow()
634 { allocator_type::on_capacity_overflow(); }
635
set_stored_sizeboost::container::vector_alloc_holder636 BOOST_CONTAINER_FORCEINLINE void set_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
637 { this->m_size = static_cast<stored_size_type>(s); }
638
dec_stored_sizeboost::container::vector_alloc_holder639 BOOST_CONTAINER_FORCEINLINE void dec_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
640 { this->m_size -= static_cast<stored_size_type>(s); }
641
inc_stored_sizeboost::container::vector_alloc_holder642 BOOST_CONTAINER_FORCEINLINE void inc_stored_size(size_type s) BOOST_NOEXCEPT_OR_NOTHROW
643 { this->m_size += static_cast<stored_size_type>(s); }
644
priv_first_allocationboost::container::vector_alloc_holder645 BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap)
646 {
647 if(cap > allocator_type::internal_capacity){
648 on_capacity_overflow();
649 }
650 }
651
deep_swapboost::container::vector_alloc_holder652 BOOST_CONTAINER_FORCEINLINE void deep_swap(vector_alloc_holder &x)
653 {
654 this->priv_deep_swap(x);
655 }
656
657 template<class OtherAllocator, class OtherStoredSizeType, class OtherAllocatorVersion>
deep_swapboost::container::vector_alloc_holder658 void deep_swap(vector_alloc_holder<OtherAllocator, OtherStoredSizeType, OtherAllocatorVersion> &x)
659 {
660 typedef typename real_allocator<value_type, OtherAllocator>::type other_allocator_type;
661 if(this->m_size > other_allocator_type::internal_capacity || x.m_size > allocator_type::internal_capacity){
662 on_capacity_overflow();
663 }
664 this->priv_deep_swap(x);
665 }
666
swap_resourcesboost::container::vector_alloc_holder667 BOOST_CONTAINER_FORCEINLINE void swap_resources(vector_alloc_holder &) BOOST_NOEXCEPT_OR_NOTHROW
668 { //Containers with version 0 allocators can't be moved without moving elements one by one
669 on_capacity_overflow();
670 }
671
672
steal_resourcesboost::container::vector_alloc_holder673 BOOST_CONTAINER_FORCEINLINE void steal_resources(vector_alloc_holder &)
674 { //Containers with version 0 allocators can't be moved without moving elements one by one
675 on_capacity_overflow();
676 }
677
allocboost::container::vector_alloc_holder678 BOOST_CONTAINER_FORCEINLINE allocator_type &alloc() BOOST_NOEXCEPT_OR_NOTHROW
679 { return *this; }
680
allocboost::container::vector_alloc_holder681 BOOST_CONTAINER_FORCEINLINE const allocator_type &alloc() const BOOST_NOEXCEPT_OR_NOTHROW
682 { return *this; }
683
try_expand_fwdboost::container::vector_alloc_holder684 BOOST_CONTAINER_FORCEINLINE bool try_expand_fwd(size_type at_least)
685 { return !at_least; }
686
startboost::container::vector_alloc_holder687 BOOST_CONTAINER_FORCEINLINE pointer start() const BOOST_NOEXCEPT_OR_NOTHROW
688 { return allocator_type::internal_storage(); }
689
capacityboost::container::vector_alloc_holder690 BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW
691 { return allocator_type::internal_capacity; }
692
693 stored_size_type m_size;
694
695 private:
696
697 template<class OtherAllocator, class OtherStoredSizeType, class OtherAllocatorVersion>
priv_deep_swapboost::container::vector_alloc_holder698 void priv_deep_swap(vector_alloc_holder<OtherAllocator, OtherStoredSizeType, OtherAllocatorVersion> &x)
699 {
700 const size_type MaxTmpStorage = sizeof(value_type)*allocator_type::internal_capacity;
701 value_type *const first_this = boost::movelib::to_raw_pointer(this->start());
702 value_type *const first_x = boost::movelib::to_raw_pointer(x.start());
703
704 if(this->m_size < x.m_size){
705 boost::container::deep_swap_alloc_n<MaxTmpStorage>(this->alloc(), first_this, this->m_size, first_x, x.m_size);
706 }
707 else{
708 boost::container::deep_swap_alloc_n<MaxTmpStorage>(this->alloc(), first_x, x.m_size, first_this, this->m_size);
709 }
710 boost::adl_move_swap(this->m_size, x.m_size);
711 }
712 };
713
714 struct growth_factor_60;
715
716 template<class Options, class AllocatorSizeType>
717 struct get_vector_opt
718 {
719 typedef vector_opt< typename default_if_void<typename Options::growth_factor_type, growth_factor_60>::type
720 , typename default_if_void<typename Options::stored_size_type, AllocatorSizeType>::type
721 > type;
722 };
723
724 template<class AllocatorSizeType>
725 struct get_vector_opt<void, AllocatorSizeType>
726 {
727 typedef vector_opt<growth_factor_60, AllocatorSizeType> type;
728 };
729
730 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
731
732 //! A vector is a sequence that supports random access to elements, constant
733 //! time insertion and removal of elements at the end, and linear time insertion
734 //! and removal of elements at the beginning or in the middle. The number of
735 //! elements in a vector may vary dynamically; memory management is automatic.
736 //!
737 //! \tparam T The type of object that is stored in the vector
738 //! \tparam A The allocator used for all internal memory management, use void
739 //! for the default allocator
740 //! \tparam Options A type produced from \c boost::container::vector_options.
741 template <class T, class A BOOST_CONTAINER_DOCONLY(= void), class Options BOOST_CONTAINER_DOCONLY(= void) >
742 class vector
743 {
744 public:
745 //////////////////////////////////////////////
746 //
747 // types
748 //
749 //////////////////////////////////////////////
750 typedef T value_type;
751 typedef BOOST_CONTAINER_IMPDEF
752 (typename real_allocator<T BOOST_MOVE_I A>::type) allocator_type;
753 typedef ::boost::container::allocator_traits<allocator_type> allocator_traits_t;
754 typedef typename allocator_traits<allocator_type>::pointer pointer;
755 typedef typename allocator_traits<allocator_type>::const_pointer const_pointer;
756 typedef typename allocator_traits<allocator_type>::reference reference;
757 typedef typename allocator_traits<allocator_type>::const_reference const_reference;
758 typedef typename allocator_traits<allocator_type>::size_type size_type;
759 typedef typename allocator_traits<allocator_type>::difference_type difference_type;
760 typedef allocator_type stored_allocator_type;
761 typedef BOOST_CONTAINER_IMPDEF(vec_iterator<pointer BOOST_MOVE_I false>) iterator;
762 typedef BOOST_CONTAINER_IMPDEF(vec_iterator<pointer BOOST_MOVE_I true >) const_iterator;
763 typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator<iterator>) reverse_iterator;
764 typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator<const_iterator>) const_reverse_iterator;
765
766 private:
767
768 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
769 typedef typename boost::container::
770 allocator_traits<allocator_type>::size_type alloc_size_type;
771 typedef typename get_vector_opt<Options, alloc_size_type>::type options_type;
772 typedef typename options_type::growth_factor_type growth_factor_type;
773 typedef typename options_type::stored_size_type stored_size_type;
774 typedef value_less<T> value_less_t;
775
776 //If provided the stored_size option must specify a type that is equal or a type that is smaller.
777 BOOST_STATIC_ASSERT( (sizeof(stored_size_type) < sizeof(alloc_size_type) ||
778 dtl::is_same<stored_size_type, alloc_size_type>::value) );
779
780 typedef typename dtl::version<allocator_type>::type alloc_version;
781 typedef boost::container::vector_alloc_holder
782 <allocator_type, stored_size_type> alloc_holder_t;
783
784 alloc_holder_t m_holder;
785
786 typedef allocator_traits<allocator_type> allocator_traits_type;
787 template <class U, class UA, class UOptions>
788 friend class vector;
789
790
791 protected:
792 BOOST_CONTAINER_FORCEINLINE
is_propagable_from(const allocator_type & from_alloc,pointer p,const allocator_type & to_alloc,bool const propagate_allocator)793 static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator)
794 { return alloc_holder_t::is_propagable_from(from_alloc, p, to_alloc, propagate_allocator); }
795
796 BOOST_CONTAINER_FORCEINLINE
are_swap_propagable(const allocator_type & l_a,pointer l_p,const allocator_type & r_a,pointer r_p,bool const propagate_allocator)797 static bool are_swap_propagable( const allocator_type &l_a, pointer l_p
798 , const allocator_type &r_a, pointer r_p, bool const propagate_allocator)
799 { return alloc_holder_t::are_swap_propagable(l_a, l_p, r_a, r_p, propagate_allocator); }
800
801 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
802 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
803 private:
804 BOOST_COPYABLE_AND_MOVABLE(vector)
805 typedef vector_value_traits<allocator_type> value_traits;
806 typedef constant_iterator<T, difference_type> cvalue_iterator;
807
808 protected:
809
steal_resources(vector & x)810 BOOST_CONTAINER_FORCEINLINE void steal_resources(vector &x)
811 { return this->m_holder.steal_resources(x.m_holder); }
812
813 template<class AllocFwd>
vector(initial_capacity_t,pointer initial_memory,size_type capacity,BOOST_FWD_REF (AllocFwd)a)814 BOOST_CONTAINER_FORCEINLINE vector(initial_capacity_t, pointer initial_memory, size_type capacity, BOOST_FWD_REF(AllocFwd) a)
815 : m_holder(initial_capacity_t(), initial_memory, capacity, ::boost::forward<AllocFwd>(a))
816 {}
817
vector(initial_capacity_t,pointer initial_memory,size_type capacity)818 BOOST_CONTAINER_FORCEINLINE vector(initial_capacity_t, pointer initial_memory, size_type capacity)
819 : m_holder(initial_capacity_t(), initial_memory, capacity)
820 {}
821
822 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
823
824 public:
825 //////////////////////////////////////////////
826 //
827 // construct/copy/destroy
828 //
829 //////////////////////////////////////////////
830
831 //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
832 //!
833 //! <b>Throws</b>: Nothing.
834 //!
835 //! <b>Complexity</b>: Constant.
BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)836 vector() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)
837 : m_holder()
838 {}
839
840 //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
841 //!
842 //! <b>Throws</b>: Nothing
843 //!
844 //! <b>Complexity</b>: Constant.
vector(const allocator_type & a)845 explicit vector(const allocator_type& a) BOOST_NOEXCEPT_OR_NOTHROW
846 : m_holder(a)
847 {}
848
849 //! <b>Effects</b>: Constructs a vector and inserts n value initialized values.
850 //!
851 //! <b>Throws</b>: If allocator_type's allocation
852 //! throws or T's value initialization throws.
853 //!
854 //! <b>Complexity</b>: Linear to n.
vector(size_type n)855 explicit vector(size_type n)
856 : m_holder(vector_uninitialized_size, n)
857 {
858 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
859 this->num_alloc += n != 0;
860 #endif
861 boost::container::uninitialized_value_init_alloc_n
862 (this->m_holder.alloc(), n, this->priv_raw_begin());
863 }
864
865 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
866 //! and inserts n value initialized values.
867 //!
868 //! <b>Throws</b>: If allocator_type's allocation
869 //! throws or T's value initialization throws.
870 //!
871 //! <b>Complexity</b>: Linear to n.
vector(size_type n,const allocator_type & a)872 explicit vector(size_type n, const allocator_type &a)
873 : m_holder(vector_uninitialized_size, a, n)
874 {
875 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
876 this->num_alloc += n != 0;
877 #endif
878 boost::container::uninitialized_value_init_alloc_n
879 (this->m_holder.alloc(), n, this->priv_raw_begin());
880 }
881
882 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
883 //! and inserts n default initialized values.
884 //!
885 //! <b>Throws</b>: If allocator_type's allocation
886 //! throws or T's default initialization throws.
887 //!
888 //! <b>Complexity</b>: Linear to n.
889 //!
890 //! <b>Note</b>: Non-standard extension
vector(size_type n,default_init_t)891 vector(size_type n, default_init_t)
892 : m_holder(vector_uninitialized_size, n)
893 {
894 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
895 this->num_alloc += n != 0;
896 #endif
897 boost::container::uninitialized_default_init_alloc_n
898 (this->m_holder.alloc(), n, this->priv_raw_begin());
899 }
900
901 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
902 //! and inserts n default initialized values.
903 //!
904 //! <b>Throws</b>: If allocator_type's allocation
905 //! throws or T's default initialization throws.
906 //!
907 //! <b>Complexity</b>: Linear to n.
908 //!
909 //! <b>Note</b>: Non-standard extension
vector(size_type n,default_init_t,const allocator_type & a)910 vector(size_type n, default_init_t, const allocator_type &a)
911 : m_holder(vector_uninitialized_size, a, n)
912 {
913 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
914 this->num_alloc += n != 0;
915 #endif
916 boost::container::uninitialized_default_init_alloc_n
917 (this->m_holder.alloc(), n, this->priv_raw_begin());
918 }
919
920 //! <b>Effects</b>: Constructs a vector
921 //! and inserts n copies of value.
922 //!
923 //! <b>Throws</b>: If allocator_type's allocation
924 //! throws or T's copy constructor throws.
925 //!
926 //! <b>Complexity</b>: Linear to n.
vector(size_type n,const T & value)927 vector(size_type n, const T& value)
928 : m_holder(vector_uninitialized_size, n)
929 {
930 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
931 this->num_alloc += n != 0;
932 #endif
933 boost::container::uninitialized_fill_alloc_n
934 (this->m_holder.alloc(), value, n, this->priv_raw_begin());
935 }
936
937 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
938 //! and inserts n copies of value.
939 //!
940 //! <b>Throws</b>: If allocation
941 //! throws or T's copy constructor throws.
942 //!
943 //! <b>Complexity</b>: Linear to n.
vector(size_type n,const T & value,const allocator_type & a)944 vector(size_type n, const T& value, const allocator_type& a)
945 : m_holder(vector_uninitialized_size, a, n)
946 {
947 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
948 this->num_alloc += n != 0;
949 #endif
950 boost::container::uninitialized_fill_alloc_n
951 (this->m_holder.alloc(), value, n, this->priv_raw_begin());
952 }
953
954 //! <b>Effects</b>: Constructs a vector
955 //! and inserts a copy of the range [first, last) in the vector.
956 //!
957 //! <b>Throws</b>: If allocator_type's allocation
958 //! throws or T's constructor taking a dereferenced InIt throws.
959 //!
960 //! <b>Complexity</b>: Linear to the range [first, last).
961 // template <class InIt>
962 // vector(InIt first, InIt last
963 // BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c
964 // < dtl::is_convertible<InIt BOOST_MOVE_I size_type>::value
965 // BOOST_MOVE_I dtl::nat >::type * = 0)
966 // ) -> vector<typename iterator_traits<InIt>::value_type, new_allocator<typename iterator_traits<InIt>::value_type>>;
967 template <class InIt>
968 vector(InIt first, InIt last
969 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c
970 < dtl::is_convertible<InIt BOOST_MOVE_I size_type>::value
971 BOOST_MOVE_I dtl::nat >::type * = 0)
972 )
973 : m_holder()
974 { this->assign(first, last); }
975
976 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
977 //! and inserts a copy of the range [first, last) in the vector.
978 //!
979 //! <b>Throws</b>: If allocator_type's allocation
980 //! throws or T's constructor taking a dereferenced InIt throws.
981 //!
982 //! <b>Complexity</b>: Linear to the range [first, last).
983 template <class InIt>
984 vector(InIt first, InIt last, const allocator_type& a
985 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_c
986 < dtl::is_convertible<InIt BOOST_MOVE_I size_type>::value
987 BOOST_MOVE_I dtl::nat >::type * = 0)
988 )
989 : m_holder(a)
990 { this->assign(first, last); }
991
992 //! <b>Effects</b>: Copy constructs a vector.
993 //!
994 //! <b>Postcondition</b>: x == *this.
995 //!
996 //! <b>Throws</b>: If allocator_type's allocation
997 //! throws or T's copy constructor throws.
998 //!
999 //! <b>Complexity</b>: Linear to the elements x contains.
vector(const vector & x)1000 vector(const vector &x)
1001 : m_holder( vector_uninitialized_size
1002 , allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc())
1003 , x.size())
1004 {
1005 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1006 this->num_alloc += x.size() != 0;
1007 #endif
1008 ::boost::container::uninitialized_copy_alloc_n
1009 ( this->m_holder.alloc(), x.priv_raw_begin()
1010 , x.size(), this->priv_raw_begin());
1011 }
1012
1013 //! <b>Effects</b>: Move constructor. Moves x's resources to *this.
1014 //!
1015 //! <b>Throws</b>: Nothing
1016 //!
1017 //! <b>Complexity</b>: Constant.
vector(BOOST_RV_REF (vector)x)1018 vector(BOOST_RV_REF(vector) x) BOOST_NOEXCEPT_OR_NOTHROW
1019 : m_holder(boost::move(x.m_holder))
1020 { BOOST_STATIC_ASSERT((!allocator_traits_type::is_partially_propagable::value)); }
1021
1022 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
1023 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
1024 //! and inserts a copy of the range [il.begin(), il.last()) in the vector
1025 //!
1026 //! <b>Throws</b>: If T's constructor taking a dereferenced initializer_list iterator throws.
1027 //!
1028 //! <b>Complexity</b>: Linear to the range [il.begin(), il.end()).
vector(std::initializer_list<value_type> il,const allocator_type & a=allocator_type ())1029 vector(std::initializer_list<value_type> il, const allocator_type& a = allocator_type())
1030 : m_holder(vector_uninitialized_size, a, il.size())
1031 {
1032 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1033 this->num_alloc += il.size() != 0;
1034 #endif
1035 ::boost::container::uninitialized_copy_alloc_n_source
1036 ( this->m_holder.alloc(), il.begin()
1037 , static_cast<size_type>(il.size()), this->priv_raw_begin());
1038 }
1039 #endif
1040
1041 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1042
1043 //! <b>Effects</b>: Move constructor. Moves x's resources to *this.
1044 //!
1045 //! <b>Throws</b>: If T's move constructor or allocation throws
1046 //!
1047 //! <b>Complexity</b>: Linear.
1048 //!
1049 //! <b>Note</b>: Non-standard extension to support static_vector
1050 template<class OtherA>
vector(BOOST_RV_REF_BEG vector<T,OtherA,Options> BOOST_RV_REF_END x,typename dtl::enable_if_c<dtl::is_version<typename real_allocator<T,OtherA>::type,0>::value>::type * =0)1051 vector(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x
1052 , typename dtl::enable_if_c
1053 < dtl::is_version<typename real_allocator<T, OtherA>::type, 0>::value>::type * = 0
1054 )
1055 : m_holder(boost::move(x.m_holder))
1056 {}
1057
1058 #endif // defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1059
1060 //! <b>Effects</b>: Copy constructs a vector using the specified allocator.
1061 //!
1062 //! <b>Postcondition</b>: x == *this.
1063 //!
1064 //! <b>Throws</b>: If allocation
1065 //! throws or T's copy constructor throws.
1066 //!
1067 //! <b>Complexity</b>: Linear to the elements x contains.
vector(const vector & x,const allocator_type & a)1068 vector(const vector &x, const allocator_type &a)
1069 : m_holder(vector_uninitialized_size, a, x.size())
1070 {
1071 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1072 this->num_alloc += x.size() != 0;
1073 #endif
1074 ::boost::container::uninitialized_copy_alloc_n_source
1075 ( this->m_holder.alloc(), x.priv_raw_begin()
1076 , x.size(), this->priv_raw_begin());
1077 }
1078
1079 //! <b>Effects</b>: Move constructor using the specified allocator.
1080 //! Moves x's resources to *this if a == allocator_type().
1081 //! Otherwise copies values from x to *this.
1082 //!
1083 //! <b>Throws</b>: If allocation or T's copy constructor throws.
1084 //!
1085 //! <b>Complexity</b>: Constant if a == x.get_allocator(), linear otherwise.
vector(BOOST_RV_REF (vector)x,const allocator_type & a)1086 vector(BOOST_RV_REF(vector) x, const allocator_type &a)
1087 : m_holder( vector_uninitialized_size, a
1088 //In this allocator move constructor the allocator won't be propagated --v
1089 , is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, false) ? 0 : x.size()
1090 )
1091 {
1092 //In this allocator move constructor the allocator won't be propagated ---v
1093 if(is_propagable_from(x.get_stored_allocator(), x.m_holder.start(), a, false)){
1094 this->m_holder.steal_resources(x.m_holder);
1095 }
1096 else{
1097 const size_type n = x.size();
1098 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1099 this->num_alloc += n != 0;
1100 #endif
1101 ::boost::container::uninitialized_move_alloc_n_source
1102 ( this->m_holder.alloc(), x.priv_raw_begin()
1103 , n, this->priv_raw_begin());
1104 }
1105 }
1106
1107 //! <b>Effects</b>: Destroys the vector. All stored values are destroyed
1108 //! and used memory is deallocated.
1109 //!
1110 //! <b>Throws</b>: Nothing.
1111 //!
1112 //! <b>Complexity</b>: Linear to the number of elements.
~vector()1113 ~vector() BOOST_NOEXCEPT_OR_NOTHROW
1114 {
1115 boost::container::destroy_alloc_n
1116 (this->get_stored_allocator(), this->priv_raw_begin(), this->m_holder.m_size);
1117 //vector_alloc_holder deallocates the data
1118 }
1119
1120 //! <b>Effects</b>: Makes *this contain the same elements as x.
1121 //!
1122 //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
1123 //! of each of x's elements.
1124 //!
1125 //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor/assignment throws.
1126 //!
1127 //! <b>Complexity</b>: Linear to the number of elements in x.
operator =(BOOST_COPY_ASSIGN_REF (vector)x)1128 BOOST_CONTAINER_FORCEINLINE vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x)
1129 {
1130 if (BOOST_LIKELY(&x != this)){
1131 this->priv_copy_assign(x);
1132 }
1133 return *this;
1134 }
1135
1136 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
1137 //! <b>Effects</b>: Make *this container contains elements from il.
1138 //!
1139 //! <b>Complexity</b>: Linear to the range [il.begin(), il.end()).
operator =(std::initializer_list<value_type> il)1140 BOOST_CONTAINER_FORCEINLINE vector& operator=(std::initializer_list<value_type> il)
1141 {
1142 this->assign(il.begin(), il.end());
1143 return *this;
1144 }
1145 #endif
1146
1147 //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
1148 //!
1149 //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
1150 //! before the function.
1151 //!
1152 //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment
1153 //! is false and (allocation throws or value_type's move constructor throws)
1154 //!
1155 //! <b>Complexity</b>: Constant if allocator_traits_type::
1156 //! propagate_on_container_move_assignment is true or
1157 //! this->get>allocator() == x.get_allocator(). Linear otherwise.
operator =(BOOST_RV_REF (vector)x)1158 BOOST_CONTAINER_FORCEINLINE vector& operator=(BOOST_RV_REF(vector) x)
1159 BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value
1160 || allocator_traits_type::is_always_equal::value)
1161 {
1162 if (BOOST_LIKELY(&x != this)){
1163 this->priv_move_assign(boost::move(x));
1164 }
1165 return *this;
1166 }
1167
1168 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1169
1170 //! <b>Effects</b>: Move assignment. All x's values are transferred to *this.
1171 //!
1172 //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
1173 //! before the function.
1174 //!
1175 //! <b>Throws</b>: If move constructor/assignment of T throws or allocation throws
1176 //!
1177 //! <b>Complexity</b>: Linear.
1178 //!
1179 //! <b>Note</b>: Non-standard extension to support static_vector
1180 template<class OtherA>
1181 BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and
1182 < vector&
1183 , dtl::is_version<typename real_allocator<T, OtherA>::type, 0>
1184 , dtl::is_different<typename real_allocator<T, OtherA>::type, allocator_type>
1185 >::type
operator =(BOOST_RV_REF_BEG vector<value_type,OtherA,Options> BOOST_RV_REF_END x)1186 operator=(BOOST_RV_REF_BEG vector<value_type, OtherA, Options> BOOST_RV_REF_END x)
1187 {
1188 this->priv_move_assign(boost::move(x));
1189 return *this;
1190 }
1191
1192 //! <b>Effects</b>: Copy assignment. All x's values are copied to *this.
1193 //!
1194 //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
1195 //! before the function.
1196 //!
1197 //! <b>Throws</b>: If move constructor/assignment of T throws or allocation throws
1198 //!
1199 //! <b>Complexity</b>: Linear.
1200 //!
1201 //! <b>Note</b>: Non-standard extension to support static_vector
1202 template<class OtherA>
1203 BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_and
1204 < vector&
1205 , dtl::is_version<typename real_allocator<T, OtherA>::type, 0>
1206 , dtl::is_different<typename real_allocator<T, OtherA>::type, allocator_type>
1207 >::type
operator =(const vector<value_type,OtherA,Options> & x)1208 operator=(const vector<value_type, OtherA, Options> &x)
1209 {
1210 this->priv_copy_assign(x);
1211 return *this;
1212 }
1213
1214 #endif
1215
1216 //! <b>Effects</b>: Assigns the the range [first, last) to *this.
1217 //!
1218 //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor/assignment or
1219 //! T's constructor/assignment from dereferencing InpIt throws.
1220 //!
1221 //! <b>Complexity</b>: Linear to n.
1222 template <class InIt>
1223 void assign(InIt first, InIt last
1224 //Input iterators or version 0 allocator
1225 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or
1226 < void
1227 BOOST_MOVE_I dtl::is_convertible<InIt BOOST_MOVE_I size_type>
1228 BOOST_MOVE_I dtl::and_
1229 < dtl::is_different<alloc_version BOOST_MOVE_I version_0>
1230 BOOST_MOVE_I dtl::is_not_input_iterator<InIt>
1231 >
1232 >::type * = 0)
1233 )
1234 {
1235 //Overwrite all elements we can from [first, last)
1236 iterator cur = this->begin();
1237 const iterator end_it = this->end();
1238 for ( ; first != last && cur != end_it; ++cur, ++first){
1239 *cur = *first;
1240 }
1241
1242 if (first == last){
1243 //There are no more elements in the sequence, erase remaining
1244 T* const end_pos = this->priv_raw_end();
1245 const size_type n = static_cast<size_type>(end_pos - boost::movelib::iterator_to_raw_pointer(cur));
1246 this->priv_destroy_last_n(n);
1247 }
1248 else{
1249 //There are more elements in the range, insert the remaining ones
1250 this->insert(this->cend(), first, last);
1251 }
1252 }
1253
1254 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
1255 //! <b>Effects</b>: Assigns the the range [il.begin(), il.end()) to *this.
1256 //!
1257 //! <b>Throws</b>: If memory allocation throws or
1258 //! T's constructor from dereferencing iniializer_list iterator throws.
1259 //!
assign(std::initializer_list<T> il)1260 BOOST_CONTAINER_FORCEINLINE void assign(std::initializer_list<T> il)
1261 {
1262 this->assign(il.begin(), il.end());
1263 }
1264 #endif
1265
1266 //! <b>Effects</b>: Assigns the the range [first, last) to *this.
1267 //!
1268 //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor/assignment or
1269 //! T's constructor/assignment from dereferencing InpIt throws.
1270 //!
1271 //! <b>Complexity</b>: Linear to n.
1272 template <class FwdIt>
1273 void assign(FwdIt first, FwdIt last
1274 //Forward iterators and version > 0 allocator
1275 BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or
1276 < void
1277 BOOST_MOVE_I dtl::is_same<alloc_version BOOST_MOVE_I version_0>
1278 BOOST_MOVE_I dtl::is_convertible<FwdIt BOOST_MOVE_I size_type>
1279 BOOST_MOVE_I dtl::is_input_iterator<FwdIt>
1280 >::type * = 0)
1281 )
1282 {
1283 //For Fwd iterators the standard only requires EmplaceConstructible and assignable from *first
1284 //so we can't do any backwards allocation
1285 const typename iterator_traits<FwdIt>::size_type sz = boost::container::iterator_distance(first, last);
1286 if (sz > size_type(-1)){
1287 boost::container::throw_length_error("vector::assign, FwdIt's max length reached");
1288 }
1289
1290 const size_type input_sz = static_cast<size_type>(sz);
1291 const size_type old_capacity = this->capacity();
1292 if(input_sz > old_capacity){ //If input range is too big, we need to reallocate
1293 size_type real_cap = 0;
1294 pointer reuse(this->m_holder.start());
1295 pointer const ret(this->m_holder.allocation_command(allocate_new|expand_fwd, input_sz, real_cap = input_sz, reuse));
1296 if(!reuse){ //New allocation, just emplace new values
1297 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1298 ++this->num_alloc;
1299 #endif
1300 pointer const old_p = this->m_holder.start();
1301 if(old_p){
1302 this->priv_destroy_all();
1303 this->m_holder.deallocate(old_p, old_capacity);
1304 }
1305 this->m_holder.start(ret);
1306 this->m_holder.capacity(real_cap);
1307 this->m_holder.m_size = 0;
1308 this->priv_uninitialized_construct_at_end(first, last);
1309 return;
1310 }
1311 else{
1312 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
1313 ++this->num_expand_fwd;
1314 #endif
1315 this->m_holder.capacity(real_cap);
1316 //Forward expansion, use assignment + back deletion/construction that comes later
1317 }
1318 }
1319
1320 boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), first, input_sz, this->priv_raw_begin(), this->size());
1321 m_holder.set_stored_size(input_sz);
1322 }
1323
1324 //! <b>Effects</b>: Assigns the n copies of val to *this.
1325 //!
1326 //! <b>Throws</b>: If memory allocation throws or
1327 //! T's copy/move constructor/assignment throws.
1328 //!
1329 //! <b>Complexity</b>: Linear to n.
assign(size_type n,const value_type & val)1330 BOOST_CONTAINER_FORCEINLINE void assign(size_type n, const value_type& val)
1331 { this->assign(cvalue_iterator(val, n), cvalue_iterator()); }
1332
1333 //! <b>Effects</b>: Returns a copy of the internal allocator.
1334 //!
1335 //! <b>Throws</b>: If allocator's copy constructor throws.
1336 //!
1337 //! <b>Complexity</b>: Constant.
get_allocator() const1338 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW
1339 { return this->m_holder.alloc(); }
1340
1341 //! <b>Effects</b>: Returns a reference to the internal allocator.
1342 //!
1343 //! <b>Throws</b>: Nothing
1344 //!
1345 //! <b>Complexity</b>: Constant.
1346 //!
1347 //! <b>Note</b>: Non-standard extension.
1348 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_stored_allocator()1349 stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW
1350 { return this->m_holder.alloc(); }
1351
1352 //! <b>Effects</b>: Returns a reference to the internal allocator.
1353 //!
1354 //! <b>Throws</b>: Nothing
1355 //!
1356 //! <b>Complexity</b>: Constant.
1357 //!
1358 //! <b>Note</b>: Non-standard extension.
1359 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
get_stored_allocator() const1360 const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW
1361 { return this->m_holder.alloc(); }
1362
1363 //////////////////////////////////////////////
1364 //
1365 // iterators
1366 //
1367 //////////////////////////////////////////////
1368
1369 //! <b>Effects</b>: Returns an iterator to the first element contained in the vector.
1370 //!
1371 //! <b>Throws</b>: Nothing.
1372 //!
1373 //! <b>Complexity</b>: Constant.
begin()1374 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE iterator begin() BOOST_NOEXCEPT_OR_NOTHROW
1375 { return iterator(this->m_holder.start()); }
1376
1377 //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
1378 //!
1379 //! <b>Throws</b>: Nothing.
1380 //!
1381 //! <b>Complexity</b>: Constant.
begin() const1382 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW
1383 { return const_iterator(this->m_holder.start()); }
1384
1385 //! <b>Effects</b>: Returns an iterator to the end of the vector.
1386 //!
1387 //! <b>Throws</b>: Nothing.
1388 //!
1389 //! <b>Complexity</b>: Constant.
end()1390 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW
1391 {
1392 iterator it (this->m_holder.start());
1393 it += this->m_holder.m_size;
1394 return it; //Adding zero to null pointer is allowed (non-UB)
1395 }
1396
1397 //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
1398 //!
1399 //! <b>Throws</b>: Nothing.
1400 //!
1401 //! <b>Complexity</b>: Constant.
end() const1402 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW
1403 { return this->cend(); }
1404
1405 //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
1406 //! of the reversed vector.
1407 //!
1408 //! <b>Throws</b>: Nothing.
1409 //!
1410 //! <b>Complexity</b>: Constant.
rbegin()1411 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW
1412 { return reverse_iterator(this->end()); }
1413
1414 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
1415 //! of the reversed vector.
1416 //!
1417 //! <b>Throws</b>: Nothing.
1418 //!
1419 //! <b>Complexity</b>: Constant.
rbegin() const1420 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW
1421 { return this->crbegin(); }
1422
1423 //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
1424 //! of the reversed vector.
1425 //!
1426 //! <b>Throws</b>: Nothing.
1427 //!
1428 //! <b>Complexity</b>: Constant.
rend()1429 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW
1430 { return reverse_iterator(this->begin()); }
1431
1432 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
1433 //! of the reversed vector.
1434 //!
1435 //! <b>Throws</b>: Nothing.
1436 //!
1437 //! <b>Complexity</b>: Constant.
rend() const1438 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW
1439 { return this->crend(); }
1440
1441 //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
1442 //!
1443 //! <b>Throws</b>: Nothing.
1444 //!
1445 //! <b>Complexity</b>: Constant.
cbegin() const1446 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW
1447 { return const_iterator(this->m_holder.start()); }
1448
1449 //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
1450 //!
1451 //! <b>Throws</b>: Nothing.
1452 //!
1453 //! <b>Complexity</b>: Constant.
cend() const1454 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW
1455 {
1456 const_iterator it (this->m_holder.start());
1457 it += this->m_holder.m_size;
1458 return it; //Adding zero to null pointer is allowed (non-UB)
1459 }
1460
1461 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
1462 //! of the reversed vector.
1463 //!
1464 //! <b>Throws</b>: Nothing.
1465 //!
1466 //! <b>Complexity</b>: Constant.
crbegin() const1467 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW
1468 { return const_reverse_iterator(this->end());}
1469
1470 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
1471 //! of the reversed vector.
1472 //!
1473 //! <b>Throws</b>: Nothing.
1474 //!
1475 //! <b>Complexity</b>: Constant.
crend() const1476 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW
1477 { return const_reverse_iterator(this->begin()); }
1478
1479 //////////////////////////////////////////////
1480 //
1481 // capacity
1482 //
1483 //////////////////////////////////////////////
1484
1485 //! <b>Effects</b>: Returns true if the vector contains no elements.
1486 //!
1487 //! <b>Throws</b>: Nothing.
1488 //!
1489 //! <b>Complexity</b>: Constant.
empty() const1490 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE bool empty() const BOOST_NOEXCEPT_OR_NOTHROW
1491 { return !this->m_holder.m_size; }
1492
1493 //! <b>Effects</b>: Returns the number of the elements contained in the vector.
1494 //!
1495 //! <b>Throws</b>: Nothing.
1496 //!
1497 //! <b>Complexity</b>: Constant.
size() const1498 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type size() const BOOST_NOEXCEPT_OR_NOTHROW
1499 { return this->m_holder.m_size; }
1500
1501 //! <b>Effects</b>: Returns the largest possible size of the vector.
1502 //!
1503 //! <b>Throws</b>: Nothing.
1504 //!
1505 //! <b>Complexity</b>: Constant.
max_size() const1506 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW
1507 { return allocator_traits_type::max_size(this->m_holder.alloc()); }
1508
1509 //! <b>Effects</b>: Inserts or erases elements at the end such that
1510 //! the size becomes n. New elements are value initialized.
1511 //!
1512 //! <b>Throws</b>: If memory allocation throws, or T's copy/move or value initialization throws.
1513 //!
1514 //! <b>Complexity</b>: Linear to the difference between size() and new_size.
resize(size_type new_size)1515 BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size)
1516 { this->priv_resize(new_size, value_init, alloc_version()); }
1517
1518 //! <b>Effects</b>: Inserts or erases elements at the end such that
1519 //! the size becomes n. New elements are default initialized.
1520 //!
1521 //! <b>Throws</b>: If memory allocation throws, or T's copy/move or default initialization throws.
1522 //!
1523 //! <b>Complexity</b>: Linear to the difference between size() and new_size.
1524 //!
1525 //! <b>Note</b>: Non-standard extension
resize(size_type new_size,default_init_t)1526 BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, default_init_t)
1527 { this->priv_resize(new_size, default_init, alloc_version()); }
1528
1529 //! <b>Effects</b>: Inserts or erases elements at the end such that
1530 //! the size becomes n. New elements are copy constructed from x.
1531 //!
1532 //! <b>Throws</b>: If memory allocation throws, or T's copy/move constructor throws.
1533 //!
1534 //! <b>Complexity</b>: Linear to the difference between size() and new_size.
resize(size_type new_size,const T & x)1535 BOOST_CONTAINER_FORCEINLINE void resize(size_type new_size, const T& x)
1536 { this->priv_resize(new_size, x, alloc_version()); }
1537
1538 //! <b>Effects</b>: Number of elements for which memory has been allocated.
1539 //! capacity() is always greater than or equal to size().
1540 //!
1541 //! <b>Throws</b>: Nothing.
1542 //!
1543 //! <b>Complexity</b>: Constant.
capacity() const1544 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW
1545 { return this->m_holder.capacity(); }
1546
1547 //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
1548 //! effect. Otherwise, it is a request for allocation of additional memory.
1549 //! If the request is successful, then capacity() is greater than or equal to
1550 //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
1551 //!
1552 //! <b>Throws</b>: If memory allocation allocation throws or T's copy/move constructor throws.
reserve(size_type new_cap)1553 BOOST_CONTAINER_FORCEINLINE void reserve(size_type new_cap)
1554 {
1555 if (this->capacity() < new_cap){
1556 this->priv_move_to_new_buffer(new_cap, alloc_version());
1557 }
1558 }
1559
1560 //! <b>Effects</b>: Tries to deallocate the excess of memory created
1561 //! with previous allocations. The size of the vector is unchanged
1562 //!
1563 //! <b>Throws</b>: If memory allocation throws, or T's copy/move constructor throws.
1564 //!
1565 //! <b>Complexity</b>: Linear to size().
shrink_to_fit()1566 BOOST_CONTAINER_FORCEINLINE void shrink_to_fit()
1567 { this->priv_shrink_to_fit(alloc_version()); }
1568
1569 //////////////////////////////////////////////
1570 //
1571 // element access
1572 //
1573 //////////////////////////////////////////////
1574
1575 //! <b>Requires</b>: !empty()
1576 //!
1577 //! <b>Effects</b>: Returns a reference to the first
1578 //! element of the container.
1579 //!
1580 //! <b>Throws</b>: Nothing.
1581 //!
1582 //! <b>Complexity</b>: Constant.
front()1583 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference front() BOOST_NOEXCEPT_OR_NOTHROW
1584 {
1585 BOOST_ASSERT(!this->empty());
1586 return *this->m_holder.start();
1587 }
1588
1589 //! <b>Requires</b>: !empty()
1590 //!
1591 //! <b>Effects</b>: Returns a const reference to the first
1592 //! element of the container.
1593 //!
1594 //! <b>Throws</b>: Nothing.
1595 //!
1596 //! <b>Complexity</b>: Constant.
front() const1597 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW
1598 {
1599 BOOST_ASSERT(!this->empty());
1600 return *this->m_holder.start();
1601 }
1602
1603 //! <b>Requires</b>: !empty()
1604 //!
1605 //! <b>Effects</b>: Returns a reference to the last
1606 //! element of the container.
1607 //!
1608 //! <b>Throws</b>: Nothing.
1609 //!
1610 //! <b>Complexity</b>: Constant.
back()1611 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference back() BOOST_NOEXCEPT_OR_NOTHROW
1612 {
1613 BOOST_ASSERT(!this->empty());
1614 return this->m_holder.start()[this->m_holder.m_size - 1];
1615 }
1616
1617 //! <b>Requires</b>: !empty()
1618 //!
1619 //! <b>Effects</b>: Returns a const reference to the last
1620 //! element of the container.
1621 //!
1622 //! <b>Throws</b>: Nothing.
1623 //!
1624 //! <b>Complexity</b>: Constant.
back() const1625 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW
1626 {
1627 BOOST_ASSERT(!this->empty());
1628 return this->m_holder.start()[this->m_holder.m_size - 1];
1629 }
1630
1631 //! <b>Requires</b>: size() > n.
1632 //!
1633 //! <b>Effects</b>: Returns a reference to the nth element
1634 //! from the beginning of the container.
1635 //!
1636 //! <b>Throws</b>: Nothing.
1637 //!
1638 //! <b>Complexity</b>: Constant.
operator [](size_type n)1639 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW
1640 {
1641 BOOST_ASSERT(this->m_holder.m_size > n);
1642 return this->m_holder.start()[n];
1643 }
1644
1645 //! <b>Requires</b>: size() > n.
1646 //!
1647 //! <b>Effects</b>: Returns a const reference to the nth element
1648 //! from the beginning of the container.
1649 //!
1650 //! <b>Throws</b>: Nothing.
1651 //!
1652 //! <b>Complexity</b>: Constant.
1653 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
operator [](size_type n) const1654 const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW
1655 {
1656 BOOST_ASSERT(this->m_holder.m_size > n);
1657 return this->m_holder.start()[n];
1658 }
1659
1660 //! <b>Requires</b>: size() >= n.
1661 //!
1662 //! <b>Effects</b>: Returns an iterator to the nth element
1663 //! from the beginning of the container. Returns end()
1664 //! if n == size().
1665 //!
1666 //! <b>Throws</b>: Nothing.
1667 //!
1668 //! <b>Complexity</b>: Constant.
1669 //!
1670 //! <b>Note</b>: Non-standard extension
1671 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
nth(size_type n)1672 iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW
1673 {
1674 BOOST_ASSERT(this->m_holder.m_size >= n);
1675 return iterator(this->m_holder.start()+n);
1676 }
1677
1678 //! <b>Requires</b>: size() >= n.
1679 //!
1680 //! <b>Effects</b>: Returns a const_iterator to the nth element
1681 //! from the beginning of the container. Returns end()
1682 //! if n == size().
1683 //!
1684 //! <b>Throws</b>: Nothing.
1685 //!
1686 //! <b>Complexity</b>: Constant.
1687 //!
1688 //! <b>Note</b>: Non-standard extension
1689 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
nth(size_type n) const1690 const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW
1691 {
1692 BOOST_ASSERT(this->m_holder.m_size >= n);
1693 return const_iterator(this->m_holder.start()+n);
1694 }
1695
1696 //! <b>Requires</b>: begin() <= p <= end().
1697 //!
1698 //! <b>Effects</b>: Returns the index of the element pointed by p
1699 //! and size() if p == end().
1700 //!
1701 //! <b>Throws</b>: Nothing.
1702 //!
1703 //! <b>Complexity</b>: Constant.
1704 //!
1705 //! <b>Note</b>: Non-standard extension
1706 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
index_of(iterator p)1707 size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW
1708 {
1709 //Range check assert done in priv_index_of
1710 return this->priv_index_of(vector_iterator_get_ptr(p));
1711 }
1712
1713 //! <b>Requires</b>: begin() <= p <= end().
1714 //!
1715 //! <b>Effects</b>: Returns the index of the element pointed by p
1716 //! and size() if p == end().
1717 //!
1718 //! <b>Throws</b>: Nothing.
1719 //!
1720 //! <b>Complexity</b>: Constant.
1721 //!
1722 //! <b>Note</b>: Non-standard extension
1723 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE
index_of(const_iterator p) const1724 size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW
1725 {
1726 //Range check assert done in priv_index_of
1727 return this->priv_index_of(vector_iterator_get_ptr(p));
1728 }
1729
1730 //! <b>Requires</b>: size() > n.
1731 //!
1732 //! <b>Effects</b>: Returns a reference to the nth element
1733 //! from the beginning of the container.
1734 //!
1735 //! <b>Throws</b>: range_error if n >= size()
1736 //!
1737 //! <b>Complexity</b>: Constant.
at(size_type n)1738 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE reference at(size_type n)
1739 {
1740 this->priv_throw_if_out_of_range(n);
1741 return this->m_holder.start()[n];
1742 }
1743
1744 //! <b>Requires</b>: size() > n.
1745 //!
1746 //! <b>Effects</b>: Returns a const reference to the nth element
1747 //! from the beginning of the container.
1748 //!
1749 //! <b>Throws</b>: range_error if n >= size()
1750 //!
1751 //! <b>Complexity</b>: Constant.
at(size_type n) const1752 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const_reference at(size_type n) const
1753 {
1754 this->priv_throw_if_out_of_range(n);
1755 return this->m_holder.start()[n];
1756 }
1757
1758 //////////////////////////////////////////////
1759 //
1760 // data access
1761 //
1762 //////////////////////////////////////////////
1763
1764 //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
1765 //! For a non-empty vector, data() == &front().
1766 //!
1767 //! <b>Throws</b>: Nothing.
1768 //!
1769 //! <b>Complexity</b>: Constant.
data()1770 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE T* data() BOOST_NOEXCEPT_OR_NOTHROW
1771 { return this->priv_raw_begin(); }
1772
1773 //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
1774 //! For a non-empty vector, data() == &front().
1775 //!
1776 //! <b>Throws</b>: Nothing.
1777 //!
1778 //! <b>Complexity</b>: Constant.
data() const1779 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE const T * data() const BOOST_NOEXCEPT_OR_NOTHROW
1780 { return this->priv_raw_begin(); }
1781
1782 //////////////////////////////////////////////
1783 //
1784 // modifiers
1785 //
1786 //////////////////////////////////////////////
1787
1788 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1789 //! <b>Effects</b>: Inserts an object of type T constructed with
1790 //! std::forward<Args>(args)... in the end of the vector.
1791 //!
1792 //! <b>Returns</b>: A reference to the created object.
1793 //!
1794 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws or
1795 //! T's copy/move constructor throws.
1796 //!
1797 //! <b>Complexity</b>: Amortized constant time.
1798 template<class ...Args>
emplace_back(BOOST_FWD_REF (Args)...args)1799 BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_FWD_REF(Args)...args)
1800 {
1801 T* const p = this->priv_raw_end();
1802 if (BOOST_LIKELY(this->room_enough())){
1803 //There is more memory, just construct a new object at the end
1804 allocator_traits_type::construct(this->m_holder.alloc(), p, ::boost::forward<Args>(args)...);
1805 ++this->m_holder.m_size;
1806 return *p;
1807 }
1808 else{
1809 typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t;
1810 return *this->priv_insert_forward_range_no_capacity
1811 (p, 1, proxy_t(::boost::forward<Args>(args)...), alloc_version());
1812 }
1813 }
1814
1815 //! <b>Effects</b>: Inserts an object of type T constructed with
1816 //! std::forward<Args>(args)... in the end of the vector.
1817 //!
1818 //! <b>Throws</b>: If the in-place constructor throws.
1819 //!
1820 //! <b>Complexity</b>: Constant time.
1821 //!
1822 //! <b>Note</b>: Non-standard extension.
1823 template<class ...Args>
stable_emplace_back(BOOST_FWD_REF (Args)...args)1824 BOOST_CONTAINER_FORCEINLINE bool stable_emplace_back(BOOST_FWD_REF(Args)...args)
1825 {
1826 const bool is_room_enough = this->room_enough() || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(1u));
1827 if (BOOST_LIKELY(is_room_enough)){
1828 //There is more memory, just construct a new object at the end
1829 allocator_traits_type::construct(this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward<Args>(args)...);
1830 ++this->m_holder.m_size;
1831 }
1832 return is_room_enough;
1833 }
1834
1835 //! <b>Requires</b>: position must be a valid iterator of *this.
1836 //!
1837 //! <b>Effects</b>: Inserts an object of type T constructed with
1838 //! std::forward<Args>(args)... before position
1839 //!
1840 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws or
1841 //! T's copy/move constructor/assignment throws.
1842 //!
1843 //! <b>Complexity</b>: If position is end(), amortized constant time
1844 //! Linear time otherwise.
1845 template<class ...Args>
emplace(const_iterator position,BOOST_FWD_REF (Args)...args)1846 BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator position, BOOST_FWD_REF(Args) ...args)
1847 {
1848 BOOST_ASSERT(this->priv_in_range_or_end(position));
1849 //Just call more general insert(pos, size, value) and return iterator
1850 typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t;
1851 return this->priv_insert_forward_range( vector_iterator_get_ptr(position), 1
1852 , proxy_t(::boost::forward<Args>(args)...));
1853 }
1854
1855 #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
1856
1857 #define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \
1858 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1859 BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_MOVE_UREF##N)\
1860 {\
1861 T* const p = this->priv_raw_end();\
1862 if (BOOST_LIKELY(this->room_enough())){\
1863 allocator_traits_type::construct (this->m_holder.alloc()\
1864 , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1865 ++this->m_holder.m_size;\
1866 return *p;\
1867 }\
1868 else{\
1869 typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\
1870 return *this->priv_insert_forward_range_no_capacity\
1871 ( p, 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\
1872 }\
1873 }\
1874 \
1875 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1876 BOOST_CONTAINER_FORCEINLINE bool stable_emplace_back(BOOST_MOVE_UREF##N)\
1877 {\
1878 const bool is_room_enough = this->room_enough() || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(1u));\
1879 if (BOOST_LIKELY(is_room_enough)){\
1880 allocator_traits_type::construct (this->m_holder.alloc()\
1881 , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
1882 ++this->m_holder.m_size;\
1883 }\
1884 return is_room_enough;\
1885 }\
1886 \
1887 BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
1888 BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
1889 {\
1890 BOOST_ASSERT(this->priv_in_range_or_end(pos));\
1891 typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\
1892 return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), 1, proxy_t(BOOST_MOVE_FWD##N));\
1893 }\
1894 //
1895 BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VECTOR_EMPLACE_CODE)
1896 #undef BOOST_CONTAINER_VECTOR_EMPLACE_CODE
1897
1898 #endif
1899
1900 #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1901 //! <b>Effects</b>: Inserts a copy of x at the end of the vector.
1902 //!
1903 //! <b>Throws</b>: If memory allocation throws or
1904 //! T's copy/move constructor throws.
1905 //!
1906 //! <b>Complexity</b>: Amortized constant time.
1907 void push_back(const T &x);
1908
1909 //! <b>Effects</b>: Constructs a new element in the end of the vector
1910 //! and moves the resources of x to this new element.
1911 //!
1912 //! <b>Throws</b>: If memory allocation throws or
1913 //! T's copy/move constructor throws.
1914 //!
1915 //! <b>Complexity</b>: Amortized constant time.
1916 void push_back(T &&x);
1917 #else
1918 BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back)
1919 #endif
1920
1921 #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1922 //! <b>Requires</b>: position must be a valid iterator of *this.
1923 //!
1924 //! <b>Effects</b>: Insert a copy of x before position.
1925 //!
1926 //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor/assignment throws.
1927 //!
1928 //! <b>Complexity</b>: If position is end(), amortized constant time
1929 //! Linear time otherwise.
1930 iterator insert(const_iterator position, const T &x);
1931
1932 //! <b>Requires</b>: position must be a valid iterator of *this.
1933 //!
1934 //! <b>Effects</b>: Insert a new element before position with x's resources.
1935 //!
1936 //! <b>Throws</b>: If memory allocation throws.
1937 //!
1938 //! <b>Complexity</b>: If position is end(), amortized constant time
1939 //! Linear time otherwise.
1940 iterator insert(const_iterator position, T &&x);
1941 #else
BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert,T,iterator,priv_insert,const_iterator,const_iterator)1942 BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator)
1943 #endif
1944
1945 //! <b>Requires</b>: p must be a valid iterator of *this.
1946 //!
1947 //! <b>Effects</b>: Insert n copies of x before pos.
1948 //!
1949 //! <b>Returns</b>: an iterator to the first inserted element or p if n is 0.
1950 //!
1951 //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor throws.
1952 //!
1953 //! <b>Complexity</b>: Linear to n.
1954 BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, size_type n, const T& x)
1955 {
1956 BOOST_ASSERT(this->priv_in_range_or_end(p));
1957 dtl::insert_n_copies_proxy<allocator_type, T*> proxy(x);
1958 return this->priv_insert_forward_range(vector_iterator_get_ptr(p), n, proxy);
1959 }
1960
1961 //! <b>Requires</b>: p must be a valid iterator of *this.
1962 //!
1963 //! <b>Effects</b>: Insert a copy of the [first, last) range before pos.
1964 //!
1965 //! <b>Returns</b>: an iterator to the first inserted element or pos if first == last.
1966 //!
1967 //! <b>Throws</b>: If memory allocation throws, T's constructor from a
1968 //! dereferenced InpIt throws or T's copy/move constructor/assignment throws.
1969 //!
1970 //! <b>Complexity</b>: Linear to boost::container::iterator_distance [first, last).
1971 template <class InIt>
insert(const_iterator pos,InIt first,InIt last,typename dtl::disable_if_or<void,dtl::is_convertible<InIt,size_type>,dtl::is_not_input_iterator<InIt>>::type * =0)1972 iterator insert(const_iterator pos, InIt first, InIt last
1973 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1974 , typename dtl::disable_if_or
1975 < void
1976 , dtl::is_convertible<InIt, size_type>
1977 , dtl::is_not_input_iterator<InIt>
1978 >::type * = 0
1979 #endif
1980 )
1981 {
1982 BOOST_ASSERT(this->priv_in_range_or_end(pos));
1983 const size_type n_pos = pos - this->cbegin();
1984 iterator it(vector_iterator_get_ptr(pos));
1985 for(;first != last; ++first){
1986 it = this->emplace(it, *first);
1987 ++it;
1988 }
1989 return iterator(this->m_holder.start() + n_pos);
1990 }
1991
1992 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
1993 template <class FwdIt>
insert(const_iterator pos,FwdIt first,FwdIt last,typename dtl::disable_if_or<void,dtl::is_convertible<FwdIt,size_type>,dtl::is_input_iterator<FwdIt>>::type * =0)1994 BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, FwdIt first, FwdIt last
1995 , typename dtl::disable_if_or
1996 < void
1997 , dtl::is_convertible<FwdIt, size_type>
1998 , dtl::is_input_iterator<FwdIt>
1999 >::type * = 0
2000 )
2001 {
2002 BOOST_ASSERT(this->priv_in_range_or_end(pos));
2003 const typename iterator_traits<FwdIt>::size_type sz = boost::container::iterator_distance(first, last);
2004 if (sz > size_type(-1)){
2005 boost::container::throw_length_error("vector::insert, FwdIt's max length reached");
2006 }
2007
2008 dtl::insert_range_proxy<allocator_type, FwdIt, T*> proxy(first);
2009 return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), static_cast<size_type>(sz), proxy);
2010 }
2011 #endif
2012
2013 //! <b>Requires</b>: p must be a valid iterator of *this. num, must
2014 //! be equal to boost::container::iterator_distance(first, last)
2015 //!
2016 //! <b>Effects</b>: Insert a copy of the [first, last) range before pos.
2017 //!
2018 //! <b>Returns</b>: an iterator to the first inserted element or pos if first == last.
2019 //!
2020 //! <b>Throws</b>: If memory allocation throws, T's constructor from a
2021 //! dereferenced InpIt throws or T's copy/move constructor/assignment throws.
2022 //!
2023 //! <b>Complexity</b>: Linear to boost::container::iterator_distance [first, last).
2024 //!
2025 //! <b>Note</b>: This function avoids a linear operation to calculate boost::container::iterator_distance[first, last)
2026 //! for forward and bidirectional iterators, and a one by one insertion for input iterators. This is a
2027 //! a non-standard extension.
2028 #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
2029 template <class InIt>
insert(const_iterator pos,size_type num,InIt first,InIt last)2030 BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, size_type num, InIt first, InIt last)
2031 {
2032 BOOST_ASSERT(this->priv_in_range_or_end(pos));
2033 BOOST_ASSERT(dtl::is_input_iterator<InIt>::value ||
2034 num == static_cast<size_type>(boost::container::iterator_distance(first, last)));
2035 (void)last;
2036 dtl::insert_range_proxy<allocator_type, InIt, T*> proxy(first);
2037 return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), num, proxy);
2038 }
2039 #endif
2040
2041 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
2042 //! <b>Requires</b>: position must be a valid iterator of *this.
2043 //!
2044 //! <b>Effects</b>: Insert a copy of the [il.begin(), il.end()) range before position.
2045 //!
2046 //! <b>Returns</b>: an iterator to the first inserted element or position if first == last.
2047 //!
2048 //! <b>Complexity</b>: Linear to the range [il.begin(), il.end()).
insert(const_iterator position,std::initializer_list<value_type> il)2049 BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator position, std::initializer_list<value_type> il)
2050 {
2051 //Assertion done in insert()
2052 return this->insert(position, il.begin(), il.end());
2053 }
2054 #endif
2055
2056 //! <b>Effects</b>: Removes the last element from the container.
2057 //!
2058 //! <b>Throws</b>: Nothing.
2059 //!
2060 //! <b>Complexity</b>: Constant time.
pop_back()2061 BOOST_CONTAINER_FORCEINLINE void pop_back() BOOST_NOEXCEPT_OR_NOTHROW
2062 {
2063 BOOST_ASSERT(!this->empty());
2064 //Destroy last element
2065 allocator_traits_type::destroy(this->get_stored_allocator(), this->priv_raw_end() - 1);
2066 --this->m_holder.m_size;
2067 }
2068
2069 //! <b>Effects</b>: Erases the element at position pos.
2070 //!
2071 //! <b>Throws</b>: Nothing.
2072 //!
2073 //! <b>Complexity</b>: Linear to the elements between pos and the
2074 //! last element. Constant if pos is the last element.
erase(const_iterator position)2075 iterator erase(const_iterator position)
2076 {
2077 BOOST_ASSERT(this->priv_in_range(position));
2078 const pointer p = vector_iterator_get_ptr(position);
2079 T *const pos_ptr = boost::movelib::to_raw_pointer(p);
2080 T *const end_ptr = this->priv_raw_end();
2081
2082 //Move elements forward and destroy last
2083 (void)::boost::container::move(pos_ptr + 1, end_ptr, pos_ptr);
2084
2085 T *const last_ptr = end_ptr-1;
2086 if(!value_traits::trivial_dctr_after_move || pos_ptr == last_ptr){
2087 allocator_traits_type::destroy(this->get_stored_allocator(), last_ptr);
2088 }
2089 --this->m_holder.m_size;
2090 return iterator(p);
2091 }
2092
2093 //! <b>Effects</b>: Erases the elements pointed by [first, last).
2094 //!
2095 //! <b>Throws</b>: Nothing.
2096 //!
2097 //! <b>Complexity</b>: Linear to the distance between first and last
2098 //! plus linear to the elements between pos and the last element.
erase(const_iterator first,const_iterator last)2099 iterator erase(const_iterator first, const_iterator last)
2100 {
2101 BOOST_ASSERT(this->priv_in_range_or_end(first));
2102 BOOST_ASSERT(this->priv_in_range_or_end(last));
2103 BOOST_ASSERT(first <= last);
2104 if(first != last){
2105 T* const old_end_ptr = this->priv_raw_end();
2106 T* const first_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(first));
2107 T* const last_ptr = boost::movelib::to_raw_pointer(vector_iterator_get_ptr(last));
2108 T* const new_last_ptr = boost::movelib::to_raw_pointer(boost::container::move(last_ptr, old_end_ptr, first_ptr));
2109 const size_type n = static_cast<size_type>(old_end_ptr - new_last_ptr);
2110 if(!value_traits::trivial_dctr_after_move || old_end_ptr == last_ptr){
2111 boost::container::destroy_alloc_n(this->get_stored_allocator(), new_last_ptr, n);
2112 }
2113 this->m_holder.dec_stored_size(n);
2114 }
2115 return iterator(vector_iterator_get_ptr(first));
2116 }
2117
2118 //! <b>Effects</b>: Swaps the contents of *this and x.
2119 //!
2120 //! <b>Throws</b>: Nothing.
2121 //!
2122 //! <b>Complexity</b>: Constant.
swap(vector & x)2123 BOOST_CONTAINER_FORCEINLINE void swap(vector& x)
2124 BOOST_NOEXCEPT_IF( ((allocator_traits_type::propagate_on_container_swap::value
2125 || allocator_traits_type::is_always_equal::value) &&
2126 !dtl::is_version<allocator_type, 0>::value))
2127 {
2128 this->priv_swap(x, dtl::bool_<dtl::is_version<allocator_type, 0>::value>());
2129 }
2130
2131 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
2132
2133 //! <b>Effects</b>: Swaps the contents of *this and x.
2134 //!
2135 //! <b>Throws</b>: Nothing.
2136 //!
2137 //! <b>Complexity</b>: Linear
2138 //!
2139 //! <b>Note</b>: Non-standard extension to support static_vector
2140 template<class OtherA>
swap(vector<T,OtherA,Options> & x,typename dtl::enable_if_and<void,dtl::is_version<typename real_allocator<T,OtherA>::type,0>,dtl::is_different<typename real_allocator<T,OtherA>::type,allocator_type>>::type * =0)2141 BOOST_CONTAINER_FORCEINLINE void swap(vector<T, OtherA, Options> & x
2142 , typename dtl::enable_if_and
2143 < void
2144 , dtl::is_version<typename real_allocator<T, OtherA>::type, 0>
2145 , dtl::is_different<typename real_allocator<T, OtherA>::type, allocator_type>
2146 >::type * = 0
2147 )
2148 { this->m_holder.deep_swap(x.m_holder); }
2149
2150 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
2151
2152 //! <b>Effects</b>: Erases all the elements of the vector.
2153 //!
2154 //! <b>Throws</b>: Nothing.
2155 //!
2156 //! <b>Complexity</b>: Linear to the number of elements in the container.
clear()2157 BOOST_CONTAINER_FORCEINLINE void clear() BOOST_NOEXCEPT_OR_NOTHROW
2158 { this->priv_destroy_all(); }
2159
2160 //! <b>Effects</b>: Returns true if x and y are equal
2161 //!
2162 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator ==(const vector & x,const vector & y)2163 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator==(const vector& x, const vector& y)
2164 { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); }
2165
2166 //! <b>Effects</b>: Returns true if x and y are unequal
2167 //!
2168 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator !=(const vector & x,const vector & y)2169 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const vector& x, const vector& y)
2170 { return !(x == y); }
2171
2172 //! <b>Effects</b>: Returns true if x is less than y
2173 //!
2174 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator <(const vector & x,const vector & y)2175 BOOST_CONTAINER_ATTRIBUTE_NODISCARD friend bool operator<(const vector& x, const vector& y)
2176 { return boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
2177
2178 //! <b>Effects</b>: Returns true if x is greater than y
2179 //!
2180 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator >(const vector & x,const vector & y)2181 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator>(const vector& x, const vector& y)
2182 { return y < x; }
2183
2184 //! <b>Effects</b>: Returns true if x is equal or less than y
2185 //!
2186 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator <=(const vector & x,const vector & y)2187 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const vector& x, const vector& y)
2188 { return !(y < x); }
2189
2190 //! <b>Effects</b>: Returns true if x is equal or greater than y
2191 //!
2192 //! <b>Complexity</b>: Linear to the number of elements in the container.
operator >=(const vector & x,const vector & y)2193 BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const vector& x, const vector& y)
2194 { return !(x < y); }
2195
2196 //! <b>Effects</b>: x.swap(y)
2197 //!
2198 //! <b>Complexity</b>: Constant.
swap(vector & x,vector & y)2199 BOOST_CONTAINER_FORCEINLINE friend void swap(vector& x, vector& y)
2200 BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y)))
2201 { x.swap(y); }
2202
2203 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
2204 //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
2205 //! effect. Otherwise, it is a request for allocation of additional memory
2206 //! (memory expansion) that will not invalidate iterators.
2207 //! If the request is successful, then capacity() is greater than or equal to
2208 //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
2209 //!
2210 //! <b>Throws</b>: If memory allocation allocation throws or T's copy/move constructor throws.
2211 //!
2212 //! <b>Note</b>: Non-standard extension.
stable_reserve(size_type new_cap)2213 bool stable_reserve(size_type new_cap)
2214 {
2215 const size_type cp = this->capacity();
2216 return cp >= new_cap || (alloc_version::value == 2 && this->m_holder.try_expand_fwd(new_cap - cp));
2217 }
2218
2219 //Absolutely experimental. This function might change, disappear or simply crash!
2220 template<class BiDirPosConstIt, class BiDirValueIt>
insert_ordered_at(const size_type element_count,BiDirPosConstIt last_position_it,BiDirValueIt last_value_it)2221 BOOST_CONTAINER_FORCEINLINE void insert_ordered_at(const size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it)
2222 {
2223 typedef vector_insert_ordered_cursor<BiDirPosConstIt, BiDirValueIt> inserter_t;
2224 return this->priv_insert_ordered_at(element_count, inserter_t(last_position_it, last_value_it));
2225 }
2226
2227 template<class InputIt>
merge(InputIt first,InputIt last)2228 BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last)
2229 { this->merge(first, last, value_less_t()); }
2230
2231 template<class InputIt, class Compare>
merge(InputIt first,InputIt last,Compare comp)2232 BOOST_CONTAINER_FORCEINLINE void merge(InputIt first, InputIt last, Compare comp)
2233 {
2234 size_type const s = this->size();
2235 size_type const c = this->capacity();
2236 size_type n = 0;
2237 size_type const free_cap = c - s;
2238 //If not input iterator and new elements don't fit in the remaining capacity, merge in new buffer
2239 if(!dtl::is_input_iterator<InputIt>::value &&
2240 free_cap < (n = static_cast<size_type>(boost::container::iterator_distance(first, last)))){
2241 this->priv_merge_in_new_buffer(first, n, comp, alloc_version());
2242 }
2243 else{
2244 this->insert(this->cend(), first, last);
2245 T *const raw_beg = this->priv_raw_begin();
2246 T *const raw_end = this->priv_raw_end();
2247 T *const raw_pos = raw_beg + s;
2248 boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, free_cap - n);
2249 }
2250 }
2251
2252 template<class InputIt>
merge_unique(InputIt first,InputIt last)2253 BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last)
2254 { this->merge_unique(first, last, value_less_t()); }
2255
2256 template<class InputIt, class Compare>
merge_unique(InputIt first,InputIt last,Compare comp)2257 BOOST_CONTAINER_FORCEINLINE void merge_unique(InputIt first, InputIt last, Compare comp)
2258 {
2259 size_type const old_size = this->size();
2260 this->priv_set_difference_back(first, last, comp);
2261 T *const raw_beg = this->priv_raw_begin();
2262 T *const raw_end = this->priv_raw_end();
2263 T *raw_pos = raw_beg + old_size;
2264 boost::movelib::adaptive_merge(raw_beg, raw_pos, raw_end, comp, raw_end, this->capacity() - this->size());
2265 }
2266
2267 private:
2268 template<class PositionValue>
priv_insert_ordered_at(const size_type element_count,PositionValue position_value)2269 void priv_insert_ordered_at(const size_type element_count, PositionValue position_value)
2270 {
2271 const size_type old_size_pos = this->size();
2272 this->reserve(old_size_pos + element_count);
2273 T* const begin_ptr = this->priv_raw_begin();
2274 size_type insertions_left = element_count;
2275 size_type prev_pos = old_size_pos;
2276 size_type old_hole_size = element_count;
2277
2278 //Exception rollback. If any copy throws before the hole is filled, values
2279 //already inserted/copied at the end of the buffer will be destroyed.
2280 typename value_traits::ArrayDestructor past_hole_values_destroyer
2281 (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u));
2282 //Loop for each insertion backwards, first moving the elements after the insertion point,
2283 //then inserting the element.
2284 while(insertions_left){
2285 --position_value;
2286 size_type const pos = position_value.get_pos();
2287 BOOST_ASSERT(pos != size_type(-1) && pos <= old_size_pos && pos <= prev_pos);
2288 //If needed shift the range after the insertion point and the previous insertion point.
2289 //Function will take care if the shift crosses the size() boundary, using copy/move
2290 //or uninitialized copy/move if necessary.
2291 size_type new_hole_size = (pos != prev_pos)
2292 ? priv_insert_ordered_at_shift_range(pos, prev_pos, this->size(), insertions_left)
2293 : old_hole_size
2294 ;
2295 if(new_hole_size){
2296 //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards
2297 past_hole_values_destroyer.increment_size_backwards(prev_pos - pos);
2298 //Insert the new value in the hole
2299 allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, position_value.get_val());
2300 if(--new_hole_size){
2301 //The hole was reduced by the new insertion by one
2302 past_hole_values_destroyer.increment_size_backwards(size_type(1u));
2303 }
2304 else{
2305 //Hole was just filled, disable exception rollback and change vector size
2306 past_hole_values_destroyer.release();
2307 this->m_holder.inc_stored_size(element_count);
2308 }
2309 }
2310 else{
2311 if(old_hole_size){
2312 //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size
2313 past_hole_values_destroyer.release();
2314 this->m_holder.inc_stored_size(element_count);
2315 }
2316 //Insert the new value in the already constructed range
2317 begin_ptr[pos + insertions_left - 1] = position_value.get_val();
2318 }
2319 --insertions_left;
2320 old_hole_size = new_hole_size;
2321 prev_pos = pos;
2322 }
2323 }
2324
2325 template<class InputIt, class Compare>
priv_set_difference_back(InputIt first1,InputIt last1,Compare comp)2326 void priv_set_difference_back(InputIt first1, InputIt last1, Compare comp)
2327 {
2328 T * old_first2 = this->priv_raw_begin();
2329 T * first2 = old_first2;
2330 T * last2 = this->priv_raw_end();
2331
2332 while (first1 != last1) {
2333 if (first2 == last2){
2334 this->insert(this->cend(), first1, last1);
2335 return;
2336 }
2337
2338 if (comp(*first1, *first2)) {
2339 this->emplace_back(*first1);
2340 T * const raw_begin = this->priv_raw_begin();
2341 if(old_first2 != raw_begin)
2342 {
2343 //Reallocation happened, update range
2344 first2 = raw_begin + (first2 - old_first2);
2345 last2 = raw_begin + (last2 - old_first2);
2346 old_first2 = raw_begin;
2347 }
2348 ++first1;
2349 }
2350 else {
2351 if (!comp(*first2, *first1)) {
2352 ++first1;
2353 }
2354 ++first2;
2355 }
2356 }
2357 }
2358
2359 template<class FwdIt, class Compare>
priv_merge_in_new_buffer(FwdIt,size_type,Compare,version_0)2360 BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(FwdIt, size_type, Compare, version_0)
2361 {
2362 alloc_holder_t::on_capacity_overflow();
2363 }
2364
2365 template<class FwdIt, class Compare, class Version>
priv_merge_in_new_buffer(FwdIt first,size_type n,Compare comp,Version)2366 void priv_merge_in_new_buffer(FwdIt first, size_type n, Compare comp, Version)
2367 {
2368 size_type const new_size = this->size() + n;
2369 size_type new_cap = new_size;
2370 pointer p = pointer();
2371 pointer const new_storage = this->m_holder.allocation_command(allocate_new, new_size, new_cap, p);
2372
2373 BOOST_ASSERT((new_cap >= this->size() ) && (new_cap - this->size()) >= n);
2374 allocator_type &a = this->m_holder.alloc();
2375 typename value_traits::ArrayDeallocator new_buffer_deallocator(new_storage, a, new_cap);
2376 typename value_traits::ArrayDestructor new_values_destroyer(new_storage, a, 0u);
2377 T* pbeg = this->priv_raw_begin();
2378 size_type const old_size = this->size();
2379 T* const pend = pbeg + old_size;
2380 T* d_first = boost::movelib::to_raw_pointer(new_storage);
2381 size_type added = n;
2382 //Merge in new buffer loop
2383 while(1){
2384 if(!n) {
2385 ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pbeg, pend, d_first);
2386 break;
2387 }
2388 else if(pbeg == pend) {
2389 ::boost::container::uninitialized_move_alloc_n(this->m_holder.alloc(), first, n, d_first);
2390 break;
2391 }
2392 //maintain stability moving external values only if they are strictly less
2393 else if(comp(*first, *pbeg)) {
2394 allocator_traits_type::construct( this->m_holder.alloc(), d_first, *first );
2395 new_values_destroyer.increment_size(1u);
2396 ++first;
2397 --n;
2398 ++d_first;
2399 }
2400 else{
2401 allocator_traits_type::construct( this->m_holder.alloc(), d_first, boost::move(*pbeg) );
2402 new_values_destroyer.increment_size(1u);
2403 ++pbeg;
2404 ++d_first;
2405 }
2406 }
2407
2408 //Nothrow operations
2409 pointer const old_p = this->m_holder.start();
2410 size_type const old_cap = this->m_holder.capacity();
2411 boost::container::destroy_alloc_n(a, boost::movelib::to_raw_pointer(old_p), old_size);
2412 if (old_cap > 0) {
2413 this->m_holder.deallocate(old_p, old_cap);
2414 }
2415 m_holder.set_stored_size(old_size + added);
2416 this->m_holder.start(new_storage);
2417 this->m_holder.capacity(new_cap);
2418 new_buffer_deallocator.release();
2419 new_values_destroyer.release();
2420 }
2421
room_enough() const2422 BOOST_CONTAINER_FORCEINLINE bool room_enough() const
2423 { return this->m_holder.m_size != this->m_holder.capacity(); }
2424
back_ptr() const2425 BOOST_CONTAINER_FORCEINLINE pointer back_ptr() const
2426 { return this->m_holder.start() + this->m_holder.m_size; }
2427
priv_index_of(pointer p) const2428 BOOST_CONTAINER_FORCEINLINE size_type priv_index_of(pointer p) const
2429 {
2430 BOOST_ASSERT(this->m_holder.start() <= p);
2431 BOOST_ASSERT(p <= (this->m_holder.start()+this->size()));
2432 return static_cast<size_type>(p - this->m_holder.start());
2433 }
2434
2435 template<class OtherA>
priv_move_assign(BOOST_RV_REF_BEG vector<T,OtherA,Options> BOOST_RV_REF_END x,typename dtl::enable_if_c<dtl::is_version<typename real_allocator<T,OtherA>::type,0>::value>::type * =0)2436 void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x
2437 , typename dtl::enable_if_c
2438 < dtl::is_version<typename real_allocator<T, OtherA>::type, 0>::value >::type * = 0)
2439 {
2440 if(!dtl::is_same<typename real_allocator<T, OtherA>::type, allocator_type>::value &&
2441 this->capacity() < x.size()){
2442 alloc_holder_t::on_capacity_overflow();
2443 }
2444 T* const this_start = this->priv_raw_begin();
2445 T* const other_start = x.priv_raw_begin();
2446 const size_type this_sz = m_holder.m_size;
2447 const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
2448 boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz);
2449 m_holder.set_stored_size(other_sz);
2450 //Not emptying the source container seems to be confusing for users as drop-in
2451 //replacement for non-static vectors, so clear it.
2452 x.clear();
2453 }
2454
2455 template<class OtherA>
priv_move_assign(BOOST_RV_REF_BEG vector<T,OtherA,Options> BOOST_RV_REF_END x,typename dtl::disable_if_or<void,dtl::is_version<typename real_allocator<T,OtherA>::type,0>,dtl::is_different<typename real_allocator<T,OtherA>::type,allocator_type>>::type * =0)2456 void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherA, Options> BOOST_RV_REF_END x
2457 , typename dtl::disable_if_or
2458 < void
2459 , dtl::is_version<typename real_allocator<T, OtherA>::type, 0>
2460 , dtl::is_different<typename real_allocator<T, OtherA>::type, allocator_type>
2461 >::type * = 0)
2462 {
2463 //for move assignment, no aliasing (&x != this) is assumed.
2464 //x.size() == 0 is allowed for buggy std libraries.
2465 BOOST_ASSERT(this != &x || x.size() == 0);
2466 allocator_type &this_alloc = this->m_holder.alloc();
2467 allocator_type &x_alloc = x.m_holder.alloc();
2468 const bool propagate_alloc = allocator_traits_type::propagate_on_container_move_assignment::value;
2469
2470 //In this allocator move constructor the allocator maybe will be propagated -----------------------v
2471 const bool is_propagable_from_x = is_propagable_from(x_alloc, x.m_holder.start(), this_alloc, propagate_alloc);
2472
2473 //Resources can be transferred if both allocators are
2474 //going to be equal after this function (either propagated or already equal)
2475 if(is_propagable_from_x){
2476 this->clear();
2477 if(BOOST_LIKELY(!!this->m_holder.m_start))
2478 this->m_holder.deallocate(this->m_holder.m_start, this->m_holder.m_capacity);
2479 this->m_holder.steal_resources(x.m_holder);
2480 }
2481 //Else do a one by one move. Also, clear the source as users find confusing
2482 //elements are still alive in the source container.
2483 else{
2484 this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin()))
2485 , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end() ))
2486 );
2487 x.clear();
2488 }
2489 //Move allocator if needed
2490 dtl::move_alloc(this_alloc, x_alloc, dtl::bool_<propagate_alloc>());
2491 }
2492
2493 template<class OtherA>
priv_copy_assign(const vector<T,OtherA,Options> & x,typename dtl::enable_if_c<dtl::is_version<typename real_allocator<T,OtherA>::type,0>::value>::type * =0)2494 void priv_copy_assign(const vector<T, OtherA, Options> &x
2495 , typename dtl::enable_if_c
2496 < dtl::is_version<typename real_allocator<T, OtherA>::type, 0>::value >::type * = 0)
2497 {
2498 if(!dtl::is_same<typename real_allocator<T, OtherA>::type, allocator_type>::value &&
2499 this->capacity() < x.size()){
2500 alloc_holder_t::on_capacity_overflow();
2501 }
2502 T* const this_start = this->priv_raw_begin();
2503 T* const other_start = x.priv_raw_begin();
2504 const size_type this_sz = m_holder.m_size;
2505 const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
2506 boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz);
2507 m_holder.set_stored_size(other_sz);
2508 }
2509
2510 template<class OtherA>
2511 typename dtl::disable_if_or
2512 < void
2513 , dtl::is_version<typename real_allocator<T, OtherA>::type, 0>
2514 , dtl::is_different<typename real_allocator<T, OtherA>::type, allocator_type>
2515 >::type
priv_copy_assign(const vector<T,OtherA,Options> & x)2516 priv_copy_assign(const vector<T, OtherA, Options> &x)
2517 {
2518 allocator_type &this_alloc = this->m_holder.alloc();
2519 const allocator_type &x_alloc = x.m_holder.alloc();
2520 dtl::bool_<allocator_traits_type::
2521 propagate_on_container_copy_assignment::value> flag;
2522 if(flag && this_alloc != x_alloc){
2523 this->clear();
2524 this->shrink_to_fit();
2525 }
2526 dtl::assign_alloc(this_alloc, x_alloc, flag);
2527 this->assign( x.priv_raw_begin(), x.priv_raw_end() );
2528 }
2529
2530 template<class Vector> //Template it to avoid it in explicit instantiations
priv_swap(Vector & x,dtl::true_type)2531 BOOST_CONTAINER_FORCEINLINE void priv_swap(Vector &x, dtl::true_type) //version_0
2532 { this->m_holder.deep_swap(x.m_holder); }
2533
2534 template<class Vector> //Template it to avoid it in explicit instantiations
priv_swap(Vector & x,dtl::false_type)2535 void priv_swap(Vector &x, dtl::false_type) //version_N
2536 {
2537 const bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value;
2538 if(are_swap_propagable( this->get_stored_allocator(), this->m_holder.start()
2539 , x.get_stored_allocator(), x.m_holder.start(), propagate_alloc)){
2540 //Just swap internals
2541 this->m_holder.swap_resources(x.m_holder);
2542 }
2543 else{
2544 if (BOOST_UNLIKELY(&x == this))
2545 return;
2546
2547 //Else swap element by element...
2548 bool const t_smaller = this->size() < x.size();
2549 vector &sml = t_smaller ? *this : x;
2550 vector &big = t_smaller ? x : *this;
2551
2552 size_type const common_elements = sml.size();
2553 for(size_type i = 0; i != common_elements; ++i){
2554 boost::adl_move_swap(sml[i], big[i]);
2555 }
2556 //... and move-insert the remaining range
2557 sml.insert( sml.cend()
2558 , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(big.nth(common_elements)))
2559 , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(big.end()))
2560 );
2561 //Destroy remaining elements
2562 big.erase(big.nth(common_elements), big.cend());
2563 }
2564 //And now swap the allocator
2565 dtl::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), dtl::bool_<propagate_alloc>());
2566 }
2567
priv_move_to_new_buffer(size_type,version_0)2568 BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type, version_0)
2569 { alloc_holder_t::on_capacity_overflow(); }
2570
priv_dummy_empty_proxy()2571 BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy()
2572 {
2573 return dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*>
2574 (::boost::make_move_iterator((T *)0));
2575 }
2576
priv_move_to_new_buffer(size_type new_cap,version_1)2577 BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type new_cap, version_1)
2578 {
2579 //There is not enough memory, allocate a new buffer
2580 //Pass the hint so that allocators can take advantage of this.
2581 pointer const p = this->m_holder.allocate(new_cap);
2582 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2583 ++this->num_alloc;
2584 #endif
2585 //We will reuse insert code, so create a dummy input iterator
2586 this->priv_insert_forward_range_new_allocation
2587 ( boost::movelib::to_raw_pointer(p), new_cap, this->priv_raw_end(), 0, this->priv_dummy_empty_proxy());
2588 }
2589
priv_move_to_new_buffer(size_type new_cap,version_2)2590 void priv_move_to_new_buffer(size_type new_cap, version_2)
2591 {
2592 //There is not enough memory, allocate a new
2593 //buffer or expand the old one.
2594 bool same_buffer_start;
2595 size_type real_cap = 0;
2596 pointer reuse(this->m_holder.start());
2597 pointer const ret(this->m_holder.allocation_command(allocate_new | expand_fwd | expand_bwd, new_cap, real_cap = new_cap, reuse));
2598
2599 //Check for forward expansion
2600 same_buffer_start = reuse && this->m_holder.start() == ret;
2601 if(same_buffer_start){
2602 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2603 ++this->num_expand_fwd;
2604 #endif
2605 this->m_holder.capacity(real_cap);
2606 }
2607 else{ //If there is no forward expansion, move objects, we will reuse insertion code
2608 T * const new_mem = boost::movelib::to_raw_pointer(ret);
2609 T * const ins_pos = this->priv_raw_end();
2610 if(reuse){ //Backwards (and possibly forward) expansion
2611 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2612 ++this->num_expand_bwd;
2613 #endif
2614 this->priv_insert_forward_range_expand_backwards
2615 ( new_mem , real_cap, ins_pos, 0, this->priv_dummy_empty_proxy());
2616 }
2617 else{ //New buffer
2618 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2619 ++this->num_alloc;
2620 #endif
2621 this->priv_insert_forward_range_new_allocation
2622 ( new_mem, real_cap, ins_pos, 0, this->priv_dummy_empty_proxy());
2623 }
2624 }
2625 }
2626
priv_destroy_last_n(const size_type n)2627 void priv_destroy_last_n(const size_type n) BOOST_NOEXCEPT_OR_NOTHROW
2628 {
2629 BOOST_ASSERT(n <= this->m_holder.m_size);
2630 boost::container::destroy_alloc_n(this->get_stored_allocator(), this->priv_raw_end() - n, n);
2631 this->m_holder.dec_stored_size(n);
2632 }
2633
2634 template<class InpIt>
priv_uninitialized_construct_at_end(InpIt first,InpIt last)2635 void priv_uninitialized_construct_at_end(InpIt first, InpIt last)
2636 {
2637 T* const old_end_pos = this->priv_raw_end();
2638 T* const new_end_pos = boost::container::uninitialized_copy_alloc(this->m_holder.alloc(), first, last, old_end_pos);
2639 this->m_holder.inc_stored_size(static_cast<size_type>(new_end_pos - old_end_pos));
2640 }
2641
priv_destroy_all()2642 void priv_destroy_all() BOOST_NOEXCEPT_OR_NOTHROW
2643 {
2644 boost::container::destroy_alloc_n
2645 (this->get_stored_allocator(), this->priv_raw_begin(), this->m_holder.m_size);
2646 this->m_holder.m_size = 0;
2647 }
2648
2649 template<class U>
priv_insert(const const_iterator & p,BOOST_FWD_REF (U)u)2650 BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) u)
2651 {
2652 return this->emplace(p, ::boost::forward<U>(u));
2653 }
2654
2655 template <class U>
priv_push_back(BOOST_FWD_REF (U)u)2656 BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u)
2657 {
2658 this->emplace_back(::boost::forward<U>(u));
2659 }
2660
2661 //Overload to support compiler errors that instantiate too much
priv_push_back(::boost::move_detail::nat)2662 BOOST_CONTAINER_FORCEINLINE void priv_push_back(::boost::move_detail::nat)
2663 {}
2664
priv_insert(const_iterator,::boost::move_detail::nat)2665 BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator, ::boost::move_detail::nat)
2666 { return iterator(); }
2667
priv_resize_proxy(const T & x)2668 BOOST_CONTAINER_FORCEINLINE dtl::insert_n_copies_proxy<allocator_type, T*> priv_resize_proxy(const T &x)
2669 { return dtl::insert_n_copies_proxy<allocator_type, T*>(x); }
2670
priv_resize_proxy(default_init_t)2671 BOOST_CONTAINER_FORCEINLINE dtl::insert_default_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(default_init_t)
2672 { return dtl::insert_default_initialized_n_proxy<allocator_type, T*>(); }
2673
priv_resize_proxy(value_init_t)2674 BOOST_CONTAINER_FORCEINLINE dtl::insert_value_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(value_init_t)
2675 { return dtl::insert_value_initialized_n_proxy<allocator_type, T*>(); }
2676
priv_shrink_to_fit(version_0)2677 BOOST_CONTAINER_FORCEINLINE void priv_shrink_to_fit(version_0) BOOST_NOEXCEPT_OR_NOTHROW
2678 {}
2679
priv_shrink_to_fit(version_1)2680 void priv_shrink_to_fit(version_1)
2681 {
2682 const size_type cp = this->m_holder.capacity();
2683 if(cp){
2684 const size_type sz = this->size();
2685 if(!sz){
2686 if(BOOST_LIKELY(!!this->m_holder.m_start))
2687 this->m_holder.deallocate(this->m_holder.m_start, cp);
2688 this->m_holder.m_start = pointer();
2689 this->m_holder.m_capacity = 0;
2690 }
2691 else if(sz < cp){
2692 this->priv_move_to_new_buffer(sz, alloc_version());
2693 }
2694 }
2695 }
2696
priv_shrink_to_fit(version_2)2697 void priv_shrink_to_fit(version_2) BOOST_NOEXCEPT_OR_NOTHROW
2698 {
2699 const size_type cp = this->m_holder.capacity();
2700 if(cp){
2701 const size_type sz = this->size();
2702 if(!sz){
2703 if(BOOST_LIKELY(!!this->m_holder.m_start))
2704 this->m_holder.deallocate(this->m_holder.m_start, cp);
2705 this->m_holder.m_start = pointer();
2706 this->m_holder.m_capacity = 0;
2707 }
2708 else{
2709 size_type received_size = sz;
2710 pointer reuse(this->m_holder.start());
2711 if(this->m_holder.allocation_command
2712 (shrink_in_place | nothrow_allocation, cp, received_size, reuse)){
2713 this->m_holder.capacity(received_size);
2714 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2715 ++this->num_shrink;
2716 #endif
2717 }
2718 }
2719 }
2720 }
2721
2722 template <class InsertionProxy>
priv_insert_forward_range_no_capacity(T * const,const size_type,const InsertionProxy,version_0)2723 BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range_no_capacity
2724 (T * const, const size_type, const InsertionProxy , version_0)
2725 {
2726 return alloc_holder_t::on_capacity_overflow(), iterator();
2727 }
2728
2729 template <class InsertionProxy>
priv_insert_forward_range_no_capacity(T * const raw_pos,const size_type n,const InsertionProxy insert_range_proxy,version_1)2730 BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity
2731 (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_1)
2732 {
2733 //Check if we have enough memory or try to expand current memory
2734 const size_type n_pos = static_cast<size_type>(raw_pos - this->priv_raw_begin());
2735
2736 const size_type new_cap = this->m_holder.template next_capacity<growth_factor_type>(n);
2737 //Pass the hint so that allocators can take advantage of this.
2738 T * const new_buf = boost::movelib::to_raw_pointer(this->m_holder.allocate(new_cap));
2739 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2740 ++this->num_alloc;
2741 #endif
2742 this->priv_insert_forward_range_new_allocation(new_buf, new_cap, raw_pos, n, insert_range_proxy);
2743 return iterator(this->m_holder.start() + n_pos);
2744 }
2745
2746 template <class InsertionProxy>
priv_insert_forward_range_no_capacity(T * const raw_pos,const size_type n,const InsertionProxy insert_range_proxy,version_2)2747 BOOST_CONTAINER_NOINLINE iterator priv_insert_forward_range_no_capacity
2748 (T *const raw_pos, const size_type n, const InsertionProxy insert_range_proxy, version_2)
2749 {
2750 //Check if we have enough memory or try to expand current memory
2751 const size_type n_pos = raw_pos - this->priv_raw_begin();
2752
2753 //There is not enough memory, allocate a new
2754 //buffer or expand the old one.
2755 size_type real_cap = this->m_holder.template next_capacity<growth_factor_type>(n);
2756 pointer reuse(this->m_holder.start());
2757 pointer const ret (this->m_holder.allocation_command
2758 (allocate_new | expand_fwd | expand_bwd, this->m_holder.m_size + n, real_cap, reuse));
2759
2760 //Buffer reallocated
2761 if(reuse){
2762 //Forward expansion, delay insertion
2763 if(this->m_holder.start() == ret){
2764 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2765 ++this->num_expand_fwd;
2766 #endif
2767 this->m_holder.capacity(real_cap);
2768 //Expand forward
2769 this->priv_insert_forward_range_expand_forward
2770 (raw_pos, n, insert_range_proxy, dtl::bool_<dtl::is_single_value_proxy<InsertionProxy>::value>());
2771 }
2772 //Backwards (and possibly forward) expansion
2773 else{
2774 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2775 ++this->num_expand_bwd;
2776 #endif
2777 this->priv_insert_forward_range_expand_backwards
2778 (boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy);
2779 }
2780 }
2781 //New buffer
2782 else{
2783 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
2784 ++this->num_alloc;
2785 #endif
2786 this->priv_insert_forward_range_new_allocation
2787 ( boost::movelib::to_raw_pointer(ret), real_cap, raw_pos, n, insert_range_proxy);
2788 }
2789
2790 return iterator(this->m_holder.start() + n_pos);
2791 }
2792
2793 template <class InsertionProxy>
priv_insert_forward_range(const pointer & pos,const size_type n,const InsertionProxy insert_range_proxy)2794 BOOST_CONTAINER_FORCEINLINE iterator priv_insert_forward_range
2795 (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy)
2796 {
2797 BOOST_ASSERT(this->m_holder.capacity() >= this->m_holder.m_size);
2798 T *const p = boost::movelib::to_raw_pointer(pos);
2799 //Check if we have enough memory or try to expand current memory
2800 if (BOOST_LIKELY(n <= (this->m_holder.capacity() - this->m_holder.m_size))){
2801 //Expand forward
2802 this->priv_insert_forward_range_expand_forward
2803 (p, n, insert_range_proxy, dtl::bool_<dtl::is_single_value_proxy<InsertionProxy>::value>());
2804 return iterator(pos);
2805 }
2806 else{
2807 return this->priv_insert_forward_range_no_capacity(p, n, insert_range_proxy, alloc_version());
2808 }
2809 }
2810
2811 template <class U>
priv_resize(const size_type new_size,const U & u,version_0)2812 void priv_resize(const size_type new_size, const U &u, version_0)
2813 {
2814 const size_type sz = this->m_holder.m_size;
2815 if (new_size > this->capacity()){
2816 //This will trigger an error
2817 alloc_holder_t::on_capacity_overflow();
2818 }
2819 else if (new_size < sz){
2820 //Destroy last elements
2821 this->priv_destroy_last_n(sz - new_size);
2822 }
2823 else{
2824 T* const old_finish = this->priv_raw_end();
2825 this->priv_resize_proxy(u).uninitialized_copy_n_and_update(this->m_holder.alloc(), old_finish, new_size - sz);
2826 this->m_holder.set_stored_size(new_size);
2827 }
2828 }
2829
2830 template <class U, class AllocVersion>
priv_resize(const size_type new_size,const U & u,AllocVersion)2831 void priv_resize(const size_type new_size, const U &u, AllocVersion)
2832 {
2833 const size_type sz = this->m_holder.m_size;
2834 if (new_size < sz){
2835 //Destroy last elements
2836 this->priv_destroy_last_n(sz - new_size);
2837 }
2838 else {
2839 this->priv_insert_forward_range(this->back_ptr(), new_size - sz, this->priv_resize_proxy(u));
2840 }
2841 }
2842
2843 //Takes the range pointed by [first_pos, last_pos) and shifts it to the right
2844 //by 'shift_count'. 'limit_pos' marks the end of constructed elements.
2845 //
2846 //Precondition: first_pos <= last_pos <= limit_pos
2847 //
2848 //The shift operation might cross limit_pos so elements to moved beyond limit_pos
2849 //are uninitialized_moved with an allocator. Other elements are moved.
2850 //
2851 //The shift operation might left uninitialized elements after limit_pos
2852 //and the number of uninitialized elements is returned by the function.
2853 //
2854 //Old situation:
2855 // first_pos last_pos old_limit
2856 // | | |
2857 // ____________V_______V__________________V_____________
2858 //| prefix | range | suffix |raw_mem ~
2859 //|____________|_______|__________________|_____________~
2860 //
2861 //New situation in Case A (hole_size == 0):
2862 // range is moved through move assignments
2863 //
2864 // first_pos last_pos limit_pos
2865 // | | |
2866 // ____________V_______V__________________V_____________
2867 //| prefix' | | | range |suffix'|raw_mem ~
2868 //|________________+______|___^___|_______|_____________~
2869 // | |
2870 // |_>_>_>_>_>^
2871 //
2872 //
2873 //New situation in Case B (hole_size >= 0):
2874 // range is moved through uninitialized moves
2875 //
2876 // first_pos last_pos limit_pos
2877 // | | |
2878 // ____________V_______V__________________V________________
2879 //| prefix' | | | [hole] | range |
2880 //|_______________________________________|________|___^___|
2881 // | |
2882 // |_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_^
2883 //
2884 //New situation in Case C (hole_size == 0):
2885 // range is moved through move assignments and uninitialized moves
2886 //
2887 // first_pos last_pos limit_pos
2888 // | | |
2889 // ____________V_______V__________________V___
2890 //| prefix' | | | range |
2891 //|___________________________________|___^___|
2892 // | |
2893 // |_>_>_>_>_>_>_>_>_>_>_>^
priv_insert_ordered_at_shift_range(size_type first_pos,size_type last_pos,size_type limit_pos,size_type shift_count)2894 size_type priv_insert_ordered_at_shift_range
2895 (size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count)
2896 {
2897 BOOST_ASSERT(first_pos <= last_pos);
2898 BOOST_ASSERT(last_pos <= limit_pos);
2899 //
2900 T* const begin_ptr = this->priv_raw_begin();
2901 T* const first_ptr = begin_ptr + first_pos;
2902 T* const last_ptr = begin_ptr + last_pos;
2903
2904 size_type hole_size = 0;
2905 //Case A:
2906 if((last_pos + shift_count) <= limit_pos){
2907 //All move assigned
2908 boost::container::move_backward(first_ptr, last_ptr, last_ptr + shift_count);
2909 }
2910 //Case B:
2911 else if((first_pos + shift_count) >= limit_pos){
2912 //All uninitialized_moved
2913 ::boost::container::uninitialized_move_alloc
2914 (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count);
2915 hole_size = first_pos + shift_count - limit_pos;
2916 }
2917 //Case C:
2918 else{
2919 //Some uninitialized_moved
2920 T* const limit_ptr = begin_ptr + limit_pos;
2921 T* const boundary_ptr = limit_ptr - shift_count;
2922 ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), boundary_ptr, last_ptr, limit_ptr);
2923 //The rest is move assigned
2924 boost::container::move_backward(first_ptr, boundary_ptr, limit_ptr);
2925 }
2926 return hole_size;
2927 }
2928
2929 private:
priv_raw_begin() const2930 BOOST_CONTAINER_FORCEINLINE T *priv_raw_begin() const
2931 { return boost::movelib::to_raw_pointer(m_holder.start()); }
2932
priv_raw_end() const2933 BOOST_CONTAINER_FORCEINLINE T* priv_raw_end() const
2934 { return this->priv_raw_begin() + this->m_holder.m_size; }
2935
2936 template <class InsertionProxy> //inline single-element version as it is significantly smaller
priv_insert_forward_range_expand_forward(T * const raw_pos,const size_type,InsertionProxy insert_range_proxy,dtl::true_type)2937 BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward
2938 (T* const raw_pos, const size_type, InsertionProxy insert_range_proxy, dtl::true_type)
2939 {
2940 BOOST_ASSERT(this->room_enough());
2941 //There is enough memory
2942 T* const old_finish = this->priv_raw_end();
2943 allocator_type & a = this->m_holder.alloc();
2944
2945 if (old_finish == raw_pos){
2946 insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, 1);
2947 ++this->m_holder.m_size;
2948 }
2949 else{
2950 //New elements can be just copied.
2951 //Move to uninitialized memory last objects
2952 T * const before_old_finish = old_finish-1;
2953
2954 allocator_traits_type::construct(a, old_finish, ::boost::move(*before_old_finish));
2955 ++this->m_holder.m_size;
2956 //Copy previous to last objects to the initialized end
2957 boost::container::move_backward(raw_pos, before_old_finish, old_finish);
2958 //Insert new objects in the raw_pos
2959 insert_range_proxy.copy_n_and_update(a, raw_pos, 1);
2960 }
2961 }
2962
2963 template <class InsertionProxy>
priv_insert_forward_range_expand_forward(T * const raw_pos,const size_type n,InsertionProxy insert_range_proxy,dtl::false_type)2964 BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type)
2965 {
2966 //There is enough memory
2967 boost::container::expand_forward_and_insert_alloc
2968 ( this->m_holder.alloc(), raw_pos, this->priv_raw_end(), n, insert_range_proxy);
2969 this->m_holder.inc_stored_size(n);
2970 }
2971
2972 template <class InsertionProxy>
priv_insert_forward_range_new_allocation(T * const new_start,size_type new_cap,T * const pos,const size_type n,InsertionProxy insert_range_proxy)2973 void priv_insert_forward_range_new_allocation
2974 (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy)
2975 {
2976 //n can be zero, if we want to reallocate!
2977 allocator_type &a = this->m_holder.alloc();
2978 T * const raw_old_buffer = this->priv_raw_begin();
2979
2980 typename value_traits::ArrayDeallocator new_buffer_deallocator(new_start, a, new_cap);
2981 boost::container::uninitialized_move_and_insert_alloc
2982 (a, raw_old_buffer, pos, this->priv_raw_end(), new_start, n, insert_range_proxy);
2983 new_buffer_deallocator.release();
2984
2985 //Destroy and deallocate old elements
2986 if(raw_old_buffer){
2987 BOOST_IF_CONSTEXPR(!has_trivial_destructor_after_move<value_type>::value)
2988 boost::container::destroy_alloc_n(a, raw_old_buffer, this->m_holder.m_size);
2989 this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity());
2990 }
2991
2992 this->m_holder.start(new_start);
2993 this->m_holder.inc_stored_size(n);
2994 this->m_holder.capacity(new_cap);
2995 }
2996
2997 template <class InsertionProxy>
priv_insert_forward_range_expand_backwards(T * const new_start,const size_type new_capacity,T * const pos,const size_type n,InsertionProxy insert_range_proxy)2998 void priv_insert_forward_range_expand_backwards
2999 (T* const new_start, const size_type new_capacity,
3000 T* const pos, const size_type n, InsertionProxy insert_range_proxy)
3001 {
3002 //n can be zero to just expand capacity
3003 //Backup old data
3004 T* const old_start = this->priv_raw_begin();
3005 const size_type old_size = this->m_holder.m_size;
3006 T* const old_finish = old_start + old_size;
3007 allocator_type &a = this->m_holder.alloc();
3008
3009 //Update the vector buffer information to a safe state
3010 this->m_holder.start(new_start);
3011 this->m_holder.capacity(new_capacity);
3012 this->m_holder.m_size = 0;
3013
3014 //We can have 8 possibilities:
3015 const size_type elemsbefore = static_cast<size_type>(pos - old_start);
3016 const size_type s_before = static_cast<size_type>(old_start - new_start);
3017 const size_type before_plus_new = elemsbefore + n;
3018
3019 typedef typename value_traits::ArrayDestructor array_destructor_t;
3020
3021 //If anything goes wrong, this object will destroy
3022 //all the old objects to fulfill previous vector state
3023 array_destructor_t old_values_destroyer(old_start, a, old_size);
3024 //Check if s_before is big enough to hold the beginning of old data + new data
3025 if(s_before >= before_plus_new){
3026 //Copy first old values before pos, after that the new objects
3027 T *const new_elem_pos =
3028 ::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start);
3029 this->m_holder.set_stored_size(elemsbefore);
3030 insert_range_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n);
3031 this->m_holder.set_stored_size(before_plus_new);
3032 const size_type new_size = old_size + n;
3033 //Check if s_before is so big that even copying the old data + new data
3034 //there is a gap between the new data and the old data
3035 if(s_before >= new_size){
3036 //Old situation:
3037 // _________________________________________________________
3038 //| raw_mem | old_begin | old_end |
3039 //| __________________________________|___________|_________|
3040 //
3041 //New situation:
3042 // _________________________________________________________
3043 //| old_begin | new | old_end | raw_mem |
3044 //|___________|__________|_________|________________________|
3045 //
3046 //Now initialize the rest of memory with the last old values
3047 if(before_plus_new != new_size){ //Special case to avoid operations in back insertion
3048 ::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_start + before_plus_new);
3049 //All new elements correctly constructed, avoid new element destruction
3050 this->m_holder.set_stored_size(new_size);
3051 }
3052 //Old values destroyed automatically with "old_values_destroyer"
3053 //when "old_values_destroyer" goes out of scope unless the have trivial
3054 //destructor after move.
3055 BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move)
3056 old_values_destroyer.release();
3057 }
3058 //s_before is so big that divides old_end
3059 else{
3060 //Old situation:
3061 // __________________________________________________
3062 //| raw_mem | old_begin | old_end |
3063 //| ___________________________|___________|_________|
3064 //
3065 //New situation:
3066 // __________________________________________________
3067 //| old_begin | new | old_end | raw_mem |
3068 //|___________|__________|_________|_________________|
3069 //
3070 //Now initialize the rest of memory with the last old values
3071 //All new elements correctly constructed, avoid new element destruction
3072 BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr){
3073 const size_type raw_gap = s_before - before_plus_new;
3074 //Now initialize the rest of s_before memory with the
3075 //first of elements after new values
3076 ::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start + before_plus_new);
3077 //Now we have a contiguous buffer so program trailing element destruction
3078 //and update size to the final size.
3079 old_values_destroyer.shrink_forward(new_size-s_before);
3080 this->m_holder.set_stored_size(new_size);
3081 //Now move remaining last objects in the old buffer begin
3082 T * const remaining_pos = pos + raw_gap;
3083 if(remaining_pos != old_start){ //Make sure data has to be moved
3084 ::boost::container::move(remaining_pos, old_finish, old_start);
3085 }
3086 //Once moved, avoid calling the destructors if trivial after move
3087 BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){
3088 old_values_destroyer.release();
3089 }
3090 }
3091 else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy
3092 ::boost::container::uninitialized_move_alloc_n
3093 (a, pos, static_cast<size_type>(old_finish - pos), new_start + before_plus_new);
3094 this->m_holder.set_stored_size(new_size);
3095 old_values_destroyer.release();
3096 }
3097 }
3098 }
3099 else{
3100 //Check if we have to do the insertion in two phases
3101 //since maybe s_before is not big enough and
3102 //the buffer was expanded both sides
3103 //
3104 //Old situation:
3105 // _________________________________________________
3106 //| raw_mem | old_begin + old_end | raw_mem |
3107 //|_________|_____________________|_________________|
3108 //
3109 //New situation with do_after:
3110 // _________________________________________________
3111 //| old_begin + new + old_end | raw_mem |
3112 //|___________________________________|_____________|
3113 //
3114 //New without do_after:
3115 // _________________________________________________
3116 //| old_begin + new + old_end | raw_mem |
3117 //|____________________________|____________________|
3118 //
3119 const bool do_after = n > s_before;
3120
3121 //Now we can have two situations: the raw_mem of the
3122 //beginning divides the old_begin, or the new elements:
3123 if (s_before <= elemsbefore) {
3124 //The raw memory divides the old_begin group:
3125 //
3126 //If we need two phase construction (do_after)
3127 //new group is divided in new = new_beg + new_end groups
3128 //In this phase only new_beg will be inserted
3129 //
3130 //Old situation:
3131 // _________________________________________________
3132 //| raw_mem | old_begin | old_end | raw_mem |
3133 //|_________|___________|_________|_________________|
3134 //
3135 //New situation with do_after(1):
3136 //This is not definitive situation, the second phase
3137 //will include
3138 // _________________________________________________
3139 //| old_begin | new_beg | old_end | raw_mem |
3140 //|___________|_________|_________|_________________|
3141 //
3142 //New situation without do_after:
3143 // _________________________________________________
3144 //| old_begin | new | old_end | raw_mem |
3145 //|___________|_____|_________|_____________________|
3146 //
3147 //Copy the first part of old_begin to raw_mem
3148 ::boost::container::uninitialized_move_alloc_n(a, old_start, s_before, new_start);
3149 //The buffer is all constructed until old_end,
3150 //so program trailing destruction and assign final size
3151 //if !do_after, s_before+n otherwise.
3152 size_type new_1st_range;
3153 if(do_after){
3154 new_1st_range = s_before;
3155 //release destroyer and update size
3156 old_values_destroyer.release();
3157 }
3158 else{
3159 new_1st_range = n;
3160 BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){
3161 old_values_destroyer.release();
3162 }
3163 else{
3164 old_values_destroyer.shrink_forward(old_size - (s_before - n));
3165 }
3166 }
3167 this->m_holder.set_stored_size(old_size + new_1st_range);
3168 //Now copy the second part of old_begin overwriting itself
3169 T *const next = ::boost::container::move(old_start + s_before, pos, old_start);
3170 //Now copy the new_beg elements
3171 insert_range_proxy.copy_n_and_update(a, next, new_1st_range);
3172
3173 //If there is no after work and the last old part needs to be moved to front, do it
3174 if(!do_after && (n != s_before)){
3175 //Now displace old_end elements
3176 ::boost::container::move(pos, old_finish, next + new_1st_range);
3177 }
3178 }
3179 else {
3180 //If we have to expand both sides,
3181 //we will play if the first new values so
3182 //calculate the upper bound of new values
3183
3184 //The raw memory divides the new elements
3185 //
3186 //If we need two phase construction (do_after)
3187 //new group is divided in new = new_beg + new_end groups
3188 //In this phase only new_beg will be inserted
3189 //
3190 //Old situation:
3191 // _______________________________________________________
3192 //| raw_mem | old_begin | old_end | raw_mem |
3193 //|_______________|___________|_________|_________________|
3194 //
3195 //New situation with do_after():
3196 // ____________________________________________________
3197 //| old_begin | new_beg | old_end | raw_mem |
3198 //|___________|_______________|_________|______________|
3199 //
3200 //New situation without do_after:
3201 // ______________________________________________________
3202 //| old_begin | new | old_end | raw_mem |
3203 //|___________|_____|_________|__________________________|
3204 //
3205 //First copy whole old_begin and part of new to raw_mem
3206 T * const new_pos = ::boost::container::uninitialized_move_alloc
3207 (a, old_start, pos, new_start);
3208 this->m_holder.set_stored_size(elemsbefore);
3209 const size_type mid_n = s_before - elemsbefore;
3210 insert_range_proxy.uninitialized_copy_n_and_update(a, new_pos, mid_n);
3211 //The buffer is all constructed until old_end,
3212 //release destroyer
3213 this->m_holder.set_stored_size(old_size + s_before);
3214 old_values_destroyer.release();
3215
3216 if(do_after){
3217 //Copy new_beg part
3218 insert_range_proxy.copy_n_and_update(a, old_start, elemsbefore);
3219 }
3220 else{
3221 //Copy all new elements
3222 const size_type rest_new = n - mid_n;
3223 insert_range_proxy.copy_n_and_update(a, old_start, rest_new);
3224
3225 T* const move_start = old_start + rest_new;
3226 //Displace old_end, but make sure data has to be moved
3227 T* const move_end = move_start != pos ? ::boost::container::move(pos, old_finish, move_start)
3228 : old_finish;
3229 (void)move_end; //To avoid warnings of unused initialization for move_end in case
3230 //trivial_dctr_after_move is true
3231 //Destroy remaining moved elements from old_end except if they
3232 //have trivial destructor after being moved
3233 const size_type n_destroy = s_before - n;
3234 BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){
3235 boost::container::destroy_alloc_n(a, move_end, n_destroy);
3236 }
3237 this->m_holder.dec_stored_size(n_destroy);
3238 }
3239 }
3240
3241 //This is only executed if two phase construction is needed
3242 if(do_after){
3243 //The raw memory divides the new elements
3244 //
3245 //Old situation:
3246 // ______________________________________________________
3247 //| raw_mem | old_begin | old_end | raw_mem |
3248 //|______________|___________|____________|______________|
3249 //
3250 //New situation with do_after(1):
3251 // _______________________________________________________
3252 //| old_begin + new_beg | new_end |old_end | raw_mem |
3253 //|__________________________|_________|________|_________|
3254 //
3255 //New situation with do_after(2):
3256 // ______________________________________________________
3257 //| old_begin + new | old_end |raw |
3258 //|_______________________________________|_________|____|
3259 //
3260 const size_type n_after = n - s_before;
3261 const size_type elemsafter = old_size - elemsbefore;
3262
3263 //We can have two situations:
3264 if (elemsafter >= n_after){
3265 //The raw_mem from end will divide displaced old_end
3266 //
3267 //Old situation:
3268 // ______________________________________________________
3269 //| raw_mem | old_begin | old_end | raw_mem |
3270 //|______________|___________|____________|______________|
3271 //
3272 //New situation with do_after(1):
3273 // _______________________________________________________
3274 //| old_begin + new_beg | new_end |old_end | raw_mem |
3275 //|__________________________|_________|________|_________|
3276 //
3277 //First copy the part of old_end raw_mem
3278 T* finish_n = old_finish - n_after;
3279 ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish);
3280 this->m_holder.inc_stored_size(n_after);
3281 //Displace the rest of old_end to the new position
3282 boost::container::move_backward(pos, finish_n, old_finish);
3283 //Now overwrite with new_end
3284 //The new_end part is [first + (n - n_after), last)
3285 insert_range_proxy.copy_n_and_update(a, pos, n_after);
3286 }
3287 else {
3288 //The raw_mem from end will divide new_end part
3289 //
3290 //Old situation:
3291 // _____________________________________________________________
3292 //| raw_mem | old_begin | old_end | raw_mem |
3293 //|______________|___________|____________|_____________________|
3294 //
3295 //New situation with do_after(2):
3296 // _____________________________________________________________
3297 //| old_begin + new_beg | new_end |old_end | raw_mem |
3298 //|__________________________|_______________|________|_________|
3299
3300 //First initialize data in raw memory
3301 const size_type mid_last_dist = n_after - elemsafter;
3302
3303 //Copy to the old_end part to the uninitialized zone leaving a gap.
3304 ::boost::container::uninitialized_move_alloc(a, pos, old_finish, old_finish + mid_last_dist);
3305
3306 array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, static_cast<size_type>(old_finish - pos));
3307
3308 //Copy the first part to the already constructed old_end zone
3309 insert_range_proxy.copy_n_and_update(a, pos, elemsafter);
3310 //Copy the rest to the uninitialized zone filling the gap
3311 insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist);
3312 this->m_holder.inc_stored_size(n_after);
3313 old_end_destroyer.release();
3314 }
3315 }
3316 }
3317 }
3318
priv_throw_if_out_of_range(size_type n) const3319 void priv_throw_if_out_of_range(size_type n) const
3320 {
3321 //If n is out of range, throw an out_of_range exception
3322 if (n >= this->size()){
3323 throw_out_of_range("vector::at out of range");
3324 }
3325 }
3326
priv_in_range(const_iterator pos) const3327 BOOST_CONTAINER_FORCEINLINE bool priv_in_range(const_iterator pos) const
3328 {
3329 return (this->begin() <= pos) && (pos < this->end());
3330 }
3331
priv_in_range_or_end(const_iterator pos) const3332 BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const
3333 {
3334 return (this->begin() <= pos) && (pos <= this->end());
3335 }
3336
3337 #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
3338 public:
3339 unsigned int num_expand_fwd;
3340 unsigned int num_expand_bwd;
3341 unsigned int num_shrink;
3342 unsigned int num_alloc;
reset_alloc_stats()3343 void reset_alloc_stats()
3344 { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; }
3345 #endif
3346 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
3347 };
3348
3349 #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
3350
3351 template <typename InputIterator>
3352 vector(InputIterator, InputIterator) ->
3353 vector<typename iterator_traits<InputIterator>::value_type>;
3354
3355 template <typename InputIterator, typename Allocator>
3356 vector(InputIterator, InputIterator, Allocator const&) ->
3357 vector<typename iterator_traits<InputIterator>::value_type, Allocator>;
3358
3359 #endif
3360
3361
3362 }} //namespace boost::container
3363
3364 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
3365
3366 namespace boost {
3367
3368 //!has_trivial_destructor_after_move<> == true_type
3369 //!specialization for optimizations
3370 template <class T, class Allocator, class Options>
3371 struct has_trivial_destructor_after_move<boost::container::vector<T, Allocator, Options> >
3372 {
3373 typedef typename boost::container::vector<T, Allocator, Options>::allocator_type allocator_type;
3374 typedef typename ::boost::container::allocator_traits<allocator_type>::pointer pointer;
3375 static const bool value = ::boost::has_trivial_destructor_after_move<allocator_type>::value &&
3376 ::boost::has_trivial_destructor_after_move<pointer>::value;
3377 };
3378
3379 }
3380
3381 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
3382
3383 #include <boost/container/detail/config_end.hpp>
3384
3385 #endif // #ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP
3386