fix doc example typo
[boost.git] / boost / interprocess / containers / container / stable_vector.hpp
blobb587c2a7f19e288b6fed76e02c13c28c141a8db7
1 /* Stable vector.
3 * Copyright 2008 Joaquin M Lopez Munoz.
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 */
9 #ifndef STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66
10 #define STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66
12 #include <algorithm>
13 #include <stdexcept>
14 #include <boost/mpl/bool.hpp>
15 #include <boost/mpl/not.hpp>
16 #include <boost/noncopyable.hpp>
17 #include <boost/type_traits/is_integral.hpp>
18 #include <boost/interprocess/containers/container/detail/version_type.hpp>
19 #include <boost/interprocess/containers/container/detail/multiallocation_chain.hpp>
20 #include <boost/interprocess/containers/container/detail/utilities.hpp>
21 #include <boost/interprocess/containers/container/detail/algorithms.hpp>
22 #include <boost/pointer_to_other.hpp>
23 #include <boost/get_pointer.hpp>
25 #define STABLE_VECTOR_USE_CONTAINERS_VECTOR
27 #if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR)
28 #include <boost/interprocess/containers/container/vector.hpp>
29 #else
30 #include <vector>
31 #endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR
33 //#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING
35 #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
36 #include <boost/assert.hpp>
37 #endif
39 #ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
40 namespace boost {
41 namespace interprocess {
42 #else
43 namespace boost {
44 namespace interprocess_container {
45 #endif
47 /// @cond
49 namespace stable_vector_detail{
51 template<class SmartPtr>
52 struct smart_ptr_type
54 typedef typename SmartPtr::value_type value_type;
55 typedef value_type *pointer;
56 static pointer get (const SmartPtr &smartptr)
57 { return smartptr.get();}
60 template<class T>
61 struct smart_ptr_type<T*>
63 typedef T value_type;
64 typedef value_type *pointer;
65 static pointer get (pointer ptr)
66 { return ptr;}
69 template<class Ptr>
70 inline typename smart_ptr_type<Ptr>::pointer get_pointer(const Ptr &ptr)
71 { return smart_ptr_type<Ptr>::get(ptr); }
73 template <class C>
74 class clear_on_destroy
76 public:
77 clear_on_destroy(C &c)
78 : c_(c), do_clear_(true)
81 void release()
82 { do_clear_ = false; }
84 ~clear_on_destroy()
86 if(do_clear_){
87 c_.clear();
88 c_.clear_pool();
92 private:
93 C &c_;
94 bool do_clear_;
97 template <class T, class Difference = std::ptrdiff_t>
98 class constant_iterator
99 : public std::iterator
100 <std::random_access_iterator_tag, T, Difference, const T*, const T &>
102 typedef constant_iterator<T, Difference> this_type;
104 public:
105 explicit constant_iterator(const T &ref, Difference range_size)
106 : m_ptr(&ref), m_num(range_size){}
108 //Constructors
109 constant_iterator()
110 : m_ptr(0), m_num(0){}
112 constant_iterator& operator++()
113 { increment(); return *this; }
115 constant_iterator operator++(int)
117 constant_iterator result (*this);
118 increment();
119 return result;
122 friend bool operator== (const constant_iterator& i, const constant_iterator& i2)
123 { return i.equal(i2); }
125 friend bool operator!= (const constant_iterator& i, const constant_iterator& i2)
126 { return !(i == i2); }
128 friend bool operator< (const constant_iterator& i, const constant_iterator& i2)
129 { return i.less(i2); }
131 friend bool operator> (const constant_iterator& i, const constant_iterator& i2)
132 { return i2 < i; }
134 friend bool operator<= (const constant_iterator& i, const constant_iterator& i2)
135 { return !(i > i2); }
137 friend bool operator>= (const constant_iterator& i, const constant_iterator& i2)
138 { return !(i < i2); }
140 friend Difference operator- (const constant_iterator& i, const constant_iterator& i2)
141 { return i2.distance_to(i); }
143 //Arithmetic
144 constant_iterator& operator+=(Difference off)
145 { this->advance(off); return *this; }
147 constant_iterator operator+(Difference off) const
149 constant_iterator other(*this);
150 other.advance(off);
151 return other;
154 friend constant_iterator operator+(Difference off, const constant_iterator& right)
155 { return right + off; }
157 constant_iterator& operator-=(Difference off)
158 { this->advance(-off); return *this; }
160 constant_iterator operator-(Difference off) const
161 { return *this + (-off); }
163 const T& operator*() const
164 { return dereference(); }
166 const T* operator->() const
167 { return &(dereference()); }
169 private:
170 const T * m_ptr;
171 Difference m_num;
173 void increment()
174 { --m_num; }
176 void decrement()
177 { ++m_num; }
179 bool equal(const this_type &other) const
180 { return m_num == other.m_num; }
182 bool less(const this_type &other) const
183 { return other.m_num < m_num; }
185 const T & dereference() const
186 { return *m_ptr; }
188 void advance(Difference n)
189 { m_num -= n; }
191 Difference distance_to(const this_type &other)const
192 { return m_num - other.m_num; }
195 template<class VoidPtr>
196 struct node_type_base
198 node_type_base(VoidPtr p)
199 : up(p)
200 {}*/
201 node_type_base()
203 void set_pointer(VoidPtr p)
204 { up = p; }
206 VoidPtr up;
209 template<typename VoidPointer, typename T>
210 struct node_type
211 : public node_type_base<VoidPointer>
213 #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
215 node_type()
216 : value()
219 #define BOOST_PP_LOCAL_MACRO(n) \
220 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
221 node_type(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
222 : value(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \
223 {} \
225 #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
226 #include BOOST_PP_LOCAL_ITERATE()
228 #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
230 node_type()
231 : value()
234 template<class ...Args>
235 node_type(Args &&...args)
236 : value(boost::interprocess::forward<Args>(args)...)
238 #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
240 void set_pointer(VoidPointer p)
241 { node_type_base<VoidPointer>::set_pointer(p); }
243 T value;
246 template<typename T, typename Value, typename Pointer>
247 class iterator
248 : public std::iterator< std::random_access_iterator_tag
249 , const typename std::iterator_traits<Pointer>::value_type
250 , typename std::iterator_traits<Pointer>::difference_type
251 , Pointer
252 , Value &>
255 typedef typename boost::pointer_to_other
256 <Pointer, void>::type void_ptr;
257 typedef node_type<void_ptr, T> node_type_t;
258 typedef typename boost::pointer_to_other
259 <void_ptr, node_type_t>::type node_type_ptr_t;
260 typedef typename boost::pointer_to_other
261 <void_ptr, void_ptr>::type void_ptr_ptr;
263 friend class iterator<T, const T, typename boost::pointer_to_other<Pointer, T>::type>;
265 public:
266 typedef std::random_access_iterator_tag iterator_category;
267 typedef Value value_type;
268 typedef typename std::iterator_traits
269 <Pointer>::difference_type difference_type;
270 typedef Pointer pointer;
271 typedef Value & reference;
273 iterator()
276 explicit iterator(node_type_ptr_t pn)
277 : pn(pn)
280 iterator(const iterator<T, T, typename boost::pointer_to_other<Pointer, T>::type >& x)
281 : pn(x.pn)
284 private:
285 static node_type_ptr_t node_ptr_cast(void_ptr p)
287 using boost::get_pointer;
288 return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p)));
291 static void_ptr_ptr void_ptr_ptr_cast(void_ptr p)
293 using boost::get_pointer;
294 return void_ptr_ptr(static_cast<void_ptr*>(stable_vector_detail::get_pointer(p)));
297 Value& dereference() const
298 { return pn->value; }
299 bool equal(const iterator& x) const
300 { return pn==x.pn; }
301 void increment()
302 { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); }
303 void decrement()
304 { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); }
305 void advance(std::ptrdiff_t n)
306 { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); }
307 std::ptrdiff_t distance_to(const iterator& x)const
308 { return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); }
310 public:
311 //Pointer like operators
312 reference operator*() const { return this->dereference(); }
313 pointer operator->() const { return pointer(&this->dereference()); }
315 //Increment / Decrement
316 iterator& operator++()
317 { this->increment(); return *this; }
319 iterator operator++(int)
320 { iterator tmp(*this); ++*this; return iterator(tmp); }
322 iterator& operator--()
323 { this->decrement(); return *this; }
325 iterator operator--(int)
326 { iterator tmp(*this); --*this; return iterator(tmp); }
328 reference operator[](difference_type off) const
330 iterator tmp(*this);
331 tmp += off;
332 return *tmp;
335 iterator& operator+=(difference_type off)
337 pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off));
338 return *this;
341 iterator operator+(difference_type off) const
343 iterator tmp(*this);
344 tmp += off;
345 return tmp;
348 friend iterator operator+(difference_type off, const iterator& right)
350 iterator tmp(right);
351 tmp += off;
352 return tmp;
355 iterator& operator-=(difference_type off)
356 { *this += -off; return *this; }
358 iterator operator-(difference_type off) const
360 iterator tmp(*this);
361 tmp -= off;
362 return tmp;
365 difference_type operator-(const iterator& right) const
367 void_ptr_ptr p1 = void_ptr_ptr_cast(this->pn->up);
368 void_ptr_ptr p2 = void_ptr_ptr_cast(right.pn->up);
369 return p1 - p2;
372 //Comparison operators
373 bool operator== (const iterator& r) const
374 { return pn == r.pn; }
376 bool operator!= (const iterator& r) const
377 { return pn != r.pn; }
379 bool operator< (const iterator& r) const
380 { return void_ptr_ptr_cast(pn->up) < void_ptr_ptr_cast(r.pn->up); }
382 bool operator<= (const iterator& r) const
383 { return void_ptr_ptr_cast(pn->up) <= void_ptr_ptr_cast(r.pn->up); }
385 bool operator> (const iterator& r) const
386 { return void_ptr_ptr_cast(pn->up) > void_ptr_ptr_cast(r.pn->up); }
388 bool operator>= (const iterator& r) const
389 { return void_ptr_ptr_cast(pn->up) >= void_ptr_ptr_cast(r.pn->up); }
391 node_type_ptr_t pn;
395 class node_access
397 public:
398 template<typename T, typename Value, typename VoidPointer>
399 static typename iterator<T, Value, VoidPointer>::node_type_t* get(const iterator<T,Value,VoidPointer>& it)
401 return stable_vector_detail::get_pointer(it.pn);
406 template<class Allocator, unsigned int Version>
407 struct select_multiallocation_chain
409 typedef typename Allocator::multiallocation_chain type;
412 template<class Allocator>
413 struct select_multiallocation_chain<Allocator, 1>
415 typedef typename Allocator::template
416 rebind<void>::other::pointer void_ptr;
417 typedef containers_detail::basic_multiallocation_cached_slist<void_ptr> multialloc_cached;
418 typedef containers_detail::basic_multiallocation_cached_counted_slist
419 <multialloc_cached> multialloc_cached_counted;
420 typedef boost::interprocess_container::containers_detail::transform_multiallocation_chain
421 <multialloc_cached_counted, typename Allocator::value_type> type;
424 } //namespace stable_vector_detail
426 #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
428 #define STABLE_VECTOR_CHECK_INVARIANT \
429 invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \
430 BOOST_JOIN(check_invariant_,__LINE__).touch();
431 #else
433 #define STABLE_VECTOR_CHECK_INVARIANT
435 #endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
437 /// @endcond
439 template<typename T,typename Allocator=std::allocator<T> >
440 class stable_vector
442 typedef typename Allocator::template
443 rebind<void>::other::pointer void_ptr;
444 typedef typename Allocator::template
445 rebind<void_ptr>::other::pointer void_ptr_ptr;
446 typedef stable_vector_detail::node_type
447 <void_ptr, T> node_type_t;
448 typedef typename Allocator::template
449 rebind<node_type_t>::other::pointer node_type_ptr_t;
450 typedef stable_vector_detail::node_type_base
451 <void_ptr> node_type_base_t;
452 typedef typename Allocator::template
453 rebind<node_type_base_t>::other::pointer node_type_base_ptr_t;
454 typedef
455 #if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR)
456 ::boost::interprocess_container::
457 #else
458 ::std::
459 #endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR
460 vector<void_ptr,
461 typename Allocator::
462 template rebind<void_ptr>::other
463 > impl_type;
464 typedef typename impl_type::iterator impl_iterator;
465 typedef typename impl_type::const_iterator const_impl_iterator;
467 typedef ::boost::interprocess_container::containers_detail::
468 integral_constant<unsigned, 1> allocator_v1;
469 typedef ::boost::interprocess_container::containers_detail::
470 integral_constant<unsigned, 2> allocator_v2;
471 typedef ::boost::interprocess_container::containers_detail::integral_constant
472 <unsigned, boost::interprocess_container::containers_detail::
473 version<Allocator>::value> alloc_version;
474 typedef typename Allocator::
475 template rebind<node_type_t>::other node_allocator_type;
477 node_type_ptr_t allocate_one()
478 { return this->allocate_one(alloc_version()); }
480 node_type_ptr_t allocate_one(allocator_v1)
481 { return get_al().allocate(1); }
483 node_type_ptr_t allocate_one(allocator_v2)
484 { return get_al().allocate_one(); }
486 void deallocate_one(node_type_ptr_t p)
487 { return this->deallocate_one(p, alloc_version()); }
489 void deallocate_one(node_type_ptr_t p, allocator_v1)
490 { get_al().deallocate(p, 1); }
492 void deallocate_one(node_type_ptr_t p, allocator_v2)
493 { get_al().deallocate_one(p); }
495 friend class stable_vector_detail::clear_on_destroy<stable_vector>;
497 public:
498 // types:
500 typedef typename Allocator::reference reference;
501 typedef typename Allocator::const_reference const_reference;
502 typedef typename Allocator::pointer pointer;
503 typedef typename Allocator::const_pointer const_pointer;
504 typedef stable_vector_detail::iterator
505 <T,T, pointer> iterator;
506 typedef stable_vector_detail::iterator
507 <T,const T, const_pointer> const_iterator;
508 typedef typename impl_type::size_type size_type;
509 typedef typename iterator::difference_type difference_type;
510 typedef T value_type;
511 typedef Allocator allocator_type;
512 typedef std::reverse_iterator<iterator> reverse_iterator;
513 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
515 private:
516 static const size_type ExtraPointers = 3;
517 typedef typename stable_vector_detail::
518 select_multiallocation_chain
519 < node_allocator_type
520 , alloc_version::value
521 >::type multiallocation_chain;
523 public:
524 BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(stable_vector)
526 // construct/copy/destroy:
527 explicit stable_vector(const Allocator& al=Allocator())
528 : internal_data(al),impl(al)
530 STABLE_VECTOR_CHECK_INVARIANT;
533 stable_vector(size_type n,const T& t=T(),const Allocator& al=Allocator())
534 : internal_data(al),impl(al)
536 stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
537 this->insert(this->cbegin(), n, t);
538 STABLE_VECTOR_CHECK_INVARIANT;
539 cod.release();
542 template <class InputIterator>
543 stable_vector(InputIterator first,InputIterator last,const Allocator& al=Allocator())
544 : internal_data(al),impl(al)
546 stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
547 this->insert(this->cbegin(), first, last);
548 STABLE_VECTOR_CHECK_INVARIANT;
549 cod.release();
552 stable_vector(const stable_vector& x)
553 : internal_data(x.get_al()),impl(x.get_al())
555 stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
556 this->insert(this->cbegin(), x.begin(), x.end());
557 STABLE_VECTOR_CHECK_INVARIANT;
558 cod.release();
561 stable_vector(BOOST_INTERPROCESS_RV_REF(stable_vector) x)
562 : internal_data(x.get_al()),impl(x.get_al())
563 { this->swap(x); }
565 ~stable_vector()
567 this->clear();
568 clear_pool();
571 stable_vector& operator=(const stable_vector &x)
573 STABLE_VECTOR_CHECK_INVARIANT;
574 if (this != &x) {
575 this->assign(x.begin(), x.end());
577 return *this;
580 stable_vector& operator=(BOOST_INTERPROCESS_RV_REF(stable_vector) x)
582 if (&x != this){
583 this->swap(x);
584 x.clear();
586 return *this;
589 template<typename InputIterator>
590 void assign(InputIterator first,InputIterator last)
592 assign_dispatch(first, last, boost::is_integral<InputIterator>());
595 void assign(size_type n,const T& t)
597 typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
598 return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_());
601 allocator_type get_allocator()const {return get_al();}
603 // iterators:
605 iterator begin()
606 { return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; }
608 const_iterator begin()const
609 { return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; }
611 iterator end() {return iterator(get_end_node());}
612 const_iterator end()const {return const_iterator(get_end_node());}
614 reverse_iterator rbegin() {return reverse_iterator(this->end());}
615 const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());}
616 reverse_iterator rend() {return reverse_iterator(this->begin());}
617 const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());}
619 const_iterator cbegin()const {return this->begin();}
620 const_iterator cend()const {return this->end();}
621 const_reverse_iterator crbegin()const{return this->rbegin();}
622 const_reverse_iterator crend()const {return this->rend();}
624 // capacity:
625 size_type size() const
626 { return impl.empty() ? 0 : (impl.size() - ExtraPointers); }
628 size_type max_size() const
629 { return impl.max_size() - ExtraPointers; }
631 size_type capacity() const
633 if(!impl.capacity()){
634 return 0;
636 else{
637 const size_type num_nodes = this->impl.size() + this->internal_data.pool_size;
638 const size_type num_buck = this->impl.capacity();
639 return (num_nodes < num_buck) ? num_nodes : num_buck;
643 bool empty() const
644 { return impl.empty() || impl.size() == ExtraPointers; }
646 void resize(size_type n, const T& t)
648 STABLE_VECTOR_CHECK_INVARIANT;
649 if(n > size())
650 this->insert(this->cend(), n - this->size(), t);
651 else if(n < this->size())
652 this->erase(this->cbegin() + n, this->cend());
655 void resize(size_type n)
657 typedef default_construct_iterator<value_type, difference_type> default_iterator;
658 STABLE_VECTOR_CHECK_INVARIANT;
659 if(n > size())
660 this->insert(this->cend(), default_iterator(n - this->size()), default_iterator());
661 else if(n < this->size())
662 this->erase(this->cbegin() + n, this->cend());
665 void reserve(size_type n)
667 STABLE_VECTOR_CHECK_INVARIANT;
668 if(n > this->max_size())
669 throw std::bad_alloc();
671 size_type size = this->size();
672 size_type old_capacity = this->capacity();
673 if(n > old_capacity){
674 this->initialize_end_node(n);
675 const void * old_ptr = &impl[0];
676 impl.reserve(n + ExtraPointers);
677 bool realloced = &impl[0] != old_ptr;
678 //Fix the pointers for the newly allocated buffer
679 if(realloced){
680 this->align_nodes(impl.begin(), impl.begin()+size+1);
682 //Now fill pool if data is not enough
683 if((n - size) > this->internal_data.pool_size){
684 this->add_to_pool((n - size) - this->internal_data.pool_size);
689 void clear_pool(allocator_v1)
691 if(!impl.empty() && impl.back()){
692 void_ptr &p1 = *(impl.end()-2);
693 void_ptr &p2 = impl.back();
695 multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
696 while(!holder.empty()){
697 node_type_ptr_t n = holder.front();
698 holder.pop_front();
699 this->deallocate_one(n);
701 p1 = p2 = 0;
702 this->internal_data.pool_size = 0;
706 void clear_pool(allocator_v2)
709 if(!impl.empty() && impl.back()){
710 void_ptr &p1 = *(impl.end()-2);
711 void_ptr &p2 = impl.back();
712 multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
713 get_al().deallocate_individual(boost::interprocess::move(holder));
714 p1 = p2 = 0;
715 this->internal_data.pool_size = 0;
719 void clear_pool()
721 this->clear_pool(alloc_version());
724 void add_to_pool(size_type n)
726 this->add_to_pool(n, alloc_version());
729 void add_to_pool(size_type n, allocator_v1)
731 size_type remaining = n;
732 while(remaining--){
733 this->put_in_pool(this->allocate_one());
737 void add_to_pool(size_type n, allocator_v2)
739 void_ptr &p1 = *(impl.end()-2);
740 void_ptr &p2 = impl.back();
741 multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
742 BOOST_STATIC_ASSERT((boost::interprocess::is_movable<multiallocation_chain>::value == true));
743 multiallocation_chain m (get_al().allocate_individual(n));
744 holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n);
745 this->internal_data.pool_size += n;
746 std::pair<void_ptr, void_ptr> data(holder.extract_data());
747 p1 = data.first;
748 p2 = data.second;
751 void put_in_pool(node_type_ptr_t p)
753 void_ptr &p1 = *(impl.end()-2);
754 void_ptr &p2 = impl.back();
755 multiallocation_chain holder(p1, p2, internal_data.pool_size);
756 holder.push_front(p);
757 ++this->internal_data.pool_size;
758 std::pair<void_ptr, void_ptr> ret(holder.extract_data());
759 p1 = ret.first;
760 p2 = ret.second;
763 node_type_ptr_t get_from_pool()
765 if(!impl.back()){
766 return node_type_ptr_t(0);
768 else{
769 void_ptr &p1 = *(impl.end()-2);
770 void_ptr &p2 = impl.back();
771 multiallocation_chain holder(p1, p2, internal_data.pool_size);
772 node_type_ptr_t ret = holder.front();
773 holder.pop_front();
774 std::pair<void_ptr, void_ptr> data(holder.extract_data());
775 p1 = data.first;
776 p2 = data.second;
777 --this->internal_data.pool_size;
778 return ret;
782 // element access:
784 reference operator[](size_type n){return value(impl[n]);}
785 const_reference operator[](size_type n)const{return value(impl[n]);}
787 const_reference at(size_type n)const
789 if(n>=size())
790 throw std::out_of_range("invalid subscript at stable_vector::at");
791 return operator[](n);
794 reference at(size_type n)
796 if(n>=size())
797 throw std::out_of_range("invalid subscript at stable_vector::at");
798 return operator[](n);
801 reference front()
802 { return value(impl.front()); }
804 const_reference front()const
805 { return value(impl.front()); }
807 reference back()
808 { return value(*(&impl.back() - ExtraPointers)); }
810 const_reference back()const
811 { return value(*(&impl.back() - ExtraPointers)); }
813 // modifiers:
815 void push_back(const T& t)
816 { this->insert(end(), t); }
818 void push_back(BOOST_INTERPROCESS_RV_REF(T) t)
819 { this->insert(end(), boost::interprocess::move(t)); }
821 void pop_back()
822 { this->erase(this->end()-1); }
824 iterator insert(const_iterator position, const T& t)
826 typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
827 return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag());
830 iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x)
832 typedef repeat_iterator<T, difference_type> repeat_it;
833 typedef boost::interprocess::move_iterator<repeat_it> repeat_move_it;
834 //Just call more general insert(pos, size, value) and return iterator
835 size_type pos_n = position - cbegin();
836 this->insert(position
837 ,repeat_move_it(repeat_it(x, 1))
838 ,repeat_move_it(repeat_it()));
839 return iterator(this->begin() + pos_n);
842 void insert(const_iterator position, size_type n, const T& t)
844 STABLE_VECTOR_CHECK_INVARIANT;
845 this->insert_not_iter(position, n, t);
848 template <class InputIterator>
849 void insert(const_iterator position,InputIterator first, InputIterator last)
851 STABLE_VECTOR_CHECK_INVARIANT;
852 this->insert_iter(position,first,last,
853 boost::mpl::not_<boost::is_integral<InputIterator> >());
856 #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
858 //! <b>Effects</b>: Inserts an object of type T constructed with
859 //! std::forward<Args>(args)... in the end of the vector.
861 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
863 //! <b>Complexity</b>: Amortized constant time.
864 template<class ...Args>
865 void emplace_back(Args &&...args)
867 typedef emplace_functor<node_type_t, Args...> EmplaceFunctor;
868 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator;
869 EmplaceFunctor ef(boost::interprocess::forward<Args>(args)...);
870 this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator());
873 //! <b>Requires</b>: position must be a valid iterator of *this.
875 //! <b>Effects</b>: Inserts an object of type T constructed with
876 //! std::forward<Args>(args)... before position
878 //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
880 //! <b>Complexity</b>: If position is end(), amortized constant time
881 //! Linear time otherwise.
882 template<class ...Args>
883 iterator emplace(const_iterator position, Args && ...args)
885 //Just call more general insert(pos, size, value) and return iterator
886 size_type pos_n = position - cbegin();
887 typedef emplace_functor<node_type_t, Args...> EmplaceFunctor;
888 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator;
889 EmplaceFunctor ef(boost::interprocess::forward<Args>(args)...);
890 this->insert(position, EmplaceIterator(ef), EmplaceIterator());
891 return iterator(this->begin() + pos_n);
894 #else
896 void emplace_back()
898 typedef emplace_functor<node_type_t> EmplaceFunctor;
899 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator;
900 EmplaceFunctor ef;
901 this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator());
904 iterator emplace(const_iterator position)
906 typedef emplace_functor<node_type_t> EmplaceFunctor;
907 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator;
908 EmplaceFunctor ef;
909 size_type pos_n = position - this->cbegin();
910 this->insert(position, EmplaceIterator(ef), EmplaceIterator());
911 return iterator(this->begin() + pos_n);
914 #define BOOST_PP_LOCAL_MACRO(n) \
915 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
916 void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
918 typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \
919 <node_type_t, BOOST_PP_ENUM_PARAMS(n, P)> EmplaceFunctor; \
920 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator; \
921 EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
922 this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); \
925 template<BOOST_PP_ENUM_PARAMS(n, class P)> \
926 iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
928 typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \
929 <node_type_t, BOOST_PP_ENUM_PARAMS(n, P)> EmplaceFunctor; \
930 typedef emplace_iterator<node_type_t, EmplaceFunctor> EmplaceIterator; \
931 EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
932 size_type pos_n = pos - this->cbegin(); \
933 this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \
934 return iterator(this->begin() + pos_n); \
937 #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
938 #include BOOST_PP_LOCAL_ITERATE()
940 #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
942 iterator erase(const_iterator position)
944 STABLE_VECTOR_CHECK_INVARIANT;
945 difference_type d=position-this->cbegin();
946 impl_iterator it=impl.begin()+d;
947 this->delete_node(*it);
948 impl.erase(it);
949 this->align_nodes(impl.begin()+d,get_last_align());
950 return this->begin()+d;
953 iterator erase(const_iterator first, const_iterator last)
954 { return priv_erase(first, last, alloc_version()); }
956 void swap(stable_vector & x)
958 STABLE_VECTOR_CHECK_INVARIANT;
959 this->swap_impl(*this,x);
962 void clear()
963 { this->erase(this->cbegin(),this->cend()); }
965 /// @cond
966 private:
968 void insert_iter_prolog(size_type n, difference_type d)
970 initialize_end_node(n);
971 const void* old_ptr = &impl[0];
972 //size_type old_capacity = capacity();
973 //size_type old_size = size();
974 impl.insert(impl.begin()+d, n, 0);
975 bool realloced = &impl[0] != old_ptr;
976 //Fix the pointers for the newly allocated buffer
977 if(realloced){
978 align_nodes(impl.begin(), impl.begin()+d);
982 template<typename InputIterator>
983 void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_)
985 STABLE_VECTOR_CHECK_INVARIANT;
986 iterator first1 = this->begin();
987 iterator last1 = this->end();
988 for ( ; first1 != last1 && first != last; ++first1, ++first)
989 *first1 = *first;
990 if (first == last){
991 this->erase(first1, last1);
993 else{
994 this->insert(last1, first, last);
998 template<typename Integer>
999 void assign_dispatch(Integer n, Integer t, boost::mpl::true_)
1001 typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
1002 this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_());
1005 iterator priv_erase(const_iterator first, const_iterator last, allocator_v1)
1007 STABLE_VECTOR_CHECK_INVARIANT;
1008 difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin();
1009 if(d1 != d2){
1010 impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2);
1011 for(impl_iterator it = it1; it != it2; ++it)
1012 this->delete_node(*it);
1013 impl.erase(it1, it2);
1014 this->align_nodes(impl.begin() + d1, get_last_align());
1016 return iterator(this->begin() + d1);
1019 impl_iterator get_last_align()
1021 return impl.end() - (ExtraPointers - 1);
1024 const_impl_iterator get_last_align() const
1026 return impl.cend() - (ExtraPointers - 1);
1029 template<class AllocatorVersion>
1030 iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion,
1031 typename boost::interprocess_container::containers_detail::enable_if_c
1032 <boost::interprocess_container::containers_detail::is_same<AllocatorVersion, allocator_v2>
1033 ::value>::type * = 0)
1035 STABLE_VECTOR_CHECK_INVARIANT;
1036 return priv_erase(first, last, allocator_v1());
1039 static node_type_ptr_t node_ptr_cast(void_ptr p)
1041 using boost::get_pointer;
1042 return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p)));
1045 static node_type_base_ptr_t node_base_ptr_cast(void_ptr p)
1047 using boost::get_pointer;
1048 return node_type_base_ptr_t(static_cast<node_type_base_t*>(stable_vector_detail::get_pointer(p)));
1051 static value_type& value(void_ptr p)
1053 return node_ptr_cast(p)->value;
1056 void initialize_end_node(size_type impl_capacity = 0)
1058 if(impl.empty()){
1059 impl.reserve(impl_capacity + ExtraPointers);
1060 impl.resize (ExtraPointers, void_ptr(0));
1061 impl[0] = &this->internal_data.end_node;
1062 this->internal_data.end_node.up = &impl[0];
1066 void readjust_end_node()
1068 if(!this->impl.empty()){
1069 void_ptr &end_node_ref = *(this->get_last_align()-1);
1070 end_node_ref = this->get_end_node();
1071 this->internal_data.end_node.up = &end_node_ref;
1073 else{
1074 this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up);
1078 node_type_ptr_t get_end_node() const
1080 const node_type_base_t* cp = &this->internal_data.end_node;
1081 node_type_base_t* p = const_cast<node_type_base_t*>(cp);
1082 return node_ptr_cast(p);
1085 template<class Iter>
1086 void_ptr new_node(void_ptr up, Iter it)
1088 node_type_ptr_t p = this->allocate_one();
1089 try{
1090 boost::interprocess_container::construct_in_place(&*p, it);
1091 p->set_pointer(up);
1093 catch(...){
1094 this->deallocate_one(p);
1095 throw;
1097 return p;
1100 void delete_node(void_ptr p)
1102 node_type_ptr_t n(node_ptr_cast(p));
1103 n->~node_type_t();
1104 this->put_in_pool(n);
1107 static void align_nodes(impl_iterator first,impl_iterator last)
1109 while(first!=last){
1110 node_ptr_cast(*first)->up = void_ptr(&*first);
1111 ++first;
1115 void insert_not_iter(const_iterator position, size_type n, const T& t)
1117 typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
1118 this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag());
1121 template <class InputIterator>
1122 void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_)
1124 typedef typename std::iterator_traits<InputIterator>::iterator_category category;
1125 this->insert_iter(position, first, last, category());
1128 template <class InputIterator>
1129 void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag)
1131 for(; first!=last; ++first){
1132 this->insert(position, *first);
1136 template <class InputIterator>
1137 iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag)
1139 size_type n = (size_type)std::distance(first,last);
1140 difference_type d = position-this->cbegin();
1141 if(n){
1142 this->insert_iter_prolog(n, d);
1143 const impl_iterator it(impl.begin() + d);
1144 this->insert_iter_fwd(it, first, last, n);
1145 //Fix the pointers for the newly allocated buffer
1146 this->align_nodes(it + n, get_last_align());
1148 return this->begin() + d;
1151 template <class FwdIterator>
1152 void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1)
1154 size_type i=0;
1155 try{
1156 while(first!=last){
1157 *(it + i) = this->new_node(void_ptr((void*)(&*(it + i))), first);
1158 ++first;
1159 ++i;
1162 catch(...){
1163 impl.erase(it + i, it + n);
1164 this->align_nodes(it + i, get_last_align());
1165 throw;
1169 template <class FwdIterator>
1170 void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2)
1172 multiallocation_chain mem(get_al().allocate_individual(n));
1174 size_type i = 0;
1175 node_type_ptr_t p = 0;
1176 try{
1177 while(first != last){
1178 p = mem.front();
1179 mem.pop_front();
1180 //This can throw
1181 boost::interprocess_container::construct_in_place(&*p, first);
1182 p->set_pointer(void_ptr((void*)(&*(it + i))));
1183 ++first;
1184 *(it + i) = p;
1185 ++i;
1188 catch(...){
1189 get_al().deallocate_one(p);
1190 get_al().deallocate_many(boost::interprocess::move(mem));
1191 impl.erase(it+i, it+n);
1192 this->align_nodes(it+i,get_last_align());
1193 throw;
1197 template <class FwdIterator>
1198 void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n)
1200 size_type i = 0;
1201 node_type_ptr_t p = 0;
1202 try{
1203 while(first != last){
1204 p = get_from_pool();
1205 if(!p){
1206 insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version());
1207 break;
1209 //This can throw
1210 boost::interprocess_container::construct_in_place(&*p, first);
1211 p->set_pointer(void_ptr(&*(it+i)));
1212 ++first;
1213 *(it+i)=p;
1214 ++i;
1217 catch(...){
1218 put_in_pool(p);
1219 impl.erase(it+i,it+n);
1220 this->align_nodes(it+i,get_last_align());
1221 throw;
1225 template <class InputIterator>
1226 void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::false_)
1228 this->insert_not_iter(position,first,last);
1231 static void swap_impl(stable_vector& x,stable_vector& y)
1233 using std::swap;
1234 swap(x.get_al(),y.get_al());
1235 swap(x.impl,y.impl);
1236 swap(x.internal_data.pool_size, y.internal_data.pool_size);
1237 x.readjust_end_node();
1238 y.readjust_end_node();
1241 #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
1242 bool invariant()const
1244 if(impl.empty())
1245 return !capacity() && !size();
1246 if(get_end_node() != *(impl.end() - ExtraPointers)){
1247 return false;
1249 for(const_impl_iterator it=impl.begin(),it_end=get_last_align();it!=it_end;++it){
1250 if(node_ptr_cast(*it)->up != &*it)
1251 return false;
1253 size_type n = capacity()-size();
1254 const void_ptr &pool_head = impl.back();
1255 size_type num_pool = 0;
1256 node_type_ptr_t p = node_ptr_cast(pool_head);
1257 while(p){
1258 ++num_pool;
1259 p = p->up;
1261 return n >= num_pool;
1264 class invariant_checker:private boost::noncopyable
1266 const stable_vector* p;
1267 public:
1268 invariant_checker(const stable_vector& v):p(&v){}
1269 ~invariant_checker(){BOOST_ASSERT(p->invariant());}
1270 void touch(){}
1272 #endif
1274 struct ebo_holder
1275 : node_allocator_type
1277 ebo_holder(const allocator_type &a)
1278 : node_allocator_type(a), pool_size(0), end_node()
1280 end_node.set_pointer(void_ptr(&end_node.up));
1282 size_type pool_size;
1283 node_type_base_t end_node;
1284 } internal_data;
1286 node_allocator_type &get_al() { return internal_data; }
1287 const node_allocator_type &get_al() const { return internal_data; }
1289 impl_type impl;
1290 /// @endcond
1293 template <typename T,typename Allocator>
1294 bool operator==(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1296 return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin());
1299 template <typename T,typename Allocator>
1300 bool operator< (const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1302 return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end());
1305 template <typename T,typename Allocator>
1306 bool operator!=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1308 return !(x==y);
1311 template <typename T,typename Allocator>
1312 bool operator> (const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1314 return y<x;
1317 template <typename T,typename Allocator>
1318 bool operator>=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1320 return !(x<y);
1323 template <typename T,typename Allocator>
1324 bool operator<=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
1326 return !(x>y);
1329 // specialized algorithms:
1331 template <typename T, typename Allocator>
1332 void swap(stable_vector<T,Allocator>& x,stable_vector<T,Allocator>& y)
1334 x.swap(y);
1337 /// @cond
1339 #undef STABLE_VECTOR_CHECK_INVARIANT
1341 /// @endcond
1345 #endif