You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
1701 lines
56 KiB
1701 lines
56 KiB
////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// (C) Copyright Ion Gaztanaga 2008-2011. Distributed under the Boost |
|
// Software License, Version 1.0. (See accompanying file |
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
// See http://www.boost.org/libs/container for documentation. |
|
// |
|
////////////////////////////////////////////////////////////////////////////// |
|
/* Stable vector. |
|
* |
|
* Copyright 2008 Joaquin M Lopez Munoz. |
|
* Distributed under the Boost Software License, Version 1.0. |
|
* (See accompanying file LICENSE_1_0.txt or copy at |
|
* http://www.boost.org/LICENSE_1_0.txt) |
|
*/ |
|
|
|
#ifndef BOOST_CONTAINER_STABLE_VECTOR_HPP |
|
#define BOOST_CONTAINER_STABLE_VECTOR_HPP |
|
|
|
#if (defined _MSC_VER) && (_MSC_VER >= 1200) |
|
# pragma once |
|
#endif |
|
|
|
#include <boost/container/detail/config_begin.hpp> |
|
#include <boost/container/detail/workaround.hpp> |
|
#include <boost/container/container_fwd.hpp> |
|
#include <boost/mpl/bool.hpp> |
|
#include <boost/mpl/not.hpp> |
|
#include <boost/noncopyable.hpp> |
|
#include <boost/type_traits/is_integral.hpp> |
|
#include <boost/container/detail/version_type.hpp> |
|
#include <boost/container/detail/multiallocation_chain.hpp> |
|
#include <boost/container/detail/utilities.hpp> |
|
#include <boost/container/detail/iterators.hpp> |
|
#include <boost/container/detail/algorithms.hpp> |
|
#include <boost/pointer_to_other.hpp> |
|
#include <boost/get_pointer.hpp> |
|
|
|
#include <algorithm> |
|
#include <stdexcept> |
|
#include <memory> |
|
|
|
///@cond |
|
|
|
#include <boost/container/vector.hpp> |
|
|
|
//#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING |
|
|
|
#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) |
|
#include <boost/assert.hpp> |
|
#endif |
|
|
|
///@endcond |
|
|
|
namespace boost { |
|
namespace container { |
|
|
|
///@cond |
|
|
|
namespace stable_vector_detail{ |
|
|
|
template<class SmartPtr> |
|
struct smart_ptr_type |
|
{ |
|
typedef typename SmartPtr::value_type value_type; |
|
typedef value_type *pointer; |
|
static pointer get (const SmartPtr &smartptr) |
|
{ return smartptr.get();} |
|
}; |
|
|
|
template<class T> |
|
struct smart_ptr_type<T*> |
|
{ |
|
typedef T value_type; |
|
typedef value_type *pointer; |
|
static pointer get (pointer ptr) |
|
{ return ptr;} |
|
}; |
|
|
|
template<class Ptr> |
|
inline typename smart_ptr_type<Ptr>::pointer get_pointer(const Ptr &ptr) |
|
{ return smart_ptr_type<Ptr>::get(ptr); } |
|
|
|
template <class C> |
|
class clear_on_destroy |
|
{ |
|
public: |
|
clear_on_destroy(C &c) |
|
: c_(c), do_clear_(true) |
|
{} |
|
|
|
void release() |
|
{ do_clear_ = false; } |
|
|
|
~clear_on_destroy() |
|
{ |
|
if(do_clear_){ |
|
c_.clear(); |
|
c_.clear_pool(); |
|
} |
|
} |
|
|
|
private: |
|
clear_on_destroy(const clear_on_destroy &); |
|
clear_on_destroy &operator=(const clear_on_destroy &); |
|
C &c_; |
|
bool do_clear_; |
|
}; |
|
|
|
template<class VoidPtr> |
|
struct node_type_base |
|
{/* |
|
node_type_base(VoidPtr p) |
|
: up(p) |
|
{}*/ |
|
node_type_base() |
|
{} |
|
void set_pointer(VoidPtr p) |
|
{ up = p; } |
|
|
|
VoidPtr up; |
|
}; |
|
|
|
template<typename VoidPointer, typename T> |
|
struct node_type |
|
: public node_type_base<VoidPointer> |
|
{ |
|
#if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
|
|
node_type() |
|
: value() |
|
{} |
|
|
|
template<class ...Args> |
|
node_type(Args &&...args) |
|
: value(boost::forward<Args>(args)...) |
|
{} |
|
|
|
#else //BOOST_CONTAINERS_PERFECT_FORWARDING |
|
|
|
node_type() |
|
: value() |
|
{} |
|
|
|
#define BOOST_PP_LOCAL_MACRO(n) \ |
|
template<BOOST_PP_ENUM_PARAMS(n, class P)> \ |
|
node_type(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ |
|
: value(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ |
|
{} \ |
|
//! |
|
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) |
|
#include BOOST_PP_LOCAL_ITERATE() |
|
|
|
#endif//BOOST_CONTAINERS_PERFECT_FORWARDING |
|
|
|
void set_pointer(VoidPointer p) |
|
{ node_type_base<VoidPointer>::set_pointer(p); } |
|
|
|
T value; |
|
}; |
|
|
|
template<typename T, typename Reference, typename Pointer> |
|
class iterator |
|
: public std::iterator< std::random_access_iterator_tag |
|
, typename std::iterator_traits<Pointer>::value_type |
|
, typename std::iterator_traits<Pointer>::difference_type |
|
, Pointer |
|
, Reference> |
|
{ |
|
|
|
typedef typename boost::pointer_to_other |
|
<Pointer, void>::type void_ptr; |
|
typedef typename boost::pointer_to_other |
|
<Pointer, const void>::type const_void_ptr; |
|
typedef node_type<void_ptr, T> node_type_t; |
|
typedef typename boost::pointer_to_other |
|
<void_ptr, node_type_t>::type node_type_ptr_t; |
|
typedef typename boost::pointer_to_other |
|
<void_ptr, const node_type_t>::type const_node_type_ptr_t; |
|
typedef typename boost::pointer_to_other |
|
<void_ptr, void_ptr>::type void_ptr_ptr; |
|
|
|
friend class iterator<T, const T, typename boost::pointer_to_other<Pointer, T>::type>; |
|
|
|
public: |
|
typedef std::random_access_iterator_tag iterator_category; |
|
typedef T value_type; |
|
typedef typename std::iterator_traits |
|
<Pointer>::difference_type difference_type; |
|
typedef Pointer pointer; |
|
typedef Reference reference; |
|
|
|
iterator() |
|
{} |
|
|
|
explicit iterator(node_type_ptr_t pn) |
|
: pn(pn) |
|
{} |
|
|
|
iterator(const iterator<T, T&, typename boost::pointer_to_other<Pointer, T>::type >& x) |
|
: pn(x.pn) |
|
{} |
|
|
|
private: |
|
static node_type_ptr_t node_ptr_cast(const void_ptr &p) |
|
{ |
|
using boost::get_pointer; |
|
return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p))); |
|
} |
|
|
|
static const_node_type_ptr_t node_ptr_cast(const const_void_ptr &p) |
|
{ |
|
using boost::get_pointer; |
|
return const_node_type_ptr_t(static_cast<const node_type_t*>(stable_vector_detail::get_pointer(p))); |
|
} |
|
|
|
static void_ptr_ptr void_ptr_ptr_cast(const void_ptr &p) |
|
{ |
|
using boost::get_pointer; |
|
return void_ptr_ptr(static_cast<void_ptr*>(stable_vector_detail::get_pointer(p))); |
|
} |
|
|
|
reference dereference() const |
|
{ return pn->value; } |
|
bool equal(const iterator& x) const |
|
{ return pn==x.pn; } |
|
void increment() |
|
{ pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); } |
|
void decrement() |
|
{ pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); } |
|
void advance(difference_type n) |
|
{ pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); } |
|
difference_type distance_to(const iterator& x)const |
|
{ return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); } |
|
|
|
public: |
|
//Pointer like operators |
|
reference operator*() const { return this->dereference(); } |
|
pointer operator->() const { return pointer(&this->dereference()); } |
|
|
|
//Increment / Decrement |
|
iterator& operator++() |
|
{ this->increment(); return *this; } |
|
|
|
iterator operator++(int) |
|
{ iterator tmp(*this); ++*this; return iterator(tmp); } |
|
|
|
iterator& operator--() |
|
{ this->decrement(); return *this; } |
|
|
|
iterator operator--(int) |
|
{ iterator tmp(*this); --*this; return iterator(tmp); } |
|
|
|
reference operator[](difference_type off) const |
|
{ |
|
iterator tmp(*this); |
|
tmp += off; |
|
return *tmp; |
|
} |
|
|
|
iterator& operator+=(difference_type off) |
|
{ |
|
pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off)); |
|
return *this; |
|
} |
|
|
|
friend iterator operator+(const iterator &left, difference_type off) |
|
{ |
|
iterator tmp(left); |
|
tmp += off; |
|
return tmp; |
|
} |
|
|
|
friend iterator operator+(difference_type off, const iterator& right) |
|
{ |
|
iterator tmp(right); |
|
tmp += off; |
|
return tmp; |
|
} |
|
|
|
iterator& operator-=(difference_type off) |
|
{ *this += -off; return *this; } |
|
|
|
friend iterator operator-(const iterator &left, difference_type off) |
|
{ |
|
iterator tmp(left); |
|
tmp -= off; |
|
return tmp; |
|
} |
|
|
|
friend difference_type operator-(const iterator& left, const iterator& right) |
|
{ |
|
return void_ptr_ptr_cast(left.pn->up) - void_ptr_ptr_cast(right.pn->up); |
|
} |
|
|
|
//Comparison operators |
|
friend bool operator== (const iterator& l, const iterator& r) |
|
{ return l.pn == r.pn; } |
|
|
|
friend bool operator!= (const iterator& l, const iterator& r) |
|
{ return l.pn != r.pn; } |
|
|
|
friend bool operator< (const iterator& l, const iterator& r) |
|
{ return void_ptr_ptr_cast(l.pn->up) < void_ptr_ptr_cast(r.pn->up); } |
|
|
|
friend bool operator<= (const iterator& l, const iterator& r) |
|
{ return void_ptr_ptr_cast(l.pn->up) <= void_ptr_ptr_cast(r.pn->up); } |
|
|
|
friend bool operator> (const iterator& l, const iterator& r) |
|
{ return void_ptr_ptr_cast(l.pn->up) > void_ptr_ptr_cast(r.pn->up); } |
|
|
|
friend bool operator>= (const iterator& l, const iterator& r) |
|
{ return void_ptr_ptr_cast(l.pn->up) >= void_ptr_ptr_cast(r.pn->up); } |
|
|
|
node_type_ptr_t pn; |
|
}; |
|
|
|
template<class A, unsigned int Version> |
|
struct select_multiallocation_chain |
|
{ |
|
typedef typename A::multiallocation_chain type; |
|
}; |
|
|
|
template<class A> |
|
struct select_multiallocation_chain<A, 1> |
|
{ |
|
typedef typename A::template |
|
rebind<void>::other::pointer void_ptr; |
|
typedef containers_detail::basic_multiallocation_chain |
|
<void_ptr> multialloc_cached_counted; |
|
typedef boost::container::containers_detail::transform_multiallocation_chain |
|
<multialloc_cached_counted, typename A::value_type> type; |
|
}; |
|
|
|
} //namespace stable_vector_detail |
|
|
|
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
|
|
#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) |
|
|
|
#define STABLE_VECTOR_CHECK_INVARIANT \ |
|
invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ |
|
BOOST_JOIN(check_invariant_,__LINE__).touch(); |
|
#else |
|
|
|
#define STABLE_VECTOR_CHECK_INVARIANT |
|
|
|
#endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) |
|
|
|
#endif //#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
|
|
/// @endcond |
|
|
|
//!Originally developed by Joaquin M. Lopez Munoz, stable_vector is std::vector |
|
//!drop-in replacement implemented as a node container, offering iterator and reference |
|
//!stability. |
|
//! |
|
//!More details taken the author's blog: (<a href="http://bannalia.blogspot.com/2008/09/introducing-stablevector.html" > Introducing stable_vector</a>) |
|
//! |
|
//!We present stable_vector, a fully STL-compliant stable container that provides |
|
//!most of the features of std::vector except element contiguity. |
|
//! |
|
//!General properties: stable_vector satisfies all the requirements of a container, |
|
//!a reversible container and a sequence and provides all the optional operations |
|
//!present in std::vector. Like std::vector, iterators are random access. |
|
//!stable_vector does not provide element contiguity; in exchange for this absence, |
|
//!the container is stable, i.e. references and iterators to an element of a stable_vector |
|
//!remain valid as long as the element is not erased, and an iterator that has been |
|
//!assigned the return value of end() always remain valid until the destruction of |
|
//!the associated stable_vector. |
|
//! |
|
//!Operation complexity: The big-O complexities of stable_vector operations match |
|
//!exactly those of std::vector. In general, insertion/deletion is constant time at |
|
//!the end of the sequence and linear elsewhere. Unlike std::vector, stable_vector |
|
//!does not internally perform any value_type destruction, copy or assignment |
|
//!operations other than those exactly corresponding to the insertion of new |
|
//!elements or deletion of stored elements, which can sometimes compensate in terms |
|
//!of performance for the extra burden of doing more pointer manipulation and an |
|
//!additional allocation per element. |
|
//! |
|
//!Exception safety: As stable_vector does not internally copy elements around, some |
|
//!operations provide stronger exception safety guarantees than in std::vector: |
|
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED |
|
template <class T, class A = std::allocator<T> > |
|
#else |
|
template <class T, class A> |
|
#endif |
|
class stable_vector |
|
{ |
|
///@cond |
|
typedef typename containers_detail:: |
|
move_const_ref_type<T>::type insert_const_ref_type; |
|
typedef typename A::template |
|
rebind<void>::other::pointer void_ptr; |
|
typedef typename boost::pointer_to_other |
|
<void_ptr, const void>::type const_void_ptr; |
|
typedef typename A::template |
|
rebind<void_ptr>::other::pointer void_ptr_ptr; |
|
typedef typename boost::pointer_to_other |
|
<void_ptr, const void_ptr>::type const_void_ptr_ptr; |
|
typedef stable_vector_detail::node_type |
|
<void_ptr, T> node_type_t; |
|
typedef typename A::template |
|
rebind<node_type_t>::other::pointer node_type_ptr_t; |
|
typedef stable_vector_detail::node_type_base |
|
<void_ptr> node_type_base_t; |
|
typedef typename A::template |
|
rebind<node_type_base_t>::other::pointer node_type_base_ptr_t; |
|
typedef |
|
::boost::container::vector<void_ptr, |
|
typename A:: |
|
template rebind<void_ptr>::other |
|
> impl_type; |
|
typedef typename impl_type::iterator impl_iterator; |
|
typedef typename impl_type::const_iterator const_impl_iterator; |
|
|
|
typedef ::boost::container::containers_detail:: |
|
integral_constant<unsigned, 1> allocator_v1; |
|
typedef ::boost::container::containers_detail:: |
|
integral_constant<unsigned, 2> allocator_v2; |
|
typedef ::boost::container::containers_detail::integral_constant |
|
<unsigned, boost::container::containers_detail:: |
|
version<A>::value> alloc_version; |
|
typedef typename A:: |
|
template rebind<node_type_t>::other node_allocator_type; |
|
|
|
node_type_ptr_t allocate_one() |
|
{ return this->allocate_one(alloc_version()); } |
|
|
|
node_type_ptr_t allocate_one(allocator_v1) |
|
{ return get_al().allocate(1); } |
|
|
|
node_type_ptr_t allocate_one(allocator_v2) |
|
{ return get_al().allocate_one(); } |
|
|
|
void deallocate_one(node_type_ptr_t p) |
|
{ return this->deallocate_one(p, alloc_version()); } |
|
|
|
void deallocate_one(node_type_ptr_t p, allocator_v1) |
|
{ get_al().deallocate(p, 1); } |
|
|
|
void deallocate_one(node_type_ptr_t p, allocator_v2) |
|
{ get_al().deallocate_one(p); } |
|
|
|
friend class stable_vector_detail::clear_on_destroy<stable_vector>; |
|
///@endcond |
|
public: |
|
|
|
|
|
// types: |
|
|
|
typedef typename A::reference reference; |
|
typedef typename A::const_reference const_reference; |
|
typedef typename A::pointer pointer; |
|
typedef typename A::const_pointer const_pointer; |
|
typedef stable_vector_detail::iterator |
|
<T,T&, pointer> iterator; |
|
typedef stable_vector_detail::iterator |
|
<T,const T&, const_pointer> const_iterator; |
|
typedef typename impl_type::size_type size_type; |
|
typedef typename iterator::difference_type difference_type; |
|
typedef T value_type; |
|
typedef A allocator_type; |
|
typedef std::reverse_iterator<iterator> reverse_iterator; |
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; |
|
|
|
///@cond |
|
private: |
|
BOOST_COPYABLE_AND_MOVABLE(stable_vector) |
|
static const size_type ExtraPointers = 3; |
|
//This container stores metadata at the end of the void_ptr vector with additional 3 pointers: |
|
// back() is impl.back() - ExtraPointers; |
|
// end node index is impl.end()[-3] |
|
// Node cache first is impl.end()[-2]; |
|
// Node cache last is *impl.back(); |
|
|
|
typedef typename stable_vector_detail:: |
|
select_multiallocation_chain |
|
< node_allocator_type |
|
, alloc_version::value |
|
>::type multiallocation_chain; |
|
///@endcond |
|
public: |
|
|
|
//! <b>Effects</b>: Constructs a stable_vector taking the allocator as parameter. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
explicit stable_vector(const A& al=A()) |
|
: internal_data(al),impl(al) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
} |
|
|
|
//! <b>Effects</b>: Constructs a stable_vector that will use a copy of allocator a |
|
//! and inserts n default contructed values. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
|
//! throws or T's default or copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to n. |
|
explicit stable_vector(size_type n) |
|
: internal_data(A()),impl(A()) |
|
{ |
|
stable_vector_detail::clear_on_destroy<stable_vector> cod(*this); |
|
this->resize(n); |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
cod.release(); |
|
} |
|
|
|
//! <b>Effects</b>: Constructs a stable_vector that will use a copy of allocator a |
|
//! and inserts n copies of value. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
|
//! throws or T's default or copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to n. |
|
stable_vector(size_type n, const T& t, const A& al=A()) |
|
: internal_data(al),impl(al) |
|
{ |
|
stable_vector_detail::clear_on_destroy<stable_vector> cod(*this); |
|
this->insert(this->cbegin(), n, t); |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
cod.release(); |
|
} |
|
|
|
//! <b>Effects</b>: Constructs a stable_vector that will use a copy of allocator a |
|
//! and inserts a copy of the range [first, last) in the stable_vector. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's default constructor or copy constructor |
|
//! throws or T's constructor taking an dereferenced InIt throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to the range [first, last). |
|
template <class InputIterator> |
|
stable_vector(InputIterator first,InputIterator last,const A& al=A()) |
|
: internal_data(al),impl(al) |
|
{ |
|
stable_vector_detail::clear_on_destroy<stable_vector> cod(*this); |
|
this->insert(this->cbegin(), first, last); |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
cod.release(); |
|
} |
|
|
|
//! <b>Effects</b>: Copy constructs a stable_vector. |
|
//! |
|
//! <b>Postcondition</b>: x == *this. |
|
//! |
|
//! <b>Complexity</b>: Linear to the elements x contains. |
|
stable_vector(const stable_vector& x) |
|
: internal_data(x.get_al()),impl(x.get_al()) |
|
{ |
|
stable_vector_detail::clear_on_destroy<stable_vector> cod(*this); |
|
this->insert(this->cbegin(), x.begin(), x.end()); |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
cod.release(); |
|
} |
|
|
|
//! <b>Effects</b>: Move constructor. Moves mx's resources to *this. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
stable_vector(BOOST_RV_REF(stable_vector) x) |
|
: internal_data(x.get_al()),impl(x.get_al()) |
|
{ this->swap(x); } |
|
|
|
//! <b>Effects</b>: Destroys the stable_vector. All stored values are destroyed |
|
//! and used memory is deallocated. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Linear to the number of elements. |
|
~stable_vector() |
|
{ |
|
this->clear(); |
|
clear_pool(); |
|
} |
|
|
|
//! <b>Effects</b>: Makes *this contain the same elements as x. |
|
//! |
|
//! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy |
|
//! of each of x's elements. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to the number of elements in x. |
|
stable_vector& operator=(BOOST_COPY_ASSIGN_REF(stable_vector) x) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
if (this != &x) { |
|
this->assign(x.begin(), x.end()); |
|
} |
|
return *this; |
|
} |
|
|
|
//! <b>Effects</b>: Move assignment. All mx's values are transferred to *this. |
|
//! |
|
//! <b>Postcondition</b>: x.empty(). *this contains a the elements x had |
|
//! before the function. |
|
//! |
|
//! <b>Throws</b>: If allocator_type's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear. |
|
stable_vector& operator=(BOOST_RV_REF(stable_vector) x) |
|
{ |
|
if (&x != this){ |
|
this->swap(x); |
|
x.clear(); |
|
} |
|
return *this; |
|
} |
|
|
|
//! <b>Effects</b>: Assigns the the range [first, last) to *this. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or |
|
//! T's constructor from dereferencing InpIt throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to n. |
|
template<typename InputIterator> |
|
void assign(InputIterator first,InputIterator last) |
|
{ |
|
assign_dispatch(first, last, boost::is_integral<InputIterator>()); |
|
} |
|
|
|
|
|
//! <b>Effects</b>: Assigns the n copies of val to *this. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to n. |
|
void assign(size_type n,const T& t) |
|
{ |
|
typedef constant_iterator<value_type, difference_type> cvalue_iterator; |
|
return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); |
|
} |
|
|
|
//! <b>Effects</b>: Returns a copy of the internal allocator. |
|
//! |
|
//! <b>Throws</b>: If allocator's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
allocator_type get_allocator()const {return get_al();} |
|
|
|
|
|
//! <b>Effects</b>: Returns an iterator to the first element contained in the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
iterator begin() |
|
{ return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; } |
|
|
|
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_iterator begin()const |
|
{ return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; } |
|
|
|
//! <b>Effects</b>: Returns an iterator to the end of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
iterator end() {return iterator(get_end_node());} |
|
|
|
//! <b>Effects</b>: Returns a const_iterator to the end of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_iterator end()const {return const_iterator(get_end_node());} |
|
|
|
//! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reverse_iterator rbegin() {return reverse_iterator(this->end());} |
|
|
|
//! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());} |
|
|
|
//! <b>Effects</b>: Returns a reverse_iterator pointing to the end |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reverse_iterator rend() {return reverse_iterator(this->begin());} |
|
|
|
//! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());} |
|
|
|
//! <b>Effects</b>: Returns a const_iterator to the first element contained in the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_iterator cbegin()const {return this->begin();} |
|
|
|
//! <b>Effects</b>: Returns a const_iterator to the end of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_iterator cend()const {return this->end();} |
|
|
|
//! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reverse_iterator crbegin()const{return this->rbegin();} |
|
|
|
//! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end |
|
//! of the reversed stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reverse_iterator crend()const {return this->rend();} |
|
|
|
//! <b>Effects</b>: Returns the number of the elements contained in the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
size_type size() const |
|
{ return impl.empty() ? 0 : (impl.size() - ExtraPointers); } |
|
|
|
//! <b>Effects</b>: Returns the largest possible size of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
size_type max_size() const |
|
{ return impl.max_size() - ExtraPointers; } |
|
|
|
//! <b>Effects</b>: Number of elements for which memory has been allocated. |
|
//! capacity() is always greater than or equal to size(). |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
size_type capacity() const |
|
{ |
|
if(!impl.capacity()){ |
|
return 0; |
|
} |
|
else{ |
|
const size_type num_nodes = this->impl.size() + this->internal_data.pool_size; |
|
const size_type num_buck = this->impl.capacity(); |
|
return (num_nodes < num_buck) ? num_nodes : num_buck; |
|
} |
|
} |
|
|
|
//! <b>Effects</b>: Returns true if the stable_vector contains no elements. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
bool empty() const |
|
{ return impl.empty() || impl.size() == ExtraPointers; } |
|
|
|
//! <b>Effects</b>: Inserts or erases elements at the end such that |
|
//! the size becomes n. New elements are copy constructed from x. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to the difference between size() and new_size. |
|
void resize(size_type n, const T& t) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
if(n > size()) |
|
this->insert(this->cend(), n - this->size(), t); |
|
else if(n < this->size()) |
|
this->erase(this->cbegin() + n, this->cend()); |
|
} |
|
|
|
//! <b>Effects</b>: Inserts or erases elements at the end such that |
|
//! the size becomes n. New elements are default constructed. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to the difference between size() and new_size. |
|
void resize(size_type n) |
|
{ |
|
typedef default_construct_iterator<value_type, difference_type> default_iterator; |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
if(n > size()) |
|
this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); |
|
else if(n < this->size()) |
|
this->erase(this->cbegin() + n, this->cend()); |
|
} |
|
|
|
//! <b>Effects</b>: If n is less than or equal to capacity(), this call has no |
|
//! effect. Otherwise, it is a request for allocation of additional memory. |
|
//! If the request is successful, then capacity() is greater than or equal to |
|
//! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. |
|
//! |
|
//! <b>Throws</b>: If memory allocation allocation throws. |
|
void reserve(size_type n) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
if(n > this->max_size()) |
|
throw std::bad_alloc(); |
|
|
|
size_type size = this->size(); |
|
size_type old_capacity = this->capacity(); |
|
if(n > old_capacity){ |
|
this->initialize_end_node(n); |
|
const void * old_ptr = &impl[0]; |
|
impl.reserve(n + ExtraPointers); |
|
bool realloced = &impl[0] != old_ptr; |
|
//Fix the pointers for the newly allocated buffer |
|
if(realloced){ |
|
this->align_nodes(impl.begin(), impl.begin()+size+1); |
|
} |
|
//Now fill pool if data is not enough |
|
if((n - size) > this->internal_data.pool_size){ |
|
this->add_to_pool((n - size) - this->internal_data.pool_size); |
|
} |
|
} |
|
} |
|
|
|
//! <b>Requires</b>: size() < n. |
|
//! |
|
//! <b>Effects</b>: Returns a reference to the nth element |
|
//! from the beginning of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reference operator[](size_type n){return value(impl[n]);} |
|
|
|
//! <b>Requires</b>: size() < n. |
|
//! |
|
//! <b>Effects</b>: Returns a const reference to the nth element |
|
//! from the beginning of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reference operator[](size_type n)const{return value(impl[n]);} |
|
|
|
//! <b>Requires</b>: size() < n. |
|
//! |
|
//! <b>Effects</b>: Returns a reference to the nth element |
|
//! from the beginning of the container. |
|
//! |
|
//! <b>Throws</b>: std::range_error if n >= size() |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reference at(size_type n) |
|
{ |
|
if(n>=size()) |
|
throw std::out_of_range("invalid subscript at stable_vector::at"); |
|
return operator[](n); |
|
} |
|
|
|
//! <b>Requires</b>: size() < n. |
|
//! |
|
//! <b>Effects</b>: Returns a const reference to the nth element |
|
//! from the beginning of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reference at(size_type n)const |
|
{ |
|
if(n>=size()) |
|
throw std::out_of_range("invalid subscript at stable_vector::at"); |
|
return operator[](n); |
|
} |
|
|
|
//! <b>Requires</b>: !empty() |
|
//! |
|
//! <b>Effects</b>: Returns a reference to the first |
|
//! element of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reference front() |
|
{ return value(impl.front()); } |
|
|
|
//! <b>Requires</b>: !empty() |
|
//! |
|
//! <b>Effects</b>: Returns a const reference to the first |
|
//! element of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reference front()const |
|
{ return value(impl.front()); } |
|
|
|
//! <b>Requires</b>: !empty() |
|
//! |
|
//! <b>Effects</b>: Returns a reference to the last |
|
//! element of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
reference back() |
|
{ return value(*(&impl.back() - ExtraPointers)); } |
|
|
|
//! <b>Requires</b>: !empty() |
|
//! |
|
//! <b>Effects</b>: Returns a const reference to the last |
|
//! element of the container. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
const_reference back()const |
|
{ return value(*(&impl.back() - ExtraPointers)); } |
|
|
|
//! <b>Effects</b>: Inserts a copy of x at the end of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or |
|
//! T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Amortized constant time. |
|
void push_back(insert_const_ref_type x) |
|
{ return priv_push_back(x); } |
|
|
|
#if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
void push_back(T &x) { push_back(const_cast<const T &>(x)); } |
|
|
|
template<class U> |
|
void push_back(const U &u, typename containers_detail::enable_if_c<containers_detail::is_same<T, U>::value && !::boost::has_move_emulation_enabled<U>::value >::type* =0) |
|
{ return priv_push_back(u); } |
|
#endif |
|
|
|
//! <b>Effects</b>: Constructs a new element in the end of the stable_vector |
|
//! and moves the resources of mx to this new element. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws. |
|
//! |
|
//! <b>Complexity</b>: Amortized constant time. |
|
void push_back(BOOST_RV_REF(T) t) |
|
{ this->insert(end(), boost::move(t)); } |
|
|
|
//! <b>Effects</b>: Removes the last element from the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant time. |
|
void pop_back() |
|
{ this->erase(this->end()-1); } |
|
|
|
//! <b>Requires</b>: position must be a valid iterator of *this. |
|
//! |
|
//! <b>Effects</b>: Insert a copy of x before position. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or x's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: If position is end(), amortized constant time |
|
//! Linear time otherwise. |
|
iterator insert(const_iterator position, insert_const_ref_type x) |
|
{ return this->priv_insert(position, x); } |
|
|
|
#if defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
iterator insert(const_iterator position, T &x) { return this->insert(position, const_cast<const T &>(x)); } |
|
|
|
template<class U> |
|
iterator insert(const_iterator position, const U &u, typename containers_detail::enable_if_c<containers_detail::is_same<T, U>::value && !::boost::has_move_emulation_enabled<U>::value >::type* =0) |
|
{ return this->priv_insert(position, u); } |
|
#endif |
|
|
|
//! <b>Requires</b>: position must be a valid iterator of *this. |
|
//! |
|
//! <b>Effects</b>: Insert a new element before position with mx's resources. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws. |
|
//! |
|
//! <b>Complexity</b>: If position is end(), amortized constant time |
|
//! Linear time otherwise. |
|
iterator insert(const_iterator position, BOOST_RV_REF(T) x) |
|
{ |
|
typedef repeat_iterator<T, difference_type> repeat_it; |
|
typedef boost::move_iterator<repeat_it> repeat_move_it; |
|
//Just call more general insert(pos, size, value) and return iterator |
|
size_type pos_n = position - cbegin(); |
|
this->insert(position |
|
,repeat_move_it(repeat_it(x, 1)) |
|
,repeat_move_it(repeat_it())); |
|
return iterator(this->begin() + pos_n); |
|
} |
|
|
|
//! <b>Requires</b>: pos must be a valid iterator of *this. |
|
//! |
|
//! <b>Effects</b>: Insert n copies of x before pos. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to n. |
|
void insert(const_iterator position, size_type n, const T& t) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
this->insert_not_iter(position, n, t); |
|
} |
|
|
|
//! <b>Requires</b>: pos must be a valid iterator of *this. |
|
//! |
|
//! <b>Effects</b>: Insert a copy of the [first, last) range before pos. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws, T's constructor from a |
|
//! dereferenced InpIt throws or T's copy constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to std::distance [first, last). |
|
template <class InputIterator> |
|
void insert(const_iterator position,InputIterator first, InputIterator last) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
this->insert_iter(position,first,last, |
|
boost::mpl::not_<boost::is_integral<InputIterator> >()); |
|
} |
|
|
|
#if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) |
|
|
|
//! <b>Effects</b>: Inserts an object of type T constructed with |
|
//! std::forward<Args>(args)... in the end of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. |
|
//! |
|
//! <b>Complexity</b>: Amortized constant time. |
|
template<class ...Args> |
|
void emplace_back(Args &&...args) |
|
{ |
|
typedef emplace_functor<node_type_t, Args...> EmplaceFunctor; |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; |
|
EmplaceFunctor &&ef = EmplaceFunctor(boost::forward<Args>(args)...); |
|
this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); |
|
} |
|
|
|
//! <b>Requires</b>: position must be a valid iterator of *this. |
|
//! |
|
//! <b>Effects</b>: Inserts an object of type T constructed with |
|
//! std::forward<Args>(args)... before position |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. |
|
//! |
|
//! <b>Complexity</b>: If position is end(), amortized constant time |
|
//! Linear time otherwise. |
|
template<class ...Args> |
|
iterator emplace(const_iterator position, Args && ...args) |
|
{ |
|
//Just call more general insert(pos, size, value) and return iterator |
|
size_type pos_n = position - cbegin(); |
|
typedef emplace_functor<node_type_t, Args...> EmplaceFunctor; |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; |
|
EmplaceFunctor &&ef = EmplaceFunctor(boost::forward<Args>(args)...); |
|
this->insert(position, EmplaceIterator(ef), EmplaceIterator()); |
|
return iterator(this->begin() + pos_n); |
|
} |
|
|
|
#else |
|
|
|
void emplace_back() |
|
{ |
|
typedef emplace_functor<node_type_t> EmplaceFunctor; |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; |
|
EmplaceFunctor ef; |
|
this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); |
|
} |
|
|
|
iterator emplace(const_iterator position) |
|
{ |
|
typedef emplace_functor<node_type_t> EmplaceFunctor; |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; |
|
EmplaceFunctor ef; |
|
size_type pos_n = position - this->cbegin(); |
|
this->insert(position, EmplaceIterator(ef), EmplaceIterator()); |
|
return iterator(this->begin() + pos_n); |
|
} |
|
|
|
#define BOOST_PP_LOCAL_MACRO(n) \ |
|
template<BOOST_PP_ENUM_PARAMS(n, class P)> \ |
|
void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ |
|
{ \ |
|
typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ |
|
<node_type_t, BOOST_PP_ENUM_PARAMS(n, P)> EmplaceFunctor; \ |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; \ |
|
EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ |
|
this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); \ |
|
} \ |
|
\ |
|
template<BOOST_PP_ENUM_PARAMS(n, class P)> \ |
|
iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ |
|
{ \ |
|
typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ |
|
<node_type_t, BOOST_PP_ENUM_PARAMS(n, P)> EmplaceFunctor; \ |
|
typedef emplace_iterator<node_type_t, EmplaceFunctor, difference_type> EmplaceIterator; \ |
|
EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ |
|
size_type pos_n = pos - this->cbegin(); \ |
|
this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ |
|
return iterator(this->begin() + pos_n); \ |
|
} \ |
|
//! |
|
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) |
|
#include BOOST_PP_LOCAL_ITERATE() |
|
|
|
#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING |
|
|
|
//! <b>Effects</b>: Erases the element at position pos. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Linear to the elements between pos and the |
|
//! last element. Constant if pos is the last element. |
|
iterator erase(const_iterator position) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
difference_type d = position - this->cbegin(); |
|
impl_iterator it = impl.begin() + d; |
|
this->delete_node(*it); |
|
it = impl.erase(it); |
|
this->align_nodes(it, get_last_align()); |
|
return this->begin()+d; |
|
} |
|
|
|
//! <b>Effects</b>: Erases the elements pointed by [first, last). |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Linear to the distance between first and last |
|
//! plus linear to the elements between pos and the last element. |
|
iterator erase(const_iterator first, const_iterator last) |
|
{ return priv_erase(first, last, alloc_version()); } |
|
|
|
//! <b>Effects</b>: Swaps the contents of *this and x. |
|
//! If this->allocator_type() != x.allocator_type() |
|
//! allocators are also swapped. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Constant. |
|
void swap(stable_vector & x) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
this->swap_impl(*this,x); |
|
} |
|
|
|
//! <b>Effects</b>: Erases all the elements of the stable_vector. |
|
//! |
|
//! <b>Throws</b>: Nothing. |
|
//! |
|
//! <b>Complexity</b>: Linear to the number of elements in the stable_vector. |
|
void clear() |
|
{ this->erase(this->cbegin(),this->cend()); } |
|
|
|
//! <b>Effects</b>: Tries to deallocate the excess of memory created |
|
//! with previous allocations. The size of the stable_vector is unchanged |
|
//! |
|
//! <b>Throws</b>: If memory allocation throws. |
|
//! |
|
//! <b>Complexity</b>: Linear to size(). |
|
void shrink_to_fit() |
|
{ |
|
if(this->capacity()){ |
|
//First empty allocated node pool |
|
this->clear_pool(); |
|
//If empty completely destroy the index, let's recover default-constructed state |
|
if(this->empty()){ |
|
impl_type().swap(this->impl); |
|
this->internal_data.set_end_pointer_to_default_constructed(); |
|
} |
|
//Otherwise, try to shrink-to-fit the index and readjust pointers if necessary |
|
else{ |
|
const size_type size = this->size(); |
|
const void* old_ptr = &impl[0]; |
|
this->impl.shrink_to_fit(); |
|
bool realloced = &impl[0] != old_ptr; |
|
//Fix the pointers for the newly allocated buffer |
|
if(realloced){ |
|
this->align_nodes(impl.begin(), impl.begin()+size+1); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// @cond |
|
|
|
iterator priv_insert(const_iterator position, const value_type &t) |
|
{ |
|
typedef constant_iterator<value_type, difference_type> cvalue_iterator; |
|
return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); |
|
} |
|
|
|
void priv_push_back(const value_type &t) |
|
{ this->insert(end(), t); } |
|
|
|
void clear_pool(allocator_v1) |
|
{ |
|
if(!impl.empty() && impl.back()){ |
|
void_ptr &pool_first_ref = impl.end()[-2]; |
|
void_ptr &pool_last_ref = impl.back(); |
|
|
|
multiallocation_chain holder; |
|
holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, this->internal_data.pool_size); |
|
while(!holder.empty()){ |
|
node_type_ptr_t n = holder.front(); |
|
holder.pop_front(); |
|
this->deallocate_one(n); |
|
} |
|
pool_first_ref = pool_last_ref = 0; |
|
this->internal_data.pool_size = 0; |
|
} |
|
} |
|
|
|
void clear_pool(allocator_v2) |
|
{ |
|
|
|
if(!impl.empty() && impl.back()){ |
|
void_ptr &pool_first_ref = impl.end()[-2]; |
|
void_ptr &pool_last_ref = impl.back(); |
|
multiallocation_chain holder; |
|
holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); |
|
get_al().deallocate_individual(boost::move(holder)); |
|
pool_first_ref = pool_last_ref = 0; |
|
this->internal_data.pool_size = 0; |
|
} |
|
} |
|
|
|
void clear_pool() |
|
{ |
|
this->clear_pool(alloc_version()); |
|
} |
|
|
|
void add_to_pool(size_type n) |
|
{ |
|
this->add_to_pool(n, alloc_version()); |
|
} |
|
|
|
void add_to_pool(size_type n, allocator_v1) |
|
{ |
|
size_type remaining = n; |
|
while(remaining--){ |
|
this->put_in_pool(this->allocate_one()); |
|
} |
|
} |
|
|
|
void add_to_pool(size_type n, allocator_v2) |
|
{ |
|
void_ptr &pool_first_ref = impl.end()[-2]; |
|
void_ptr &pool_last_ref = impl.back(); |
|
multiallocation_chain holder; |
|
holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); |
|
//BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled<multiallocation_chain>::value == true)); |
|
multiallocation_chain m (get_al().allocate_individual(n)); |
|
holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n); |
|
this->internal_data.pool_size += n; |
|
std::pair<void_ptr, void_ptr> data(holder.extract_data()); |
|
pool_first_ref = data.first; |
|
pool_last_ref = data.second; |
|
} |
|
|
|
void put_in_pool(node_type_ptr_t p) |
|
{ |
|
void_ptr &pool_first_ref = impl.end()[-2]; |
|
void_ptr &pool_last_ref = impl.back(); |
|
multiallocation_chain holder; |
|
holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); |
|
holder.push_front(p); |
|
++this->internal_data.pool_size; |
|
std::pair<void_ptr, void_ptr> ret(holder.extract_data()); |
|
pool_first_ref = ret.first; |
|
pool_last_ref = ret.second; |
|
} |
|
|
|
node_type_ptr_t get_from_pool() |
|
{ |
|
if(!impl.back()){ |
|
return node_type_ptr_t(0); |
|
} |
|
else{ |
|
void_ptr &pool_first_ref = impl.end()[-2]; |
|
void_ptr &pool_last_ref = impl.back(); |
|
multiallocation_chain holder; |
|
holder.incorporate_after(holder.before_begin(), pool_first_ref, pool_last_ref, internal_data.pool_size); |
|
node_type_ptr_t ret = holder.front(); |
|
holder.pop_front(); |
|
--this->internal_data.pool_size; |
|
if(!internal_data.pool_size){ |
|
pool_first_ref = pool_last_ref = void_ptr(0); |
|
} |
|
else{ |
|
std::pair<void_ptr, void_ptr> data(holder.extract_data()); |
|
pool_first_ref = data.first; |
|
pool_last_ref = data.second; |
|
} |
|
return ret; |
|
} |
|
} |
|
|
|
void insert_iter_prolog(size_type n, difference_type d) |
|
{ |
|
initialize_end_node(n); |
|
const void* old_ptr = &impl[0]; |
|
//size_type old_capacity = capacity(); |
|
//size_type old_size = size(); |
|
impl.insert(impl.begin()+d, n, 0); |
|
bool realloced = &impl[0] != old_ptr; |
|
//Fix the pointers for the newly allocated buffer |
|
if(realloced){ |
|
align_nodes(impl.begin(), impl.begin()+d); |
|
} |
|
} |
|
|
|
template<typename InputIterator> |
|
void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
iterator first1 = this->begin(); |
|
iterator last1 = this->end(); |
|
for ( ; first1 != last1 && first != last; ++first1, ++first) |
|
*first1 = *first; |
|
if (first == last){ |
|
this->erase(first1, last1); |
|
} |
|
else{ |
|
this->insert(last1, first, last); |
|
} |
|
} |
|
|
|
template<typename Integer> |
|
void assign_dispatch(Integer n, Integer t, boost::mpl::true_) |
|
{ |
|
typedef constant_iterator<value_type, difference_type> cvalue_iterator; |
|
this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); |
|
} |
|
|
|
iterator priv_erase(const_iterator first, const_iterator last, allocator_v1) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); |
|
if(d1 != d2){ |
|
impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); |
|
for(impl_iterator it = it1; it != it2; ++it) |
|
this->delete_node(*it); |
|
impl_iterator e = impl.erase(it1, it2); |
|
this->align_nodes(e, get_last_align()); |
|
} |
|
return iterator(this->begin() + d1); |
|
} |
|
|
|
impl_iterator get_last_align() |
|
{ |
|
return impl.end() - (ExtraPointers - 1); |
|
} |
|
|
|
const_impl_iterator get_last_align() const |
|
{ |
|
return impl.cend() - (ExtraPointers - 1); |
|
} |
|
|
|
template<class AllocatorVersion> |
|
iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, |
|
typename boost::container::containers_detail::enable_if_c |
|
<boost::container::containers_detail::is_same<AllocatorVersion, allocator_v2> |
|
::value>::type * = 0) |
|
{ |
|
STABLE_VECTOR_CHECK_INVARIANT; |
|
return priv_erase(first, last, allocator_v1()); |
|
} |
|
|
|
static node_type_ptr_t node_ptr_cast(const void_ptr &p) |
|
{ |
|
using boost::get_pointer; |
|
return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p))); |
|
} |
|
|
|
static node_type_base_ptr_t node_base_ptr_cast(const void_ptr &p) |
|
{ |
|
using boost::get_pointer; |
|
return node_type_base_ptr_t(static_cast<node_type_base_t*>(stable_vector_detail::get_pointer(p))); |
|
} |
|
|
|
static value_type& value(const void_ptr &p) |
|
{ |
|
return node_ptr_cast(p)->value; |
|
} |
|
|
|
void initialize_end_node(size_type impl_capacity = 0) |
|
{ |
|
if(impl.empty()){ |
|
impl.reserve(impl_capacity + ExtraPointers); |
|
impl.resize (ExtraPointers, void_ptr(0)); |
|
impl[0] = &this->internal_data.end_node; |
|
this->internal_data.end_node.up = &impl[0]; |
|
} |
|
} |
|
|
|
void readjust_end_node() |
|
{ |
|
if(!this->impl.empty()){ |
|
void_ptr &end_node_ref = *(this->get_last_align()-1); |
|
end_node_ref = this->get_end_node(); |
|
this->internal_data.end_node.up = &end_node_ref; |
|
} |
|
else{ |
|
this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up); |
|
} |
|
} |
|
|
|
node_type_ptr_t get_end_node() const |
|
{ |
|
const node_type_base_t* cp = &this->internal_data.end_node; |
|
node_type_base_t* p = const_cast<node_type_base_t*>(cp); |
|
return node_ptr_cast(p); |
|
} |
|
|
|
template<class Iter> |
|
void_ptr new_node(const void_ptr &up, Iter it) |
|
{ |
|
node_type_ptr_t p = this->allocate_one(); |
|
try{ |
|
boost::container::construct_in_place(&*p, it); |
|
p->set_pointer(up); |
|
} |
|
catch(...){ |
|
this->deallocate_one(p); |
|
throw; |
|
} |
|
return p; |
|
} |
|
|
|
void delete_node(const void_ptr &p) |
|
{ |
|
node_type_ptr_t n(node_ptr_cast(p)); |
|
n->~node_type_t(); |
|
this->put_in_pool(n); |
|
} |
|
|
|
static void align_nodes(impl_iterator first, impl_iterator last) |
|
{ |
|
while(first!=last){ |
|
node_ptr_cast(*first)->up = void_ptr(&*first); |
|
++first; |
|
} |
|
} |
|
|
|
void insert_not_iter(const_iterator position, size_type n, const T& t) |
|
{ |
|
typedef constant_iterator<value_type, difference_type> cvalue_iterator; |
|
this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); |
|
} |
|
|
|
template <class InputIterator> |
|
void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) |
|
{ |
|
typedef typename std::iterator_traits<InputIterator>::iterator_category category; |
|
this->insert_iter(position, first, last, category()); |
|
} |
|
|
|
template <class InputIterator> |
|
void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) |
|
{ |
|
for(; first!=last; ++first){ |
|
this->insert(position, *first); |
|
} |
|
} |
|
|
|
template <class InputIterator> |
|
iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag) |
|
{ |
|
size_type n = (size_type)std::distance(first,last); |
|
difference_type d = position-this->cbegin(); |
|
if(n){ |
|
this->insert_iter_prolog(n, d); |
|
const impl_iterator it(impl.begin() + d); |
|
this->insert_iter_fwd(it, first, last, n); |
|
//Fix the pointers for the newly allocated buffer |
|
this->align_nodes(it + n, get_last_align()); |
|
} |
|
return this->begin() + d; |
|
} |
|
|
|
template <class FwdIterator> |
|
void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) |
|
{ |
|
size_type i=0; |
|
try{ |
|
while(first!=last){ |
|
it[i] = this->new_node(void_ptr_ptr(&it[i]), first); |
|
++first; |
|
++i; |
|
} |
|
} |
|
catch(...){ |
|
impl_iterator e = impl.erase(it + i, it + n); |
|
this->align_nodes(e, get_last_align()); |
|
throw; |
|
} |
|
} |
|
|
|
template <class FwdIterator> |
|
void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) |
|
{ |
|
multiallocation_chain mem(get_al().allocate_individual(n)); |
|
|
|
size_type i = 0; |
|
node_type_ptr_t p = 0; |
|
try{ |
|
while(first != last){ |
|
p = mem.front(); |
|
mem.pop_front(); |
|
//This can throw |
|
boost::container::construct_in_place(&*p, first); |
|
p->set_pointer(void_ptr_ptr(&it[i])); |
|
++first; |
|
it[i] = p; |
|
++i; |
|
} |
|
} |
|
catch(...){ |
|
get_al().deallocate_one(p); |
|
get_al().deallocate_many(boost::move(mem)); |
|
impl_iterator e = impl.erase(it+i, it+n); |
|
this->align_nodes(e, get_last_align()); |
|
throw; |
|
} |
|
} |
|
|
|
template <class FwdIterator> |
|
void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) |
|
{ |
|
size_type i = 0; |
|
node_type_ptr_t p = 0; |
|
try{ |
|
while(first != last){ |
|
p = get_from_pool(); |
|
if(!p){ |
|
insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); |
|
break; |
|
} |
|
//This can throw |
|
boost::container::construct_in_place(&*p, first); |
|
p->set_pointer(void_ptr_ptr(&it[i])); |
|
++first; |
|
it[i]=p; |
|
++i; |
|
} |
|
} |
|
catch(...){ |
|
put_in_pool(p); |
|
impl_iterator e = impl.erase(it+i, it+n); |
|
this->align_nodes(e, get_last_align()); |
|
throw; |
|
} |
|
} |
|
|
|
template <class InputIterator> |
|
void insert_iter(const_iterator position, InputIterator first, InputIterator last, boost::mpl::false_) |
|
{ |
|
this->insert_not_iter(position, first, last); |
|
} |
|
|
|
static void swap_impl(stable_vector& x,stable_vector& y) |
|
{ |
|
using std::swap; |
|
swap(x.get_al(),y.get_al()); |
|
swap(x.impl,y.impl); |
|
swap(x.internal_data.pool_size, y.internal_data.pool_size); |
|
x.readjust_end_node(); |
|
y.readjust_end_node(); |
|
} |
|
|
|
#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) |
|
bool invariant()const |
|
{ |
|
if(impl.empty()) |
|
return !capacity() && !size(); |
|
if(get_end_node() != *(impl.end() - ExtraPointers)){ |
|
return false; |
|
} |
|
for(const_impl_iterator it = impl.begin(), it_end = get_last_align(); it != it_end; ++it){ |
|
if(const_void_ptr(node_ptr_cast(*it)->up) != |
|
const_void_ptr(const_void_ptr_ptr(&*it))) |
|
return false; |
|
} |
|
size_type n = capacity()-size(); |
|
const void_ptr &pool_head = impl.back(); |
|
size_type num_pool = 0; |
|
node_type_ptr_t p = node_ptr_cast(pool_head); |
|
while(p){ |
|
++num_pool; |
|
p = node_ptr_cast(p->up); |
|
} |
|
return n >= num_pool; |
|
} |
|
|
|
class invariant_checker:private boost::noncopyable |
|
{ |
|
const stable_vector* p; |
|
public: |
|
invariant_checker(const stable_vector& v):p(&v){} |
|
~invariant_checker(){BOOST_ASSERT(p->invariant());} |
|
void touch(){} |
|
}; |
|
#endif |
|
|
|
struct ebo_holder |
|
: node_allocator_type |
|
{ |
|
ebo_holder(const allocator_type &a) |
|
: node_allocator_type(a), pool_size(0), end_node() |
|
{ |
|
this->set_end_pointer_to_default_constructed(); |
|
} |
|
|
|
void set_end_pointer_to_default_constructed() |
|
{ |
|
end_node.set_pointer(void_ptr(&end_node.up)); |
|
} |
|
|
|
size_type pool_size; |
|
node_type_base_t end_node; |
|
} internal_data; |
|
|
|
node_allocator_type &get_al() { return internal_data; } |
|
const node_allocator_type &get_al() const { return internal_data; } |
|
|
|
impl_type impl; |
|
/// @endcond |
|
}; |
|
|
|
template <typename T,typename A> |
|
bool operator==(const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); |
|
} |
|
|
|
template <typename T,typename A> |
|
bool operator< (const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); |
|
} |
|
|
|
template <typename T,typename A> |
|
bool operator!=(const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return !(x==y); |
|
} |
|
|
|
template <typename T,typename A> |
|
bool operator> (const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return y<x; |
|
} |
|
|
|
template <typename T,typename A> |
|
bool operator>=(const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return !(x<y); |
|
} |
|
|
|
template <typename T,typename A> |
|
bool operator<=(const stable_vector<T,A>& x,const stable_vector<T,A>& y) |
|
{ |
|
return !(x>y); |
|
} |
|
|
|
// specialized algorithms: |
|
|
|
template <typename T, typename A> |
|
void swap(stable_vector<T,A>& x,stable_vector<T,A>& y) |
|
{ |
|
x.swap(y); |
|
} |
|
|
|
/// @cond |
|
|
|
#undef STABLE_VECTOR_CHECK_INVARIANT |
|
|
|
/// @endcond |
|
|
|
}} |
|
|
|
#include <boost/container/detail/config_end.hpp> |
|
|
|
#endif //BOOST_CONTAINER_STABLE_VECTOR_HPP
|
|
|