fix doc example typo
[boost.git] / boost / interprocess / containers / container / vector.hpp
blob4c38e25a5326aa2abc95d08e2f8d45ffd901c639
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2008. 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 //////////////////////////////////////////////////////////////////////////////
11 // This file comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga.
12 // Renaming, isolating and porting to generic algorithms. Pointer typedef
13 // set to allocator::pointer to allow placing it in shared memory.
15 ///////////////////////////////////////////////////////////////////////////////
16 // Copyright (c) 1994
17 // Hewlett-Packard Company
18 //
19 // Permission to use, copy, modify, distribute and sell this software
20 // and its documentation for any purpose is hereby granted without fee,
21 // provided that the above copyright notice appear in all copies and
22 // that both that copyright notice and this permission notice appear
23 // in supporting documentation. Hewlett-Packard Company makes no
24 // representations about the suitability of this software for any
25 // purpose. It is provided "as is" without express or implied warranty.
26 //
27 //
28 // Copyright (c) 1996
29 // Silicon Graphics Computer Systems, Inc.
30 //
31 // Permission to use, copy, modify, distribute and sell this software
32 // and its documentation for any purpose is hereby granted without fee,
33 // provided that the above copyright notice appear in all copies and
34 // that both that copyright notice and this permission notice appear
35 // in supporting documentation. Silicon Graphics makes no
36 // representations about the suitability of this software for any
37 // purpose. It is provided "as is" without express or implied warranty.
39 #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP
40 #define BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP
42 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
43 # pragma once
44 #endif
46 #include <boost/interprocess/containers/container/detail/config_begin.hpp>
47 #include <boost/interprocess/containers/container/detail/workaround.hpp>
49 #include <cstddef>
50 #include <memory>
51 #include <algorithm>
52 #include <stdexcept>
53 #include <iterator>
54 #include <utility>
55 #include <boost/detail/no_exceptions_support.hpp>
56 #include <boost/type_traits/has_trivial_destructor.hpp>
57 #include <boost/type_traits/has_trivial_copy.hpp>
58 #include <boost/type_traits/has_trivial_assign.hpp>
59 #include <boost/type_traits/has_nothrow_copy.hpp>
60 #include <boost/type_traits/has_nothrow_assign.hpp>
61 #include <boost/interprocess/containers/container/detail/version_type.hpp>
62 #include <boost/interprocess/containers/container/detail/allocation_type.hpp>
63 #include <boost/interprocess/containers/container/detail/utilities.hpp>
64 #include <boost/interprocess/containers/container/detail/iterators.hpp>
65 #include <boost/interprocess/containers/container/detail/algorithms.hpp>
66 #include <boost/interprocess/containers/container/detail/destroyers.hpp>
67 #include <boost/interprocess/containers/container/containers_fwd.hpp>
68 #include <boost/interprocess/detail/move.hpp>
69 #include <boost/pointer_to_other.hpp>
70 #include <boost/interprocess/containers/container/detail/mpl.hpp>
71 #include <boost/interprocess/containers/container/detail/advanced_insert_int.hpp>
73 #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
74 namespace boost {
75 namespace interprocess {
76 #else
77 namespace boost {
78 namespace interprocess_container {
79 #endif
81 /// @cond
83 namespace containers_detail {
85 //! Const vector_iterator used to iterate through a vector.
86 template <class Pointer>
87 class vector_const_iterator
88 : public std::iterator<std::random_access_iterator_tag
89 ,const typename std::iterator_traits<Pointer>::value_type
90 ,typename std::iterator_traits<Pointer>::difference_type
91 ,typename boost::pointer_to_other
92 <Pointer
93 ,const typename std::iterator_traits<Pointer>::value_type
94 >::type
95 ,const typename std::iterator_traits<Pointer>::value_type &>
97 public:
98 typedef const typename std::iterator_traits<Pointer>::value_type value_type;
99 typedef typename std::iterator_traits<Pointer>::difference_type difference_type;
100 typedef typename boost::pointer_to_other<Pointer, value_type>::type pointer;
101 typedef value_type& reference;
103 /// @cond
104 protected:
105 Pointer m_ptr;
107 public:
108 Pointer get_ptr() const { return m_ptr; }
109 explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){}
110 /// @endcond
112 public:
114 //Constructors
115 vector_const_iterator() : m_ptr(0){}
117 //Pointer like operators
118 reference operator*() const
119 { return *m_ptr; }
121 const value_type * operator->() const
122 { return containers_detail::get_pointer(m_ptr); }
124 reference operator[](difference_type off) const
125 { return m_ptr[off]; }
127 //Increment / Decrement
128 vector_const_iterator& operator++()
129 { ++m_ptr; return *this; }
131 vector_const_iterator operator++(int)
132 { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); }
134 vector_const_iterator& operator--()
135 { --m_ptr; return *this; }
137 vector_const_iterator operator--(int)
138 { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); }
140 //Arithmetic
141 vector_const_iterator& operator+=(difference_type off)
142 { m_ptr += off; return *this; }
144 vector_const_iterator operator+(difference_type off) const
145 { return vector_const_iterator(m_ptr+off); }
147 friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right)
148 { return vector_const_iterator(off + right.m_ptr); }
150 vector_const_iterator& operator-=(difference_type off)
151 { m_ptr -= off; return *this; }
153 vector_const_iterator operator-(difference_type off) const
154 { return vector_const_iterator(m_ptr-off); }
156 difference_type operator-(const vector_const_iterator& right) const
157 { return m_ptr - right.m_ptr; }
159 //Comparison operators
160 bool operator== (const vector_const_iterator& r) const
161 { return m_ptr == r.m_ptr; }
163 bool operator!= (const vector_const_iterator& r) const
164 { return m_ptr != r.m_ptr; }
166 bool operator< (const vector_const_iterator& r) const
167 { return m_ptr < r.m_ptr; }
169 bool operator<= (const vector_const_iterator& r) const
170 { return m_ptr <= r.m_ptr; }
172 bool operator> (const vector_const_iterator& r) const
173 { return m_ptr > r.m_ptr; }
175 bool operator>= (const vector_const_iterator& r) const
176 { return m_ptr >= r.m_ptr; }
179 //! Iterator used to iterate through a vector
180 template <class Pointer>
181 class vector_iterator
182 : public vector_const_iterator<Pointer>
184 public:
185 explicit vector_iterator(Pointer ptr)
186 : vector_const_iterator<Pointer>(ptr)
189 public:
190 typedef typename std::iterator_traits<Pointer>::value_type value_type;
191 typedef typename vector_const_iterator<Pointer>::difference_type difference_type;
192 typedef Pointer pointer;
193 typedef value_type& reference;
195 //Constructors
196 vector_iterator()
199 //Pointer like operators
200 reference operator*() const
201 { return *this->m_ptr; }
203 value_type* operator->() const
204 { return containers_detail::get_pointer(this->m_ptr); }
206 reference operator[](difference_type off) const
207 { return this->m_ptr[off]; }
209 //Increment / Decrement
210 vector_iterator& operator++()
211 { ++this->m_ptr; return *this; }
213 vector_iterator operator++(int)
214 { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); }
216 vector_iterator& operator--()
217 { --this->m_ptr; return *this; }
219 vector_iterator operator--(int)
220 { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); }
222 // Arithmetic
223 vector_iterator& operator+=(difference_type off)
224 { this->m_ptr += off; return *this; }
226 vector_iterator operator+(difference_type off) const
227 { return vector_iterator(this->m_ptr+off); }
229 friend vector_iterator operator+(difference_type off, const vector_iterator& right)
230 { return vector_iterator(off + right.m_ptr); }
232 vector_iterator& operator-=(difference_type off)
233 { this->m_ptr -= off; return *this; }
235 vector_iterator operator-(difference_type off) const
236 { return vector_iterator(this->m_ptr-off); }
238 difference_type operator-(const vector_const_iterator<Pointer>& right) const
239 { return static_cast<const vector_const_iterator<Pointer>&>(*this) - right; }
242 template <class T, class A>
243 struct vector_value_traits
245 typedef T value_type;
246 typedef A allocator_type;
247 static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value;
248 static const bool trivial_dctr_after_move =
249 boost::interprocess::has_trivial_destructor_after_move<value_type>::value || trivial_dctr;
250 static const bool trivial_copy = has_trivial_copy<value_type>::value;
251 static const bool nothrow_copy = has_nothrow_copy<value_type>::value;
252 static const bool trivial_assign = has_trivial_assign<value_type>::value;
253 static const bool nothrow_assign = has_nothrow_assign<value_type>::value;
255 //This is the anti-exception array destructor
256 //to deallocate values already constructed
257 typedef typename containers_detail::if_c
258 <trivial_dctr
259 ,containers_detail::null_scoped_destructor_n<allocator_type>
260 ,containers_detail::scoped_destructor_n<allocator_type>
261 >::type OldArrayDestructor;
262 //This is the anti-exception array destructor
263 //to destroy objects created with copy construction
264 typedef typename containers_detail::if_c
265 <nothrow_copy
266 ,containers_detail::null_scoped_destructor_n<allocator_type>
267 ,containers_detail::scoped_destructor_n<allocator_type>
268 >::type UCopiedArrayDestructor;
269 //This is the anti-exception array deallocator
270 typedef typename containers_detail::if_c
271 <nothrow_copy
272 ,containers_detail::null_scoped_array_deallocator<allocator_type>
273 ,containers_detail::scoped_array_deallocator<allocator_type>
274 >::type UCopiedArrayDeallocator;
277 //!This struct deallocates and allocated memory
278 template <class A>
279 struct vector_alloc_holder
281 typedef typename A::pointer pointer;
282 typedef typename A::size_type size_type;
283 typedef typename A::value_type value_type;
284 typedef vector_value_traits<value_type, A> value_traits;
286 //Constructor, does not throw
287 vector_alloc_holder(const A &a)
288 : members_(a)
291 //Constructor, does not throw
292 vector_alloc_holder(const vector_alloc_holder<A> &h)
293 : members_(h.alloc())
296 //Destructor
297 ~vector_alloc_holder()
299 this->prot_destroy_all();
300 this->prot_deallocate();
303 typedef containers_detail::integral_constant<unsigned, 1> allocator_v1;
304 typedef containers_detail::integral_constant<unsigned, 2> allocator_v2;
305 typedef containers_detail::integral_constant<unsigned,
306 boost::interprocess_container::containers_detail::version<A>::value> alloc_version;
307 std::pair<pointer, bool>
308 allocation_command(allocation_type command,
309 size_type limit_size,
310 size_type preferred_size,
311 size_type &received_size, const pointer &reuse = 0)
313 return allocation_command(command, limit_size, preferred_size,
314 received_size, reuse, alloc_version());
317 std::pair<pointer, bool>
318 allocation_command(allocation_type command,
319 size_type limit_size,
320 size_type preferred_size,
321 size_type &received_size,
322 const pointer &reuse,
323 allocator_v1)
325 (void)limit_size;
326 (void)reuse;
327 if(!(command & allocate_new))
328 return std::pair<pointer, bool>(pointer(0), 0);
329 received_size = preferred_size;
330 return std::make_pair(this->alloc().allocate(received_size), false);
333 std::pair<pointer, bool>
334 allocation_command(allocation_type command,
335 size_type limit_size,
336 size_type preferred_size,
337 size_type &received_size,
338 const pointer &reuse,
339 allocator_v2)
341 return this->alloc().allocation_command
342 (command, limit_size, preferred_size, received_size, reuse);
345 size_type next_capacity(size_type additional_objects) const
346 { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); }
348 struct members_holder
349 : public A
351 private:
352 members_holder(const members_holder&);
354 public:
355 members_holder(const A &alloc)
356 : A(alloc), m_start(0), m_size(0), m_capacity(0)
359 pointer m_start;
360 size_type m_size;
361 size_type m_capacity;
362 } members_;
364 protected:
365 void prot_deallocate()
367 if(!this->members_.m_capacity) return;
368 this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
369 this->members_.m_start = 0;
370 this->members_.m_size = 0;
371 this->members_.m_capacity = 0;
374 void destroy(value_type* p)
376 if(!value_traits::trivial_dctr)
377 containers_detail::get_pointer(p)->~value_type();
380 void destroy_n(value_type* p, size_type n)
382 if(!value_traits::trivial_dctr)
383 for(; n--; ++p) p->~value_type();
386 void prot_destroy_all()
388 this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size);
389 this->members_.m_size = 0;
392 A &alloc()
393 { return members_; }
395 const A &alloc() const
396 { return members_; }
399 } //namespace containers_detail {
400 /// @endcond
402 //! \class ::boost::interprocess::vector boost/interprocess/containers/container/vector.hpp <boost/interprocess/containers/vector.hpp>
403 //! A vector is a sequence that supports random access to elements, constant
404 //! time insertion and removal of elements at the end, and linear time insertion
405 //! and removal of elements at the beginning or in the middle. The number of
406 //! elements in a vector may vary dynamically; memory management is automatic.
407 //! boost::interprocess_container::vector is similar to std::vector but it's compatible
408 //! with shared memory and memory mapped files.
409 template <class T, class A>
410 class vector : private containers_detail::vector_alloc_holder<A>
412 /// @cond
413 typedef vector<T, A> self_t;
414 typedef containers_detail::vector_alloc_holder<A> base_t;
415 /// @endcond
416 public:
417 //! The type of object, T, stored in the vector
418 typedef T value_type;
419 //! Pointer to T
420 typedef typename A::pointer pointer;
421 //! Const pointer to T
422 typedef typename A::const_pointer const_pointer;
423 //! Reference to T
424 typedef typename A::reference reference;
425 //! Const reference to T
426 typedef typename A::const_reference const_reference;
427 //! An unsigned integral type
428 typedef typename A::size_type size_type;
429 //! A signed integral type
430 typedef typename A::difference_type difference_type;
431 //! The allocator type
432 typedef A allocator_type;
433 //! The random access iterator
434 typedef containers_detail::vector_iterator<pointer> iterator;
435 //! The random access const_iterator
436 typedef containers_detail::vector_const_iterator<pointer> const_iterator;
438 //! Iterator used to iterate backwards through a vector.
439 typedef std::reverse_iterator<iterator>
440 reverse_iterator;
441 //! Const iterator used to iterate backwards through a vector.
442 typedef std::reverse_iterator<const_iterator>
443 const_reverse_iterator;
444 //! The stored allocator type
445 typedef allocator_type stored_allocator_type;
447 /// @cond
448 private:
449 typedef containers_detail::advanced_insert_aux_int<T, T*> advanced_insert_aux_int_t;
450 typedef containers_detail::vector_value_traits<value_type, A> value_traits;
452 typedef typename base_t::allocator_v1 allocator_v1;
453 typedef typename base_t::allocator_v2 allocator_v2;
454 typedef typename base_t::alloc_version alloc_version;
456 typedef constant_iterator<T, difference_type> cvalue_iterator;
457 typedef repeat_iterator<T, difference_type> repeat_it;
458 typedef boost::interprocess::move_iterator<repeat_it> repeat_move_it;
459 /// @endcond
461 public:
462 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(vector)
464 //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
465 //!
466 //! <b>Throws</b>: If allocator_type's copy constructor throws.
467 //!
468 //! <b>Complexity</b>: Constant.
469 explicit vector(const A& a = A())
470 : base_t(a)
473 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
474 //! and inserts n default contructed values.
476 //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
477 //! throws or T's default or copy constructor throws.
478 //!
479 //! <b>Complexity</b>: Linear to n.
480 vector(size_type n)
481 : base_t(allocator_type())
482 { this->resize(n); }
484 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
485 //! and inserts n copies of value.
487 //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
488 //! throws or T's default or copy constructor throws.
489 //!
490 //! <b>Complexity</b>: Linear to n.
491 vector(size_type n, const T& value, const allocator_type& a = allocator_type())
492 : base_t(a)
493 { this->insert(this->cend(), n, value); }
495 //! <b>Effects</b>: Copy constructs a vector.
497 //! <b>Postcondition</b>: x == *this.
498 //!
499 //! <b>Complexity</b>: Linear to the elements x contains.
500 vector(const vector<T, A>& x)
501 : base_t((base_t&)x)
502 { *this = x; }
504 //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
506 //! <b>Throws</b>: If allocator_type's copy constructor throws.
507 //!
508 //! <b>Complexity</b>: Constant.
509 vector(BOOST_INTERPROCESS_RV_REF(vector) mx)
510 : base_t(boost::interprocess::move(mx))
511 { this->swap(mx); }
513 //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
514 //! and inserts a copy of the range [first, last) in the vector.
516 //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
517 //! throws or T's constructor taking an dereferenced InIt throws.
519 //! <b>Complexity</b>: Linear to the range [first, last).
520 template <class InIt>
521 vector(InIt first, InIt last, const allocator_type& a = allocator_type())
522 : base_t(a)
523 { this->assign(first, last); }
525 //! <b>Effects</b>: Destroys the vector. All stored values are destroyed
526 //! and used memory is deallocated.
528 //! <b>Throws</b>: Nothing.
530 //! <b>Complexity</b>: Linear to the number of elements.
531 ~vector()
532 {} //vector_alloc_holder clears the data
534 //! <b>Effects</b>: Returns an iterator to the first element contained in the vector.
535 //!
536 //! <b>Throws</b>: Nothing.
537 //!
538 //! <b>Complexity</b>: Constant.
539 iterator begin()
540 { return iterator(this->members_.m_start); }
542 //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
543 //!
544 //! <b>Throws</b>: Nothing.
545 //!
546 //! <b>Complexity</b>: Constant.
547 const_iterator begin() const
548 { return const_iterator(this->members_.m_start); }
550 //! <b>Effects</b>: Returns an iterator to the end of the vector.
551 //!
552 //! <b>Throws</b>: Nothing.
553 //!
554 //! <b>Complexity</b>: Constant.
555 iterator end()
556 { return iterator(this->members_.m_start + this->members_.m_size); }
558 //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
559 //!
560 //! <b>Throws</b>: Nothing.
561 //!
562 //! <b>Complexity</b>: Constant.
563 const_iterator end() const
564 { return this->cend(); }
566 //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
567 //! of the reversed vector.
568 //!
569 //! <b>Throws</b>: Nothing.
570 //!
571 //! <b>Complexity</b>: Constant.
572 reverse_iterator rbegin()
573 { return reverse_iterator(this->end()); }
575 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
576 //! of the reversed vector.
577 //!
578 //! <b>Throws</b>: Nothing.
579 //!
580 //! <b>Complexity</b>: Constant.
581 const_reverse_iterator rbegin()const
582 { return this->crbegin(); }
584 //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
585 //! of the reversed vector.
586 //!
587 //! <b>Throws</b>: Nothing.
588 //!
589 //! <b>Complexity</b>: Constant.
590 reverse_iterator rend()
591 { return reverse_iterator(this->begin()); }
593 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
594 //! of the reversed vector.
595 //!
596 //! <b>Throws</b>: Nothing.
597 //!
598 //! <b>Complexity</b>: Constant.
599 const_reverse_iterator rend() const
600 { return this->crend(); }
602 //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
603 //!
604 //! <b>Throws</b>: Nothing.
605 //!
606 //! <b>Complexity</b>: Constant.
607 const_iterator cbegin() const
608 { return const_iterator(this->members_.m_start); }
610 //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
611 //!
612 //! <b>Throws</b>: Nothing.
613 //!
614 //! <b>Complexity</b>: Constant.
615 const_iterator cend() const
616 { return const_iterator(this->members_.m_start + this->members_.m_size); }
618 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
619 //! of the reversed vector.
620 //!
621 //! <b>Throws</b>: Nothing.
622 //!
623 //! <b>Complexity</b>: Constant.
624 const_reverse_iterator crbegin()const
625 { return const_reverse_iterator(this->end());}
627 //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
628 //! of the reversed vector.
629 //!
630 //! <b>Throws</b>: Nothing.
631 //!
632 //! <b>Complexity</b>: Constant.
633 const_reverse_iterator crend() const
634 { return const_reverse_iterator(this->begin()); }
636 //! <b>Requires</b>: !empty()
638 //! <b>Effects</b>: Returns a reference to the first element
639 //! from the beginning of the container.
640 //!
641 //! <b>Throws</b>: Nothing.
642 //!
643 //! <b>Complexity</b>: Constant.
644 reference front()
645 { return *this->members_.m_start; }
647 //! <b>Requires</b>: !empty()
649 //! <b>Effects</b>: Returns a const reference to the first element
650 //! from the beginning of the container.
651 //!
652 //! <b>Throws</b>: Nothing.
653 //!
654 //! <b>Complexity</b>: Constant.
655 const_reference front() const
656 { return *this->members_.m_start; }
658 //! <b>Requires</b>: !empty()
660 //! <b>Effects</b>: Returns a reference to the first element
661 //! from the beginning of the container.
662 //!
663 //! <b>Throws</b>: Nothing.
664 //!
665 //! <b>Complexity</b>: Constant.
666 reference back()
667 { return this->members_.m_start[this->members_.m_size - 1]; }
669 //! <b>Effects</b>: Returns a const reference to the first element
670 //! from the beginning of the container.
671 //!
672 //! <b>Throws</b>: Nothing.
673 //!
674 //! <b>Complexity</b>: Constant.
675 const_reference back() const
676 { return this->members_.m_start[this->members_.m_size - 1]; }
678 //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
679 //! For a non-empty vector, data() == &front().
680 //!
681 //! <b>Throws</b>: Nothing.
682 //!
683 //! <b>Complexity</b>: Constant.
684 pointer data()
685 { return this->members_.m_start; }
687 //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
688 //! For a non-empty vector, data() == &front().
689 //!
690 //! <b>Throws</b>: Nothing.
691 //!
692 //! <b>Complexity</b>: Constant.
693 const_pointer data() const
694 { return this->members_.m_start; }
696 //! <b>Effects</b>: Returns the number of the elements contained in the vector.
697 //!
698 //! <b>Throws</b>: Nothing.
699 //!
700 //! <b>Complexity</b>: Constant.
701 size_type size() const
702 { return this->members_.m_size; }
704 //! <b>Effects</b>: Returns the largest possible size of the vector.
705 //!
706 //! <b>Throws</b>: Nothing.
707 //!
708 //! <b>Complexity</b>: Constant.
709 size_type max_size() const
710 { return this->alloc().max_size(); }
712 //! <b>Effects</b>: Number of elements for which memory has been allocated.
713 //! capacity() is always greater than or equal to size().
714 //!
715 //! <b>Throws</b>: Nothing.
716 //!
717 //! <b>Complexity</b>: Constant.
718 size_type capacity() const
719 { return this->members_.m_capacity; }
721 //! <b>Effects</b>: Returns true if the vector contains no elements.
722 //!
723 //! <b>Throws</b>: Nothing.
724 //!
725 //! <b>Complexity</b>: Constant.
726 bool empty() const
727 { return !this->members_.m_size; }
729 //! <b>Requires</b>: size() < n.
731 //! <b>Effects</b>: Returns a reference to the nth element
732 //! from the beginning of the container.
733 //!
734 //! <b>Throws</b>: Nothing.
735 //!
736 //! <b>Complexity</b>: Constant.
737 reference operator[](size_type n)
738 { return this->members_.m_start[n]; }
740 //! <b>Requires</b>: size() < n.
742 //! <b>Effects</b>: Returns a const reference to the nth element
743 //! from the beginning of the container.
744 //!
745 //! <b>Throws</b>: Nothing.
746 //!
747 //! <b>Complexity</b>: Constant.
748 const_reference operator[](size_type n) const
749 { return this->members_.m_start[n]; }
751 //! <b>Requires</b>: size() < n.
753 //! <b>Effects</b>: Returns a reference to the nth element
754 //! from the beginning of the container.
755 //!
756 //! <b>Throws</b>: std::range_error if n >= size()
757 //!
758 //! <b>Complexity</b>: Constant.
759 reference at(size_type n)
760 { this->priv_check_range(n); return this->members_.m_start[n]; }
762 //! <b>Requires</b>: size() < n.
764 //! <b>Effects</b>: Returns a const reference to the nth element
765 //! from the beginning of the container.
766 //!
767 //! <b>Throws</b>: std::range_error if n >= size()
768 //!
769 //! <b>Complexity</b>: Constant.
770 const_reference at(size_type n) const
771 { this->priv_check_range(n); return this->members_.m_start[n]; }
773 //! <b>Effects</b>: Returns a copy of the internal allocator.
774 //!
775 //! <b>Throws</b>: If allocator's copy constructor throws.
776 //!
777 //! <b>Complexity</b>: Constant.
778 allocator_type get_allocator() const
779 { return this->alloc(); }
781 const stored_allocator_type &get_stored_allocator() const
782 { return this->alloc(); }
784 stored_allocator_type &get_stored_allocator()
785 { return this->alloc(); }
787 //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
788 //! effect. Otherwise, it is a request for allocation of additional memory.
789 //! If the request is successful, then capacity() is greater than or equal to
790 //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
791 //!
792 //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
793 void reserve(size_type new_cap)
795 if (this->capacity() < new_cap){
796 //There is not enough memory, allocate a new
797 //buffer or expand the old one.
798 bool same_buffer_start;
799 size_type real_cap = 0;
800 std::pair<pointer, bool> ret =
801 this->allocation_command
802 (allocate_new | expand_fwd | expand_bwd,
803 new_cap, new_cap, real_cap, this->members_.m_start);
805 //Check for forward expansion
806 same_buffer_start = ret.second && this->members_.m_start == ret.first;
807 if(same_buffer_start){
808 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
809 ++this->num_expand_fwd;
810 #endif
811 this->members_.m_capacity = real_cap;
814 //If there is no forward expansion, move objects
815 else{
816 //We will reuse insert code, so create a dummy input iterator
817 T *dummy_it(containers_detail::get_pointer(this->members_.m_start));
818 containers_detail::advanced_insert_aux_proxy<T, boost::interprocess::move_iterator<T*>, T*>
819 proxy(boost::interprocess::make_move_iterator(dummy_it), boost::interprocess::make_move_iterator(dummy_it));
820 //Backwards (and possibly forward) expansion
821 if(ret.second){
822 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
823 ++this->num_expand_bwd;
824 #endif
825 this->priv_range_insert_expand_backwards
826 ( containers_detail::get_pointer(ret.first)
827 , real_cap
828 , containers_detail::get_pointer(this->members_.m_start)
830 , proxy);
832 //New buffer
833 else{
834 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
835 ++this->num_alloc;
836 #endif
837 this->priv_range_insert_new_allocation
838 ( containers_detail::get_pointer(ret.first)
839 , real_cap
840 , containers_detail::get_pointer(this->members_.m_start)
842 , proxy);
848 //! <b>Effects</b>: Makes *this contain the same elements as x.
850 //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
851 //! of each of x's elements.
853 //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
855 //! <b>Complexity</b>: Linear to the number of elements in x.
856 vector& operator=(const vector& x)
858 if (&x != this){
859 this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size);
861 return *this;
864 //! <b>Effects</b>: Move assignment. All mx's values are transferred to *this.
866 //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
867 //! before the function.
869 //! <b>Throws</b>: If allocator_type's copy constructor throws.
871 //! <b>Complexity</b>: Constant.
872 vector& operator=(BOOST_INTERPROCESS_RV_REF(vector) x)
874 if (&x != this){
875 this->swap(x);
876 x.clear();
878 return *this;
881 //! <b>Effects</b>: Assigns the n copies of val to *this.
883 //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
885 //! <b>Complexity</b>: Linear to n.
886 void assign(size_type n, const value_type& val)
887 { this->assign(cvalue_iterator(val, n), cvalue_iterator()); }
889 //! <b>Effects</b>: Assigns the the range [first, last) to *this.
891 //! <b>Throws</b>: If memory allocation throws or
892 //! T's constructor from dereferencing InpIt throws.
894 //! <b>Complexity</b>: Linear to n.
895 template <class InIt>
896 void assign(InIt first, InIt last)
898 //Dispatch depending on integer/iterator
899 const bool aux_boolean = containers_detail::is_convertible<InIt, std::size_t>::value;
900 typedef containers_detail::bool_<aux_boolean> Result;
901 this->priv_assign_dispatch(first, last, Result());
904 //! <b>Effects</b>: Inserts a copy of x at the end of the vector.
906 //! <b>Throws</b>: If memory allocation throws or
907 //! T's copy constructor throws.
909 //! <b>Complexity</b>: Amortized constant time.
910 void push_back(const T& x)
912 if (this->members_.m_size < this->members_.m_capacity){
913 //There is more memory, just construct a new object at the end
914 new((void*)(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x);
915 ++this->members_.m_size;
917 else{
918 this->insert(this->cend(), x);
922 //! <b>Effects</b>: Constructs a new element in the end of the vector
923 //! and moves the resources of mx to this new element.
925 //! <b>Throws</b>: If memory allocation throws.
927 //! <b>Complexity</b>: Amortized constant time.
928 void push_back(BOOST_INTERPROCESS_RV_REF(T) x)
930 if (this->members_.m_size < this->members_.m_capacity){
931 //There is more memory, just construct a new object at the end
932 new((void*)containers_detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(boost::interprocess::move(x));
933 ++this->members_.m_size;
935 else{
936 this->insert(this->cend(), boost::interprocess::move(x));
940 #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
942 //! <b>Effects</b>: Inserts an object of type T constructed with
943 //! std::forward<Args>(args)... in the end of the vector.
945 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
947 //! <b>Complexity</b>: Amortized constant time.
948 template<class ...Args>
949 void emplace_back(Args &&...args)
951 T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size;
952 if (this->members_.m_size < this->members_.m_capacity){
953 //There is more memory, just construct a new object at the end
954 new((void*)(back_pos))value_type(boost::interprocess::forward<Args>(args)...);
955 ++this->members_.m_size;
957 else{
958 containers_detail::advanced_insert_aux_emplace<T, T*, Args...> proxy
959 (boost::interprocess::forward<Args>(args)...);
960 priv_range_insert(back_pos, 1, proxy);
964 //! <b>Requires</b>: position must be a valid iterator of *this.
966 //! <b>Effects</b>: Inserts an object of type T constructed with
967 //! std::forward<Args>(args)... before position
969 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
971 //! <b>Complexity</b>: If position is end(), amortized constant time
972 //! Linear time otherwise.
973 template<class ...Args>
974 iterator emplace(const_iterator position, Args && ...args)
976 //Just call more general insert(pos, size, value) and return iterator
977 size_type pos_n = position - cbegin();
978 containers_detail::advanced_insert_aux_emplace<T, T*, Args...> proxy
979 (boost::interprocess::forward<Args>(args)...);
980 priv_range_insert(position.get_ptr(), 1, proxy);
981 return iterator(this->members_.m_start + pos_n);
984 #else
986 void emplace_back()
988 T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size;
989 if (this->members_.m_size < this->members_.m_capacity){
990 //There is more memory, just construct a new object at the end
991 new((void*)(back_pos))value_type();
992 ++this->members_.m_size;
994 else{
995 containers_detail::advanced_insert_aux_emplace<value_type, T*> proxy;
996 priv_range_insert(back_pos, 1, proxy);
1000 iterator emplace(const_iterator position)
1002 size_type pos_n = position - cbegin();
1003 containers_detail::advanced_insert_aux_emplace<value_type, T*> proxy;
1004 priv_range_insert(containers_detail::get_pointer(position.get_ptr()), 1, proxy);
1005 return iterator(this->members_.m_start + pos_n);
1008 #define BOOST_PP_LOCAL_MACRO(n) \
1009 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
1010 void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
1012 T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; \
1013 if (this->members_.m_size < this->members_.m_capacity){ \
1014 new((void*)(back_pos))value_type \
1015 (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
1016 ++this->members_.m_size; \
1018 else{ \
1019 containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
1020 <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \
1021 proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
1022 priv_range_insert(back_pos, 1, proxy); \
1026 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
1027 iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
1029 size_type pos_n = pos - cbegin(); \
1030 containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
1031 <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \
1032 proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
1033 priv_range_insert(containers_detail::get_pointer(pos.get_ptr()), 1, proxy); \
1034 return iterator(this->members_.m_start + pos_n); \
1037 #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
1038 #include BOOST_PP_LOCAL_ITERATE()
1040 #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
1042 //! <b>Effects</b>: Swaps the contents of *this and x.
1043 //! If this->allocator_type() != x.allocator_type()
1044 //! allocators are also swapped.
1046 //! <b>Throws</b>: Nothing.
1048 //! <b>Complexity</b>: Constant.
1049 void swap(vector& x)
1051 allocator_type &this_al = this->alloc(), &other_al = x.alloc();
1052 //Just swap internals
1053 containers_detail::do_swap(this->members_.m_start, x.members_.m_start);
1054 containers_detail::do_swap(this->members_.m_size, x.members_.m_size);
1055 containers_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity);
1057 if (this_al != other_al){
1058 containers_detail::do_swap(this_al, other_al);
1062 //! <b>Requires</b>: position must be a valid iterator of *this.
1064 //! <b>Effects</b>: Insert a copy of x before position.
1066 //! <b>Throws</b>: If memory allocation throws or x's copy constructor throws.
1068 //! <b>Complexity</b>: If position is end(), amortized constant time
1069 //! Linear time otherwise.
1070 iterator insert(const_iterator position, const T& x)
1072 //Just call more general insert(pos, size, value) and return iterator
1073 size_type pos_n = position - cbegin();
1074 this->insert(position, (size_type)1, x);
1075 return iterator(this->members_.m_start + pos_n);
1078 //! <b>Requires</b>: position must be a valid iterator of *this.
1080 //! <b>Effects</b>: Insert a new element before position with mx's resources.
1082 //! <b>Throws</b>: If memory allocation throws.
1084 //! <b>Complexity</b>: If position is end(), amortized constant time
1085 //! Linear time otherwise.
1086 iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x)
1088 //Just call more general insert(pos, size, value) and return iterator
1089 size_type pos_n = position - cbegin();
1090 this->insert(position
1091 ,repeat_move_it(repeat_it(x, 1))
1092 ,repeat_move_it(repeat_it()));
1093 return iterator(this->members_.m_start + pos_n);
1096 //! <b>Requires</b>: pos must be a valid iterator of *this.
1098 //! <b>Effects</b>: Insert a copy of the [first, last) range before pos.
1100 //! <b>Throws</b>: If memory allocation throws, T's constructor from a
1101 //! dereferenced InpIt throws or T's copy constructor throws.
1103 //! <b>Complexity</b>: Linear to std::distance [first, last).
1104 template <class InIt>
1105 void insert(const_iterator pos, InIt first, InIt last)
1107 //Dispatch depending on integer/iterator
1108 const bool aux_boolean = containers_detail::is_convertible<InIt, std::size_t>::value;
1109 typedef containers_detail::bool_<aux_boolean> Result;
1110 this->priv_insert_dispatch(pos, first, last, Result());
1113 //! <b>Requires</b>: pos must be a valid iterator of *this.
1115 //! <b>Effects</b>: Insert n copies of x before pos.
1117 //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
1119 //! <b>Complexity</b>: Linear to n.
1120 void insert(const_iterator p, size_type n, const T& x)
1121 { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); }
1123 //! <b>Effects</b>: Removes the last element from the vector.
1125 //! <b>Throws</b>: Nothing.
1127 //! <b>Complexity</b>: Constant time.
1128 void pop_back()
1130 //Destroy last element
1131 --this->members_.m_size;
1132 this->destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size);
1135 //! <b>Effects</b>: Erases the element at position pos.
1137 //! <b>Throws</b>: Nothing.
1139 //! <b>Complexity</b>: Linear to the elements between pos and the
1140 //! last element. Constant if pos is the first or the last element.
1141 iterator erase(const_iterator position)
1143 T *pos = containers_detail::get_pointer(position.get_ptr());
1144 T *beg = containers_detail::get_pointer(this->members_.m_start);
1145 boost::interprocess::move(pos + 1, beg + this->members_.m_size, pos);
1146 --this->members_.m_size;
1147 //Destroy last element
1148 base_t::destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size);
1149 return iterator(position.get_ptr());
1152 //! <b>Effects</b>: Erases the elements pointed by [first, last).
1154 //! <b>Throws</b>: Nothing.
1156 //! <b>Complexity</b>: Linear to the distance between first and last.
1157 iterator erase(const_iterator first, const_iterator last)
1159 if (first != last){ // worth doing, copy down over hole
1160 T* end_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size;
1161 T* ptr = containers_detail::get_pointer(boost::interprocess::move
1162 (containers_detail::get_pointer(last.get_ptr())
1163 ,end_pos
1164 ,containers_detail::get_pointer(first.get_ptr())
1166 size_type destroyed = (end_pos - ptr);
1167 this->destroy_n(ptr, destroyed);
1168 this->members_.m_size -= destroyed;
1170 return iterator(first.get_ptr());
1173 //! <b>Effects</b>: Inserts or erases elements at the end such that
1174 //! the size becomes n. New elements are copy constructed from x.
1176 //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
1178 //! <b>Complexity</b>: Linear to the difference between size() and new_size.
1179 void resize(size_type new_size, const T& x)
1181 pointer finish = this->members_.m_start + this->members_.m_size;
1182 if (new_size < size()){
1183 //Destroy last elements
1184 this->erase(const_iterator(this->members_.m_start + new_size), this->end());
1186 else{
1187 //Insert new elements at the end
1188 this->insert(const_iterator(finish), new_size - this->size(), x);
1192 //! <b>Effects</b>: Inserts or erases elements at the end such that
1193 //! the size becomes n. New elements are default constructed.
1195 //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
1197 //! <b>Complexity</b>: Linear to the difference between size() and new_size.
1198 void resize(size_type new_size)
1200 if (new_size < this->size()){
1201 //Destroy last elements
1202 this->erase(const_iterator(this->members_.m_start + new_size), this->end());
1204 else{
1205 size_type n = new_size - this->size();
1206 this->reserve(new_size);
1207 containers_detail::default_construct_aux_proxy<T, T*, size_type> proxy(n);
1208 priv_range_insert(this->cend().get_ptr(), n, proxy);
1212 //! <b>Effects</b>: Erases all the elements of the vector.
1214 //! <b>Throws</b>: Nothing.
1216 //! <b>Complexity</b>: Linear to the number of elements in the vector.
1217 void clear()
1218 { this->prot_destroy_all(); }
1220 /// @cond
1222 //! <b>Effects</b>: Tries to deallocate the excess of memory created
1223 //! with previous allocations. The size of the vector is unchanged
1225 //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
1227 //! <b>Complexity</b>: Linear to size().
1228 void shrink_to_fit()
1229 { priv_shrink_to_fit(alloc_version()); }
1231 private:
1232 void priv_shrink_to_fit(allocator_v1)
1234 if(this->members_.m_capacity){
1235 if(!size()){
1236 this->prot_deallocate();
1238 else{
1239 //This would not work with stateful allocators
1240 vector<T, A>(*this).swap(*this);
1245 void priv_shrink_to_fit(allocator_v2)
1247 if(this->members_.m_capacity){
1248 if(!size()){
1249 this->prot_deallocate();
1251 else{
1252 size_type received_size;
1253 if(this->alloc().allocation_command
1254 ( shrink_in_place | nothrow_allocation
1255 , this->capacity(), this->size()
1256 , received_size, this->members_.m_start).first){
1257 this->members_.m_capacity = received_size;
1258 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
1259 ++this->num_shrink;
1260 #endif
1266 template <class FwdIt>
1267 void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag)
1269 if(first != last){
1270 const size_type n = std::distance(first, last);
1271 containers_detail::advanced_insert_aux_proxy<T, FwdIt, T*> proxy(first, last);
1272 priv_range_insert(pos, n, proxy);
1276 void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf)
1278 //Check if we have enough memory or try to expand current memory
1279 size_type remaining = this->members_.m_capacity - this->members_.m_size;
1280 bool same_buffer_start;
1281 std::pair<pointer, bool> ret;
1282 size_type real_cap = this->members_.m_capacity;
1284 //Check if we already have room
1285 if (n <= remaining){
1286 same_buffer_start = true;
1288 else{
1289 //There is not enough memory, allocate a new
1290 //buffer or expand the old one.
1291 size_type new_cap = this->next_capacity(n);
1292 ret = this->allocation_command
1293 (allocate_new | expand_fwd | expand_bwd,
1294 this->members_.m_size + n, new_cap, real_cap, this->members_.m_start);
1296 //Check for forward expansion
1297 same_buffer_start = ret.second && this->members_.m_start == ret.first;
1298 if(same_buffer_start){
1299 this->members_.m_capacity = real_cap;
1303 //If we had room or we have expanded forward
1304 if (same_buffer_start){
1305 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
1306 ++this->num_expand_fwd;
1307 #endif
1308 this->priv_range_insert_expand_forward
1309 (containers_detail::get_pointer(pos), n, interf);
1311 //Backwards (and possibly forward) expansion
1312 else if(ret.second){
1313 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
1314 ++this->num_expand_bwd;
1315 #endif
1316 this->priv_range_insert_expand_backwards
1317 ( containers_detail::get_pointer(ret.first)
1318 , real_cap
1319 , containers_detail::get_pointer(pos)
1321 , interf);
1323 //New buffer
1324 else{
1325 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
1326 ++this->num_alloc;
1327 #endif
1328 this->priv_range_insert_new_allocation
1329 ( containers_detail::get_pointer(ret.first)
1330 , real_cap
1331 , containers_detail::get_pointer(pos)
1333 , interf);
1337 void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf)
1339 //There is enough memory
1340 T* old_finish = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size;
1341 const size_type elems_after = old_finish - pos;
1343 if (elems_after > n){
1344 //New elements can be just copied.
1345 //Move to uninitialized memory last objects
1346 boost::interprocess::uninitialized_move(old_finish - n, old_finish, old_finish);
1347 this->members_.m_size += n;
1348 //Copy previous to last objects to the initialized end
1349 boost::interprocess::move_backward(pos, old_finish - n, old_finish);
1350 //Insert new objects in the pos
1351 interf.copy_all_to(pos);
1353 else {
1354 //The new elements don't fit in the [pos, end()) range. Copy
1355 //to the beginning of the unallocated zone the last new elements.
1356 interf.uninitialized_copy_some_and_update(old_finish, elems_after, false);
1357 this->members_.m_size += n - elems_after;
1358 //Copy old [pos, end()) elements to the uninitialized memory
1359 boost::interprocess::uninitialized_move
1360 ( pos, old_finish, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size);
1361 this->members_.m_size += elems_after;
1362 //Copy first new elements in pos
1363 interf.copy_all_to(pos);
1367 void priv_range_insert_new_allocation
1368 (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf)
1370 T* new_finish = new_start;
1371 T *old_finish;
1372 //Anti-exception rollbacks
1373 typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap);
1374 typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u);
1376 //Initialize with [begin(), pos) old buffer
1377 //the start of the new buffer
1378 new_finish = boost::interprocess::uninitialized_move
1379 (containers_detail::get_pointer(this->members_.m_start), pos, old_finish = new_finish);
1380 constructed_values_destroyer.increment_size(new_finish - old_finish);
1381 //Initialize new objects, starting from previous point
1382 interf.uninitialized_copy_all_to(old_finish = new_finish);
1383 new_finish += n;
1384 constructed_values_destroyer.increment_size(new_finish - old_finish);
1385 //Initialize from the rest of the old buffer,
1386 //starting from previous point
1387 new_finish = boost::interprocess::uninitialized_move
1388 ( pos, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size, new_finish);
1389 //All construction successful, disable rollbacks
1390 constructed_values_destroyer.release();
1391 scoped_alloc.release();
1392 //Destroy and deallocate old elements
1393 //If there is allocated memory, destroy and deallocate
1394 if(this->members_.m_start != 0){
1395 if(!value_traits::trivial_dctr_after_move)
1396 this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size);
1397 this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
1399 this->members_.m_start = new_start;
1400 this->members_.m_size = new_finish - new_start;
1401 this->members_.m_capacity = new_cap;
1404 void priv_range_insert_expand_backwards
1405 (T* new_start, size_type new_capacity,
1406 T* pos, const size_type n, advanced_insert_aux_int_t &interf)
1408 //Backup old data
1409 T* old_start = containers_detail::get_pointer(this->members_.m_start);
1410 T* old_finish = old_start + this->members_.m_size;
1411 size_type old_size = this->members_.m_size;
1413 //We can have 8 possibilities:
1414 const size_type elemsbefore = (size_type)(pos - old_start);
1415 const size_type s_before = (size_type)(old_start - new_start);
1417 //Update the vector buffer information to a safe state
1418 this->members_.m_start = new_start;
1419 this->members_.m_capacity = new_capacity;
1420 this->members_.m_size = 0;
1422 //If anything goes wrong, this object will destroy
1423 //all the old objects to fulfill previous vector state
1424 typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size);
1425 //Check if s_before is big enough to hold the beginning of old data + new data
1426 if(difference_type(s_before) >= difference_type(elemsbefore + n)){
1427 //Copy first old values before pos, after that the new objects
1428 boost::interprocess::uninitialized_move(old_start, pos, new_start);
1429 this->members_.m_size = elemsbefore;
1430 interf.uninitialized_copy_all_to(new_start + elemsbefore);
1431 this->members_.m_size += n;
1432 //Check if s_before is so big that even copying the old data + new data
1433 //there is a gap between the new data and the old data
1434 if(s_before >= (old_size + n)){
1435 //Old situation:
1436 // _________________________________________________________
1437 //| raw_mem | old_begin | old_end |
1438 //| __________________________________|___________|_________|
1440 //New situation:
1441 // _________________________________________________________
1442 //| old_begin | new | old_end | raw_mem |
1443 //|___________|__________|_________|________________________|
1445 //Now initialize the rest of memory with the last old values
1446 boost::interprocess::uninitialized_move
1447 (pos, old_finish, new_start + elemsbefore + n);
1448 //All new elements correctly constructed, avoid new element destruction
1449 this->members_.m_size = old_size + n;
1450 //Old values destroyed automatically with "old_values_destroyer"
1451 //when "old_values_destroyer" goes out of scope unless the have trivial
1452 //destructor after move.
1453 if(value_traits::trivial_dctr_after_move)
1454 old_values_destroyer.release();
1456 //s_before is so big that divides old_end
1457 else{
1458 //Old situation:
1459 // __________________________________________________
1460 //| raw_mem | old_begin | old_end |
1461 //| ___________________________|___________|_________|
1463 //New situation:
1464 // __________________________________________________
1465 //| old_begin | new | old_end | raw_mem |
1466 //|___________|__________|_________|_________________|
1468 //Now initialize the rest of memory with the last old values
1469 //All new elements correctly constructed, avoid new element destruction
1470 size_type raw_gap = s_before - (elemsbefore + n);
1471 //Now initialize the rest of s_before memory with the
1472 //first of elements after new values
1473 boost::interprocess::uninitialized_move(pos, pos + raw_gap, new_start + elemsbefore + n);
1474 //Update size since we have a contiguous buffer
1475 this->members_.m_size = old_size + s_before;
1476 //All new elements correctly constructed, avoid old element destruction
1477 old_values_destroyer.release();
1478 //Now copy remaining last objects in the old buffer begin
1479 T *to_destroy = boost::interprocess::move(pos + raw_gap, old_finish, old_start);
1480 //Now destroy redundant elements except if they were moved and
1481 //they have trivial destructor after move
1482 size_type n_destroy = old_finish - to_destroy;
1483 if(!value_traits::trivial_dctr_after_move)
1484 this->destroy_n(to_destroy, n_destroy);
1485 this->members_.m_size -= n_destroy;
1488 else{
1489 //Check if we have to do the insertion in two phases
1490 //since maybe s_before is not big enough and
1491 //the buffer was expanded both sides
1493 //Old situation:
1494 // _________________________________________________
1495 //| raw_mem | old_begin + old_end | raw_mem |
1496 //|_________|_____________________|_________________|
1498 //New situation with do_after:
1499 // _________________________________________________
1500 //| old_begin + new + old_end | raw_mem |
1501 //|___________________________________|_____________|
1503 //New without do_after:
1504 // _________________________________________________
1505 //| old_begin + new + old_end | raw_mem |
1506 //|____________________________|____________________|
1508 bool do_after = n > s_before;
1510 //Now we can have two situations: the raw_mem of the
1511 //beginning divides the old_begin, or the new elements:
1512 if (s_before <= elemsbefore) {
1513 //The raw memory divides the old_begin group:
1515 //If we need two phase construction (do_after)
1516 //new group is divided in new = new_beg + new_end groups
1517 //In this phase only new_beg will be inserted
1519 //Old situation:
1520 // _________________________________________________
1521 //| raw_mem | old_begin | old_end | raw_mem |
1522 //|_________|___________|_________|_________________|
1524 //New situation with do_after(1):
1525 //This is not definitive situation, the second phase
1526 //will include
1527 // _________________________________________________
1528 //| old_begin | new_beg | old_end | raw_mem |
1529 //|___________|_________|_________|_________________|
1531 //New situation without do_after:
1532 // _________________________________________________
1533 //| old_begin | new | old_end | raw_mem |
1534 //|___________|_____|_________|_____________________|
1536 //Copy the first part of old_begin to raw_mem
1537 T *start_n = old_start + difference_type(s_before);
1538 boost::interprocess::uninitialized_move(old_start, start_n, new_start);
1539 //The buffer is all constructed until old_end,
1540 //release destroyer and update size
1541 old_values_destroyer.release();
1542 this->members_.m_size = old_size + s_before;
1543 //Now copy the second part of old_begin overwriting himself
1544 T* next = boost::interprocess::move(start_n, pos, old_start);
1545 if(do_after){
1546 //Now copy the new_beg elements
1547 interf.copy_some_and_update(next, s_before, true);
1549 else{
1550 //Now copy the all the new elements
1551 interf.copy_all_to(next);
1552 T* move_start = next + n;
1553 //Now displace old_end elements
1554 T* move_end = boost::interprocess::move(pos, old_finish, move_start);
1555 //Destroy remaining moved elements from old_end except if
1556 //they have trivial destructor after being moved
1557 difference_type n_destroy = s_before - n;
1558 if(!value_traits::trivial_dctr_after_move)
1559 this->destroy_n(move_end, n_destroy);
1560 this->members_.m_size -= n_destroy;
1563 else {
1564 //If we have to expand both sides,
1565 //we will play if the first new values so
1566 //calculate the upper bound of new values
1568 //The raw memory divides the new elements
1570 //If we need two phase construction (do_after)
1571 //new group is divided in new = new_beg + new_end groups
1572 //In this phase only new_beg will be inserted
1574 //Old situation:
1575 // _______________________________________________________
1576 //| raw_mem | old_begin | old_end | raw_mem |
1577 //|_______________|___________|_________|_________________|
1579 //New situation with do_after():
1580 // ____________________________________________________
1581 //| old_begin | new_beg | old_end | raw_mem |
1582 //|___________|_______________|_________|______________|
1584 //New situation without do_after:
1585 // ______________________________________________________
1586 //| old_begin | new | old_end | raw_mem |
1587 //|___________|_____|_________|__________________________|
1589 //First copy whole old_begin and part of new to raw_mem
1590 boost::interprocess::uninitialized_move(old_start, pos, new_start);
1591 this->members_.m_size = elemsbefore;
1593 const size_type mid_n = difference_type(s_before) - elemsbefore;
1594 interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true);
1595 this->members_.m_size = old_size + s_before;
1596 //The buffer is all constructed until old_end,
1597 //release destroyer and update size
1598 old_values_destroyer.release();
1600 if(do_after){
1601 //Copy new_beg part
1602 interf.copy_some_and_update(old_start, s_before - mid_n, true);
1604 else{
1605 //Copy all new elements
1606 interf.copy_all_to(old_start);
1607 T* move_start = old_start + (n-mid_n);
1608 //Displace old_end
1609 T* move_end = boost::interprocess::move(pos, old_finish, move_start);
1610 //Destroy remaining moved elements from old_end except if they
1611 //have trivial destructor after being moved
1612 difference_type n_destroy = s_before - n;
1613 if(!value_traits::trivial_dctr_after_move)
1614 this->destroy_n(move_end, n_destroy);
1615 this->members_.m_size -= n_destroy;
1619 //This is only executed if two phase construction is needed
1620 //This can be executed without exception handling since we
1621 //have to just copy and append in raw memory and
1622 //old_values_destroyer has been released in phase 1.
1623 if(do_after){
1624 //The raw memory divides the new elements
1626 //Old situation:
1627 // ______________________________________________________
1628 //| raw_mem | old_begin | old_end | raw_mem |
1629 //|______________|___________|____________|______________|
1631 //New situation with do_after(1):
1632 // _______________________________________________________
1633 //| old_begin + new_beg | new_end |old_end | raw_mem |
1634 //|__________________________|_________|________|_________|
1636 //New situation with do_after(2):
1637 // ______________________________________________________
1638 //| old_begin + new | old_end |raw |
1639 //|_______________________________________|_________|____|
1641 const size_type n_after = n - s_before;
1642 const difference_type elemsafter = old_size - elemsbefore;
1644 //We can have two situations:
1645 if (elemsafter > difference_type(n_after)){
1646 //The raw_mem from end will divide displaced old_end
1648 //Old situation:
1649 // ______________________________________________________
1650 //| raw_mem | old_begin | old_end | raw_mem |
1651 //|______________|___________|____________|______________|
1653 //New situation with do_after(1):
1654 // _______________________________________________________
1655 //| old_begin + new_beg | new_end |old_end | raw_mem |
1656 //|__________________________|_________|________|_________|
1658 //First copy the part of old_end raw_mem
1659 T* finish_n = old_finish - difference_type(n_after);
1660 boost::interprocess::uninitialized_move(finish_n, old_finish, old_finish);
1661 this->members_.m_size += n_after;
1662 //Displace the rest of old_end to the new position
1663 boost::interprocess::move_backward(pos, finish_n, old_finish);
1664 //Now overwrite with new_end
1665 //The new_end part is [first + (n - n_after), last)
1666 interf.copy_all_to(pos);
1668 else {
1669 //The raw_mem from end will divide new_end part
1671 //Old situation:
1672 // _____________________________________________________________
1673 //| raw_mem | old_begin | old_end | raw_mem |
1674 //|______________|___________|____________|_____________________|
1676 //New situation with do_after(2):
1677 // _____________________________________________________________
1678 //| old_begin + new_beg | new_end |old_end | raw_mem |
1679 //|__________________________|_______________|________|_________|
1681 size_type mid_last_dist = n_after - elemsafter;
1682 //First initialize data in raw memory
1683 //The new_end part is [first + (n - n_after), last)
1684 interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false);
1685 this->members_.m_size += mid_last_dist;
1686 boost::interprocess::uninitialized_move(pos, old_finish, old_finish + mid_last_dist);
1687 this->members_.m_size += n_after - mid_last_dist;
1688 //Now copy the part of new_end over constructed elements
1689 interf.copy_all_to(pos);
1695 template <class InIt>
1696 void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag)
1698 for(;first != last; ++first){
1699 this->insert(pos, boost::interprocess::move(value_type(*first)));
1703 template <class InIt>
1704 void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag)
1706 //Overwrite all elements we can from [first, last)
1707 iterator cur = begin();
1708 for ( ; first != last && cur != end(); ++cur, ++first){
1709 *cur = *first;
1712 if (first == last){
1713 //There are no more elements in the sequence, erase remaining
1714 this->erase(cur, cend());
1716 else{
1717 //There are more elements in the range, insert the remaining ones
1718 this->insert(this->cend(), first, last);
1722 template <class FwdIt>
1723 void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag)
1725 size_type n = std::distance(first, last);
1726 //Check if we have enough memory or try to expand current memory
1727 size_type remaining = this->members_.m_capacity - this->members_.m_size;
1728 bool same_buffer_start;
1729 std::pair<pointer, bool> ret;
1730 size_type real_cap = this->members_.m_capacity;
1732 if (n <= remaining){
1733 same_buffer_start = true;
1735 else{
1736 //There is not enough memory, allocate a new buffer
1737 size_type new_cap = this->next_capacity(n);
1738 ret = this->allocation_command
1739 (allocate_new | expand_fwd | expand_bwd,
1740 this->size() + n, new_cap, real_cap, this->members_.m_start);
1741 same_buffer_start = ret.second && this->members_.m_start == ret.first;
1742 if(same_buffer_start){
1743 this->members_.m_capacity = real_cap;
1747 if(same_buffer_start){
1748 T *start = containers_detail::get_pointer(this->members_.m_start);
1749 if (this->size() >= n){
1750 //There is memory, but there are more old elements than new ones
1751 //Overwrite old elements with new ones
1752 // iG std::copy(first, last, start);
1753 std::copy(first, last, start);
1754 //Destroy remaining old elements
1755 this->destroy_n(start + n, this->members_.m_size - n);
1756 this->members_.m_size = n;
1758 else{
1759 //There is memory, but there are less old elements than new ones
1760 //First overwrite some old elements with new ones
1761 FwdIt mid = first;
1762 std::advance(mid, this->size());
1763 // iG T *end = std::copy(first, mid, start);
1764 T *end = std::copy(first, mid, start);
1765 //Initialize the remaining new elements in the uninitialized memory
1766 // iG std::uninitialized_copy(mid, last, end);
1767 boost::interprocess::uninitialized_copy_or_move(mid, last, end);
1768 this->members_.m_size = n;
1771 else if(!ret.second){
1772 typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap);
1773 // iG std::uninitialized_copy(first, last, containers_detail::get_pointer(ret.first));
1774 boost::interprocess::uninitialized_copy_or_move(first, last, containers_detail::get_pointer(ret.first));
1775 scoped_alloc.release();
1776 //Destroy and deallocate old buffer
1777 if(this->members_.m_start != 0){
1778 this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size);
1779 this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
1781 this->members_.m_start = ret.first;
1782 this->members_.m_size = n;
1783 this->members_.m_capacity = real_cap;
1785 else{
1786 //Backwards expansion
1787 //If anything goes wrong, this object will destroy old objects
1788 T *old_start = containers_detail::get_pointer(this->members_.m_start);
1789 size_type old_size = this->members_.m_size;
1790 typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size);
1791 //If something goes wrong size will be 0
1792 //but holding the whole buffer
1793 this->members_.m_size = 0;
1794 this->members_.m_start = ret.first;
1795 this->members_.m_capacity = real_cap;
1797 //Backup old buffer data
1798 size_type old_offset = old_start - containers_detail::get_pointer(ret.first);
1799 size_type first_count = containers_detail::min_value(n, old_offset);
1801 FwdIt mid = first;
1802 std::advance(mid, first_count);
1803 // iG std::uninitialized_copy(first, mid, containers_detail::get_pointer(ret.first));
1804 boost::interprocess::uninitialized_copy_or_move(first, mid, containers_detail::get_pointer(ret.first));
1806 if(old_offset > n){
1807 //All old elements will be destroyed by "old_values_destroyer"
1808 this->members_.m_size = n;
1810 else{
1811 //We have constructed objects from the new begin until
1812 //the old end so release the rollback destruction
1813 old_values_destroyer.release();
1814 this->members_.m_start = ret.first;
1815 this->members_.m_size = first_count + old_size;
1816 //Now overwrite the old values
1817 size_type second_count = containers_detail::min_value(old_size, n - first_count);
1818 FwdIt mid2 = mid;
1819 std::advance(mid2, second_count);
1820 // iG std::copy(mid, mid2, old_start);
1821 std::copy(mid, mid2, old_start);
1823 //Check if we still have to append elements in the
1824 //uninitialized end
1825 if(second_count == old_size){
1826 // iG std::copy(mid2, last, old_start + old_size);
1827 std::copy(mid2, last, old_start + old_size);
1829 else{
1830 //We have to destroy some old values
1831 this->destroy_n
1832 (old_start + second_count, old_size - second_count);
1833 this->members_.m_size = n;
1835 this->members_.m_size = n;
1840 template <class Integer>
1841 void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_)
1842 { this->assign((size_type) n, (T) val); }
1844 template <class InIt>
1845 void priv_assign_dispatch(InIt first, InIt last, containers_detail::false_)
1847 //Dispatch depending on integer/iterator
1848 typedef typename std::iterator_traits<InIt>::iterator_category ItCat;
1849 this->priv_assign_aux(first, last, ItCat());
1852 template <class Integer>
1853 void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, containers_detail::true_)
1854 { this->insert(pos, (size_type)n, (T)val); }
1856 template <class InIt>
1857 void priv_insert_dispatch(const_iterator pos, InIt first,
1858 InIt last, containers_detail::false_)
1860 //Dispatch depending on integer/iterator
1861 typedef typename std::iterator_traits<InIt>::iterator_category ItCat;
1862 this->priv_range_insert(pos.get_ptr(), first, last, ItCat());
1865 void priv_check_range(size_type n) const
1867 //If n is out of range, throw an out_of_range exception
1868 if (n >= size())
1869 throw std::out_of_range("vector::at");
1872 #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS
1873 public:
1874 unsigned int num_expand_fwd;
1875 unsigned int num_expand_bwd;
1876 unsigned int num_shrink;
1877 unsigned int num_alloc;
1878 void reset_alloc_stats()
1879 { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; }
1880 #endif
1881 /// @endcond
1884 template <class T, class A>
1885 inline bool
1886 operator==(const vector<T, A>& x, const vector<T, A>& y)
1888 //Check first size and each element if needed
1889 return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin());
1892 template <class T, class A>
1893 inline bool
1894 operator!=(const vector<T, A>& x, const vector<T, A>& y)
1896 //Check first size and each element if needed
1897 return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin());
1900 template <class T, class A>
1901 inline bool
1902 operator<(const vector<T, A>& x, const vector<T, A>& y)
1904 return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
1907 template <class T, class A>
1908 inline void swap(vector<T, A>& x, vector<T, A>& y)
1909 { x.swap(y); }
1913 /// @cond
1915 namespace boost {
1916 namespace interprocess {
1918 //!has_trivial_destructor_after_move<> == true_type
1919 //!specialization for optimizations
1920 template <class T, class A>
1921 struct has_trivial_destructor_after_move<boost::interprocess_container::vector<T, A> >
1923 static const bool value = has_trivial_destructor<A>::value;
1928 /// @endcond
1930 #include <boost/interprocess/containers/container/detail/config_end.hpp>
1932 #endif // #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP