//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. 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.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_CONTAINER_CONTAINER_VECTOR_HPP
#define BOOST_CONTAINER_CONTAINER_VECTOR_HPP

#if defined(_MSC_VER)
#  pragma once
#endif

#include <boost/container/detail/config_begin.hpp>
#include <boost/container/detail/workaround.hpp>
#include <boost/container/container_fwd.hpp>

#include <cstddef>
#include <memory>
#include <algorithm>
#include <iterator>
#include <utility>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/has_trivial_assign.hpp>
#include <boost/type_traits/has_nothrow_copy.hpp>
#include <boost/type_traits/has_nothrow_assign.hpp>
#include <boost/type_traits/has_nothrow_constructor.hpp>
#include <boost/container/container_fwd.hpp>
#include <boost/container/detail/version_type.hpp>
#include <boost/container/detail/allocation_type.hpp>
#include <boost/container/detail/utilities.hpp>
#include <boost/container/detail/iterators.hpp>
#include <boost/container/detail/algorithms.hpp>
#include <boost/container/detail/destroyers.hpp>
#include <boost/container/allocator_traits.hpp>
#include <boost/container/detail/allocator_version_traits.hpp>
#include <boost/container/throw_exception.hpp>
#include <boost/move/utility.hpp>
#include <boost/move/iterator.hpp>
#include <boost/move/detail/move_helpers.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/container/detail/mpl.hpp>
#include <boost/container/detail/type_traits.hpp>
#include <boost/container/detail/advanced_insert_int.hpp>
#include <boost/assert.hpp>

namespace boost {
namespace container {

/// @cond

//#define BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER

namespace container_detail {

#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER

template <class Pointer, bool IsConst>
class vec_iterator
{
   public:
	typedef std::random_access_iterator_tag                                          iterator_category;
   typedef typename boost::intrusive::pointer_traits<Pointer>::element_type         value_type;
   typedef typename boost::intrusive::pointer_traits<Pointer>::difference_type      difference_type;
   typedef typename if_c
      < IsConst
      , typename boost::intrusive::pointer_traits<Pointer>::template
                                 rebind_pointer<const value_type>::type
      , Pointer
      >::type                                                                       pointer;
   typedef typename if_c
      < IsConst
      , const value_type&
      , value_type&
      >::type                                                                       reference;

   /// @cond
   private:
   Pointer m_ptr;

   public:
   const Pointer &get_ptr() const BOOST_CONTAINER_NOEXCEPT
   {  return   m_ptr;  }

   Pointer &get_ptr() BOOST_CONTAINER_NOEXCEPT
   {  return   m_ptr;  }

   explicit vec_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT
      : m_ptr(ptr)
   {}
   /// @endcond

   public:

   //Constructors
   vec_iterator() BOOST_CONTAINER_NOEXCEPT
      #ifndef NDEBUG
      : m_ptr()
      #else
      // No value initialization of m_ptr() to speed up things a bit: 
      #endif
   {}

   vec_iterator(vec_iterator<Pointer, false> const& other) BOOST_CONTAINER_NOEXCEPT
      :  m_ptr(other.get_ptr())
   {}

   //Pointer like operators
   reference operator*()   const BOOST_CONTAINER_NOEXCEPT
   {  return *m_ptr;  }

   pointer operator->()  const BOOST_CONTAINER_NOEXCEPT
   {  return ::boost::intrusive::pointer_traits<pointer>::pointer_to(this->operator*());  }

   reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT
   {  return m_ptr[off];   }

   //Increment / Decrement
   vec_iterator& operator++() BOOST_CONTAINER_NOEXCEPT
   { ++m_ptr;  return *this; }

   vec_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT
   {  return vec_iterator(m_ptr++); }

   vec_iterator& operator--() BOOST_CONTAINER_NOEXCEPT
   {  --m_ptr; return *this;  }

   vec_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT
   {  return vec_iterator(m_ptr--); }

   //Arithmetic
   vec_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT
   {  m_ptr += off; return *this;   }

   vec_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT
   {  m_ptr -= off; return *this;   }

   friend vec_iterator operator+(const vec_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT
   {  return vec_iterator(x.m_ptr+off);  }

   friend vec_iterator operator+(difference_type off, vec_iterator right) BOOST_CONTAINER_NOEXCEPT
   {  right.m_ptr += off;  return right; }

   friend vec_iterator operator-(vec_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT
   {  left.m_ptr -= off;  return left; }

   friend difference_type operator-(const vec_iterator &left, const vec_iterator& right) BOOST_CONTAINER_NOEXCEPT
   {  return left.m_ptr - right.m_ptr;   }

   //Comparison operators
   friend bool operator==   (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr == r.m_ptr;  }

   friend bool operator!=   (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr != r.m_ptr;  }

   friend bool operator<    (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr < r.m_ptr;  }

   friend bool operator<=   (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr <= r.m_ptr;  }

   friend bool operator>    (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr > r.m_ptr;  }

   friend bool operator>=   (const vec_iterator& l, const vec_iterator& r) BOOST_CONTAINER_NOEXCEPT
   {  return l.m_ptr >= r.m_ptr;  }
};

}  //namespace container_detail {

template<class Pointer, bool IsConst>
const Pointer &vector_iterator_get_ptr(const container_detail::vec_iterator<Pointer, IsConst> &it) BOOST_CONTAINER_NOEXCEPT
{  return   it.get_ptr();  }

template<class Pointer, bool IsConst>
Pointer &get_ptr(container_detail::vec_iterator<Pointer, IsConst> &it) BOOST_CONTAINER_NOEXCEPT
{  return  it.get_ptr();  }

namespace container_detail {

#else //ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER

template< class MaybeConstPointer
        , bool ElementTypeIsConst
            = is_const< typename boost::intrusive::pointer_traits<MaybeConstPointer>::element_type>::value >
struct vector_get_ptr_pointer_to_non_const
{
   typedef MaybeConstPointer                                         const_pointer;
   typedef boost::intrusive::pointer_traits<const_pointer>           pointer_traits_t;
   typedef typename pointer_traits_t::element_type                   element_type;
   typedef typename remove_const<element_type>::type                 non_const_element_type;
   typedef typename pointer_traits_t
      ::template rebind_pointer<non_const_element_type>::type        return_type;

   static return_type get_ptr(const const_pointer &ptr) BOOST_CONTAINER_NOEXCEPT
   {  return boost::intrusive::pointer_traits<return_type>::const_cast_from(ptr);  }
};

template<class Pointer>
struct vector_get_ptr_pointer_to_non_const<Pointer, false>
{
   typedef const Pointer & return_type;
   static return_type get_ptr(const Pointer &ptr) BOOST_CONTAINER_NOEXCEPT
   {  return ptr;  }
};

}  //namespace container_detail {

template<class MaybeConstPointer>
typename container_detail::vector_get_ptr_pointer_to_non_const<MaybeConstPointer>::return_type
   vector_iterator_get_ptr(const MaybeConstPointer &ptr) BOOST_CONTAINER_NOEXCEPT
{
   return container_detail::vector_get_ptr_pointer_to_non_const<MaybeConstPointer>::get_ptr(ptr);
}

namespace container_detail {

#endif   //#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER

template <class T, class Allocator>
struct vector_value_traits
{
   typedef T value_type;
   typedef Allocator allocator_type;
   static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value;
   static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move<value_type>::value;
   static const bool trivial_copy = has_trivial_copy<value_type>::value;
   static const bool nothrow_copy = has_nothrow_copy<value_type>::value || trivial_copy;
   static const bool trivial_assign = has_trivial_assign<value_type>::value;
   static const bool nothrow_assign = has_nothrow_assign<value_type>::value || trivial_assign;

   //This is the anti-exception array destructor
   //to deallocate values already constructed
   typedef typename container_detail::if_c
      <trivial_dctr
      ,container_detail::null_scoped_destructor_n<Allocator>
      ,container_detail::scoped_destructor_n<Allocator>
      >::type   OldArrayDestructor;
   //This is the anti-exception array destructor
   //to destroy objects created with copy construction
   typedef typename container_detail::if_c
      <nothrow_copy
      ,container_detail::null_scoped_destructor_n<Allocator>
      ,container_detail::scoped_destructor_n<Allocator>
      >::type   ArrayDestructor;
   //This is the anti-exception array deallocator
   typedef typename container_detail::if_c
      <nothrow_copy
      ,container_detail::null_scoped_array_deallocator<Allocator>
      ,container_detail::scoped_array_deallocator<Allocator>
      >::type   ArrayDeallocator;
};

//!This struct deallocates and allocated memory
template < class Allocator
         , class AllocatorVersion = container_detail::integral_constant
            < unsigned
            , boost::container::container_detail::version<Allocator>::value
            >
         >
struct vector_alloc_holder
   : public Allocator
{
   private:
   BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder)

   public:
   typedef boost::container::allocator_traits<Allocator> allocator_traits_type;
   typedef typename allocator_traits_type::pointer       pointer;
   typedef typename allocator_traits_type::size_type     size_type;
   typedef typename allocator_traits_type::value_type    value_type;

   //Constructor, does not throw
   vector_alloc_holder()
      BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value)
      : Allocator(), m_start(), m_size(), m_capacity()
   {}

   //Constructor, does not throw
   template<class AllocConvertible>
   explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT
      : Allocator(boost::forward<AllocConvertible>(a)), m_start(), m_size(), m_capacity()
   {}

   //Constructor, does not throw
   template<class AllocConvertible>
   explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
      : Allocator(boost::forward<AllocConvertible>(a))
      , m_start()
      , m_size(initial_size)  //Size is initialized here so vector should only call uninitialized_xxx after this
      , m_capacity()
   {
      if(initial_size){
         m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first;
      }
   }

   //Constructor, does not throw
   explicit vector_alloc_holder(size_type initial_size)
      : Allocator()
      , m_start()
      , m_size(initial_size)  //Size is initialized here so vector should only call uninitialized_xxx after this
      , m_capacity()
   {
      if(initial_size){
         m_start = this->allocation_command
               (allocate_new, initial_size, initial_size, m_capacity, m_start).first;
      }
   }

   vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT
      : Allocator(boost::move(static_cast<Allocator&>(holder)))
      , m_start(holder.m_start)
      , m_size(holder.m_size)
      , m_capacity(holder.m_capacity)
   {
      holder.m_start = pointer();
      holder.m_size = holder.m_capacity = 0;
   }

   void first_allocation(size_type cap)
   {
      if(cap){
         m_start = this->allocation_command
               (allocate_new, cap, cap, m_capacity, m_start).first;
      }
   }

   void first_allocation_same_allocator_type(size_type cap)
   {  this->first_allocation(cap);  }

   ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT
   {
      if(this->m_capacity){
         this->alloc().deallocate(this->m_start, this->m_capacity);
      }
   }

   std::pair<pointer, bool>
      allocation_command(allocation_type command,
                         size_type limit_size,
                         size_type preferred_size,
                         size_type &received_size, const pointer &reuse = pointer())
   {
      return allocator_version_traits<Allocator>::allocation_command
         (this->alloc(), command, limit_size, preferred_size, received_size, reuse);
   }

   size_type next_capacity(size_type additional_objects) const
   {
      std::size_t num_objects   = this->m_size + additional_objects;
      std::size_t next_cap = this->m_capacity + this->m_capacity/2;
      return num_objects > next_cap ? num_objects : next_cap;/*
      return get_next_capacity( allocator_traits_type::max_size(this->m_holder.alloc())
                              , this->m_capacity, additional_objects);*/
   }

   pointer     m_start;
   size_type   m_size;
   size_type   m_capacity;

   void swap(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT
   {
      boost::container::swap_dispatch(this->m_start, x.m_start);
      boost::container::swap_dispatch(this->m_size, x.m_size);
      boost::container::swap_dispatch(this->m_capacity, x.m_capacity);
   }

   void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT
   {
      this->m_start     = x.m_start;
      this->m_size      = x.m_size;
      this->m_capacity  = x.m_capacity;
      x.m_start = pointer();
      x.m_size = x.m_capacity = 0;
   }

   Allocator &alloc() BOOST_CONTAINER_NOEXCEPT
   {  return *this;  }

   const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT
   {  return *this;  }

   const pointer   &start() const     BOOST_CONTAINER_NOEXCEPT {  return m_start;  }
   const size_type &capacity() const  BOOST_CONTAINER_NOEXCEPT {  return m_capacity;  }
   void start(const pointer &p)       BOOST_CONTAINER_NOEXCEPT {  m_start = p;  }
   void capacity(const size_type &c)  BOOST_CONTAINER_NOEXCEPT {  m_capacity = c;  }
};

//!This struct deallocates and allocated memory
template <class Allocator>
struct vector_alloc_holder<Allocator, container_detail::integral_constant<unsigned, 0> >
   : public Allocator
{
   private:
   BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder)

   public:
   typedef boost::container::allocator_traits<Allocator> allocator_traits_type;
   typedef typename allocator_traits_type::pointer       pointer;
   typedef typename allocator_traits_type::size_type     size_type;
   typedef typename allocator_traits_type::value_type    value_type;

   template <class OtherAllocator, class OtherAllocatorVersion>
   friend struct vector_alloc_holder;

   //Constructor, does not throw
   vector_alloc_holder()
      BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value)
      : Allocator(), m_size()
   {}

   //Constructor, does not throw
   template<class AllocConvertible>
   explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT
      : Allocator(boost::forward<AllocConvertible>(a)), m_size()
   {}

   //Constructor, does not throw
   template<class AllocConvertible>
   explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size)
      : Allocator(boost::forward<AllocConvertible>(a))
      , m_size(initial_size)  //Size is initialized here...
   {
      //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor
      this->first_allocation(initial_size);
   }

   //Constructor, does not throw
   explicit vector_alloc_holder(size_type initial_size)
      : Allocator()
      , m_size(initial_size)  //Size is initialized here...
   {
      //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor
      this->first_allocation(initial_size);
   }

   vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder)
      : Allocator(boost::move(static_cast<Allocator&>(holder)))
      , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this
   {
      ::boost::container::uninitialized_move_alloc_n
         (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start()));
   }

   template<class OtherAllocator, class OtherAllocatorVersion>
   vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END holder)
      : Allocator()
      , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort
   {
      //Different allocator type so we must check we have enough storage
      const size_type n = holder.m_size;
      this->first_allocation(n);
      ::boost::container::uninitialized_move_alloc_n
         (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start()));
   }

   void first_allocation(size_type cap)
   {
      if(cap > Allocator::internal_capacity){
         throw_bad_alloc();
      }
   }

   void first_allocation_same_allocator_type(size_type) BOOST_CONTAINER_NOEXCEPT
   {}

   //Destructor
   ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT
   {}

   void swap(vector_alloc_holder &x)
   {
      this->priv_swap_members_impl(x);
   }

   template<class OtherAllocator, class OtherAllocatorVersion>
   void swap(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x)
   {
      if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){
         throw_bad_alloc();
      }
      this->priv_swap_members_impl(x);
   }

   void move_from_empty(vector_alloc_holder &)
   {  //Containers with version 0 allocators can't be moved without move elements one by one
      throw_bad_alloc();
   }

   Allocator &alloc() BOOST_CONTAINER_NOEXCEPT
   {  return *this;  }

   const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT
   {  return *this;  }

   pointer start() const       BOOST_CONTAINER_NOEXCEPT {  return Allocator::internal_storage();  }
   size_type  capacity() const BOOST_CONTAINER_NOEXCEPT {  return Allocator::internal_capacity;  }
   size_type   m_size;

   private:

   template<class OtherAllocator, class OtherAllocatorVersion>
   void priv_swap_members_impl(vector_alloc_holder<OtherAllocator, OtherAllocatorVersion> &x)
   {
      const std::size_t MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity;
      value_type *const first_this = container_detail::to_raw_pointer(this->start());
      value_type *const first_x = container_detail::to_raw_pointer(x.start());

      if(this->m_size < x.m_size){
         boost::container::deep_swap_alloc_n<MaxTmpStorage>(this->alloc(), first_this, this->m_size, first_x, x.m_size);
      }
      else{
         boost::container::deep_swap_alloc_n<MaxTmpStorage>(this->alloc(), first_x, x.m_size, first_this, this->m_size);
      }
      boost::container::swap_dispatch(this->m_size, x.m_size);
   }
};

}  //namespace container_detail {

/// @endcond

//! \class vector
//! A vector is a sequence that supports random access to elements, constant
//! time insertion and removal of elements at the end, and linear time insertion
//! and removal of elements at the beginning or in the middle. The number of
//! elements in a vector may vary dynamically; memory management is automatic.
//! boost::container::vector is similar to std::vector but it's compatible
//! with shared memory and memory mapped files.
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
template <class T, class Allocator = std::allocator<T> >
#else
template <class T, class Allocator>
#endif
class vector
{
   /// @cond
   typedef container_detail::integral_constant
      <unsigned, boost::container::container_detail::version
         <Allocator>::value >                               alloc_version;
   boost::container::container_detail::vector_alloc_holder
      <Allocator, alloc_version>                            m_holder;
   typedef allocator_traits<Allocator>                      allocator_traits_type;
   template <class U, class UAllocator>
   friend class vector;

   typedef typename ::boost::container::allocator_traits
      <Allocator>::pointer                                     pointer_impl;
   typedef container_detail::vec_iterator<pointer_impl, false> iterator_impl;
   typedef container_detail::vec_iterator<pointer_impl, true > const_iterator_impl;

   /// @endcond
   public:
   //////////////////////////////////////////////
   //
   //                    types
   //
   //////////////////////////////////////////////

   typedef T                                                                           value_type;
   typedef typename ::boost::container::allocator_traits<Allocator>::pointer           pointer;
   typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer     const_pointer;
   typedef typename ::boost::container::allocator_traits<Allocator>::reference         reference;
   typedef typename ::boost::container::allocator_traits<Allocator>::const_reference   const_reference;
   typedef typename ::boost::container::allocator_traits<Allocator>::size_type         size_type;
   typedef typename ::boost::container::allocator_traits<Allocator>::difference_type   difference_type;
   typedef Allocator                                                                   allocator_type;
   typedef Allocator                                                                   stored_allocator_type;
   #if defined BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
   typedef BOOST_CONTAINER_IMPDEF(pointer)                                             iterator;
   typedef BOOST_CONTAINER_IMPDEF(const_pointer)                                       const_iterator;
   #else
   typedef BOOST_CONTAINER_IMPDEF(iterator_impl)                                       iterator;
   typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl)                                 const_iterator;
   #endif
   typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator<iterator>)                     reverse_iterator;
   typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator<const_iterator>)               const_reverse_iterator;

   /// @cond
   private:
   BOOST_COPYABLE_AND_MOVABLE(vector)
   typedef container_detail::vector_value_traits<value_type, Allocator> value_traits;

   typedef container_detail::integral_constant<unsigned, 0> allocator_v0;
   typedef container_detail::integral_constant<unsigned, 1> allocator_v1;
   typedef container_detail::integral_constant<unsigned, 2> allocator_v2;

   typedef constant_iterator<T, difference_type>            cvalue_iterator;
   /// @endcond

   public:
   //////////////////////////////////////////////
   //
   //          construct/copy/destroy
   //
   //////////////////////////////////////////////

   //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor throws.
   //!
   //! <b>Complexity</b>: Constant.
   vector()
      BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor<Allocator>::value)
      : m_holder()
   {}

   //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
   //!
   //! <b>Throws</b>: Nothing
   //!
   //! <b>Complexity</b>: Constant.
   explicit vector(const Allocator& a) BOOST_CONTAINER_NOEXCEPT
      : m_holder(a)
   {}

   //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
   //!   and inserts n value initialized values.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's default constructor throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   explicit vector(size_type n)
      :  m_holder(n)
   {
      boost::container::uninitialized_value_init_alloc_n
         (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
   //!   and inserts n default initialized values.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's default constructor throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   //!
   //! <b>Note</b>: Non-standard extension
   explicit vector(size_type n, default_init_t)
      :  m_holder(n)
   {
      boost::container::uninitialized_default_init_alloc_n
         (this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Constructs a vector
   //!   and inserts n copies of value.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   vector(size_type n, const T& value)
      :  m_holder(n)
   {
      boost::container::uninitialized_fill_alloc_n
         (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
   //!   and inserts n copies of value.
   //!
   //! <b>Throws</b>: If allocation
   //!   throws or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   vector(size_type n, const T& value, const allocator_type& a)
      :  m_holder(a, n)
   {
      boost::container::uninitialized_fill_alloc_n
         (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Constructs a vector
   //!   and inserts a copy of the range [first, last) in the vector.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's constructor taking an dereferenced InIt throws.
   //!
   //! <b>Complexity</b>: Linear to the range [first, last).
   template <class InIt>
   vector(InIt first, InIt last)
      :  m_holder()
   {  this->insert(this->cend(), first, last); }

   //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
   //!   and inserts a copy of the range [first, last) in the vector.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's constructor taking an dereferenced InIt throws.
   //!
   //! <b>Complexity</b>: Linear to the range [first, last).
   template <class InIt>
   vector(InIt first, InIt last, const allocator_type& a)
      :  m_holder(a)
   {  this->insert(this->cend(), first, last); }

   //! <b>Effects</b>: Copy constructs a vector.
   //!
   //! <b>Postcondition</b>: x == *this.
   //!
   //! <b>Throws</b>: If allocator_type's default constructor or allocation
   //!   throws or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Linear to the elements x contains.
   vector(const vector &x)
      :  m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size())
   {
      ::boost::container::uninitialized_copy_alloc_n
         ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())
         , x.size(), container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
   //!
   //! <b>Throws</b>: Nothing
   //!
   //! <b>Complexity</b>: Constant.
   vector(BOOST_RV_REF(vector) mx) BOOST_CONTAINER_NOEXCEPT
      :  m_holder(boost::move(mx.m_holder))
   {}

   #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)

   //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
   //!
   //! <b>Throws</b>: If T's move constructor or allocation throws
   //!
   //! <b>Complexity</b>: Linear.
   //!
   //! <b>Note</b>: Non-standard extension
   template<class OtherAllocator>
   vector(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END mx)
      :  m_holder(boost::move(mx.m_holder))
   {}

   #endif   //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED)

   //! <b>Effects</b>: Copy constructs a vector using the specified allocator.
   //!
   //! <b>Postcondition</b>: x == *this.
   //!
   //! <b>Throws</b>: If allocation
   //!   throws or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Linear to the elements x contains.
   vector(const vector &x, const allocator_type &a)
      :  m_holder(a, x.size())
   {
      ::boost::container::uninitialized_copy_alloc_n_source
         ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start())
         , x.size(), container_detail::to_raw_pointer(this->m_holder.start()));
   }

   //! <b>Effects</b>: Move constructor using the specified allocator.
   //!                 Moves mx's resources to *this if a == allocator_type().
   //!                 Otherwise copies values from x to *this.
   //!
   //! <b>Throws</b>: If allocation or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Constant if a == mx.get_allocator(), linear otherwise.
   vector(BOOST_RV_REF(vector) mx, const allocator_type &a)
      :  m_holder(a)
   {
      if(mx.m_holder.alloc() == a){
         this->m_holder.move_from_empty(mx.m_holder);
      }
      else{
         const size_type n = mx.size();
         this->m_holder.first_allocation_same_allocator_type(n);
         ::boost::container::uninitialized_move_alloc_n_source
            ( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start())
            , n, container_detail::to_raw_pointer(this->m_holder.start()));
         this->m_holder.m_size = n;
      }
   }

   //! <b>Effects</b>: Destroys the vector. All stored values are destroyed
   //!   and used memory is deallocated.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Linear to the number of elements.
   ~vector() BOOST_CONTAINER_NOEXCEPT
   {
      boost::container::destroy_alloc_n
         (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size);
      //vector_alloc_holder deallocates the data
   } 

   //! <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/move constructor/assignment throws.
   //!
   //! <b>Complexity</b>: Linear to the number of elements in x.
   vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x)
   {
      if (&x != this){
         this->priv_copy_assign(boost::move(x), alloc_version());
      }
      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>: Nothing
   //!
   //! <b>Complexity</b>: Linear.
   vector& operator=(BOOST_RV_REF(vector) x)
      //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable<allocator_type>::value);)
      BOOST_CONTAINER_NOEXCEPT
   {
      this->priv_move_assign(boost::move(x), alloc_version());
      return *this;
   }

   #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)

   //! <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 move constructor/assignment of T throws or allocation throws
   //!
   //! <b>Complexity</b>: Linear.
   template<class OtherAllocator, class OtherAllocatorVersion>
   vector& operator=(BOOST_RV_REF_BEG vector<OtherAllocator, OtherAllocatorVersion> BOOST_RV_REF_END x)
   {
      this->priv_move_assign(boost::move(x), alloc_version());
      return *this;
   }

   #endif

   //! <b>Effects</b>: Assigns the the range [first, last) to *this.
   //!
   //! <b>Throws</b>: If memory allocation throws or T's copy/move constructor/assignment or
   //!   T's constructor/assignment from dereferencing InpIt throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   template <class InIt>
   void assign(InIt first, InIt last
      #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
      , typename container_detail::enable_if_c
         < !container_detail::is_convertible<InIt, size_type>::value
            //&& container_detail::is_input_iterator<InIt>::value
         >::type * = 0
      #endif
      )
   {
      //Overwrite all elements we can from [first, last)
      iterator cur = this->begin();
      const iterator end_it = this->end();
      for ( ; first != last && cur != end_it; ++cur, ++first){
         *cur = *first;
      }

      if (first == last){
         //There are no more elements in the sequence, erase remaining
         T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
         size_type n = static_cast<size_type>(end_pos - container_detail::to_raw_pointer(vector_iterator_get_ptr(cur)));
         this->priv_destroy_last_n(n);
      }
      else{
         //There are more elements in the range, insert the remaining ones
         this->insert(this->cend(), first, last);
      }
   }

   //! <b>Effects</b>: Assigns the n copies of val to *this.
   //!
   //! <b>Throws</b>: If memory allocation throws or
   //!   T's copy/move constructor/assignment throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   void assign(size_type n, const value_type& val)
   {  this->assign(cvalue_iterator(val, n), cvalue_iterator());   }

   //! <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 BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.alloc();  }

   //! <b>Effects</b>: Returns a reference to the internal allocator.
   //!
   //! <b>Throws</b>: Nothing
   //!
   //! <b>Complexity</b>: Constant.
   //!
   //! <b>Note</b>: Non-standard extension.
   stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT
   {  return this->m_holder.alloc(); }

   //! <b>Effects</b>: Returns a reference to the internal allocator.
   //!
   //! <b>Throws</b>: Nothing
   //!
   //! <b>Complexity</b>: Constant.
   //!
   //! <b>Note</b>: Non-standard extension.
   const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT
   {  return this->m_holder.alloc(); }

   //////////////////////////////////////////////
   //
   //                iterators
   //
   //////////////////////////////////////////////

   //! <b>Effects</b>: Returns an iterator to the first element contained in the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   iterator begin() BOOST_CONTAINER_NOEXCEPT
   { return iterator(this->m_holder.start()); }

   //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_iterator begin() const BOOST_CONTAINER_NOEXCEPT
   { return const_iterator(this->m_holder.start()); }

   //! <b>Effects</b>: Returns an iterator to the end of the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   iterator end() BOOST_CONTAINER_NOEXCEPT
   { return iterator(this->m_holder.start() + this->m_holder.m_size); }

   //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_iterator end() const BOOST_CONTAINER_NOEXCEPT
   { return this->cend(); }

   //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT
   { return reverse_iterator(this->end());      }

   //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT
   { return this->crbegin(); }

   //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT
   { return reverse_iterator(this->begin());       }

   //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT
   { return this->crend(); }

   //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT
   { return const_iterator(this->m_holder.start()); }

   //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_iterator cend() const BOOST_CONTAINER_NOEXCEPT
   { return const_iterator(this->m_holder.start() + this->m_holder.m_size); }

   //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT
   { return const_reverse_iterator(this->end());}

   //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
   //! of the reversed vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT
   { return const_reverse_iterator(this->begin()); }

   //////////////////////////////////////////////
   //
   //                capacity
   //
   //////////////////////////////////////////////

   //! <b>Effects</b>: Returns true if the vector contains no elements.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   bool empty() const BOOST_CONTAINER_NOEXCEPT
   { return !this->m_holder.m_size; }

   //! <b>Effects</b>: Returns the number of the elements contained in the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   size_type size() const BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.m_size; }

   //! <b>Effects</b>: Returns the largest possible size of the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   size_type max_size() const BOOST_CONTAINER_NOEXCEPT
   { return allocator_traits_type::max_size(this->m_holder.alloc()); }

   //! <b>Effects</b>: Inserts or erases elements at the end such that
   //!   the size becomes n. New elements are value initialized.
   //!
   //! <b>Throws</b>: If memory allocation throws, or T's constructor throws.
   //!
   //! <b>Complexity</b>: Linear to the difference between size() and new_size.
   void resize(size_type new_size)
   {
      const size_type sz = this->size();
      if (new_size < sz){
         //Destroy last elements
         this->priv_destroy_last_n(sz - new_size);
      }
      else{
         const size_type n = new_size - this->size();
         container_detail::insert_value_initialized_n_proxy<Allocator, T*> proxy(this->m_holder.alloc());
         this->priv_forward_range_insert_at_end(n, proxy, alloc_version());
      }
   }

   //! <b>Effects</b>: Inserts or erases elements at the end such that
   //!   the size becomes n. New elements are value initialized.
   //!
   //! <b>Throws</b>: If memory allocation throws, or T's constructor throws.
   //!
   //! <b>Complexity</b>: Linear to the difference between size() and new_size.
   //!
   //! <b>Note</b>: Non-standard extension
   void resize(size_type new_size, default_init_t)
   {
      const size_type sz = this->size();
      if (new_size < sz){
         //Destroy last elements
         this->priv_destroy_last_n(sz - new_size);
      }
      else{
         const size_type n = new_size - this->size();
         container_detail::insert_default_initialized_n_proxy<Allocator, T*> proxy(this->m_holder.alloc());
         this->priv_forward_range_insert_at_end(n, proxy, alloc_version());
      }
   }

   //! <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 new_size, const T& x)
   {
      const size_type sz = this->size();
      if (new_size < sz){
         //Destroy last elements
         this->priv_destroy_last_n(sz - new_size);
      }
      else{
         const size_type n = new_size - this->size();
         container_detail::insert_n_copies_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
         this->priv_forward_range_insert_at_end(n, proxy, alloc_version());
      }
   }

   //! <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 BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.capacity(); }

   //! <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 or T's copy/move constructor throws.
   void reserve(size_type new_cap)
   {
      if (this->capacity() < new_cap){
         this->priv_reserve(new_cap, alloc_version());
      }
   }

   //! <b>Effects</b>: Tries to deallocate the excess of memory created
   //!   with previous allocations. The size of the vector is unchanged
   //!
   //! <b>Throws</b>: If memory allocation throws, or T's copy/move constructor throws.
   //!
   //! <b>Complexity</b>: Linear to size().
   void shrink_to_fit()
   {  this->priv_shrink_to_fit(alloc_version());   }

   //////////////////////////////////////////////
   //
   //               element access
   //
   //////////////////////////////////////////////

   //! <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() BOOST_CONTAINER_NOEXCEPT
   { return *this->m_holder.start(); }

   //! <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 BOOST_CONTAINER_NOEXCEPT
   { return *this->m_holder.start(); }

   //! <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() BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.start()[this->m_holder.m_size - 1]; }

   //! <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 BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.start()[this->m_holder.m_size - 1]; }

   //! <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) BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.start()[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 BOOST_CONTAINER_NOEXCEPT
   { return this->m_holder.start()[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)
   { this->priv_check_range(n); return this->m_holder.start()[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>: std::range_error if n >= size()
   //!
   //! <b>Complexity</b>: Constant.
   const_reference at(size_type n) const
   { this->priv_check_range(n); return this->m_holder.start()[n]; }

   //////////////////////////////////////////////
   //
   //                 data access
   //
   //////////////////////////////////////////////

   //! <b>Returns</b>: Allocator pointer such that [data(),data() + size()) is a valid range.
   //!   For a non-empty vector, data() == &front().
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   T* data() BOOST_CONTAINER_NOEXCEPT
   { return container_detail::to_raw_pointer(this->m_holder.start()); }

   //! <b>Returns</b>: Allocator pointer such that [data(),data() + size()) is a valid range.
   //!   For a non-empty vector, data() == &front().
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   const T * data()  const BOOST_CONTAINER_NOEXCEPT
   { return container_detail::to_raw_pointer(this->m_holder.start()); }

   //////////////////////////////////////////////
   //
   //                modifiers
   //
   //////////////////////////////////////////////

   #if defined(BOOST_CONTAINER_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 vector.
   //!
   //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws or
   //!   T's move constructor throws.
   //!
   //! <b>Complexity</b>: Amortized constant time.
   template<class ...Args>
   void emplace_back(Args &&...args)
   {
      T* back_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
      if (this->m_holder.m_size < this->m_holder.capacity()){
         //There is more memory, just construct a new object at the end
         allocator_traits_type::construct(this->m_holder.alloc(), back_pos, ::boost::forward<Args>(args)...);
         ++this->m_holder.m_size;
      }
      else{
         typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type;
         this->priv_forward_range_insert_no_capacity
            (vector_iterator_get_ptr(this->cend()), 1, type(this->m_holder.alloc(), ::boost::forward<Args>(args)...), alloc_version());
      }
   }

   //! <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 or
   //!   T's move constructor/assignment 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
      typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type;
      return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1, type(this->m_holder.alloc()
                                            , ::boost::forward<Args>(args)...), alloc_version());
   }

   #else

   #define BOOST_PP_LOCAL_MACRO(n)                                                                    \
   BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >)             \
   void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _))                              \
   {                                                                                                  \
      T* back_pos = container_detail::to_raw_pointer                                                  \
         (this->m_holder.start()) + this->m_holder.m_size;                                            \
      if (this->m_holder.m_size < this->m_holder.capacity()){                                         \
         allocator_traits_type::construct (this->m_holder.alloc()                                     \
            , back_pos BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) );              \
         ++this->m_holder.m_size;                                                                     \
      }                                                                                               \
      else{                                                                                           \
         container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n)                                  \
            <Allocator, T* BOOST_PP_ENUM_TRAILING_PARAMS(n, P)> proxy                                 \
            (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _));  \
         this->priv_forward_range_insert_no_capacity                                                  \
            (vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version());                       \
      }                                                                                               \
   }                                                                                                  \
                                                                                                      \
   BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >)             \
   iterator emplace(const_iterator pos                                                                \
                    BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _))                      \
   {                                                                                                  \
      container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n)                                     \
         <Allocator, T* BOOST_PP_ENUM_TRAILING_PARAMS(n, P)> proxy                                    \
            (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _));  \
      return this->priv_forward_range_insert                                                          \
         (container_detail::to_raw_pointer(vector_iterator_get_ptr(pos)), 1, proxy, alloc_version()); \
   }                                                                                                  \
   //!
   #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS)
   #include BOOST_PP_LOCAL_ITERATE()

   #endif   //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING

   #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
   //! <b>Effects</b>: Inserts a copy of x at the end of the vector.
   //!
   //! <b>Throws</b>: If memory allocation throws or
   //!   T's copy/move constructor throws.
   //!
   //! <b>Complexity</b>: Amortized constant time.
   void push_back(const T &x);

   //! <b>Effects</b>: Constructs a new element in the end of the vector
   //!   and moves the resources of mx to this new element.
   //!
   //! <b>Throws</b>: If memory allocation throws or
   //!   T's move constructor throws.
   //!
   //! <b>Complexity</b>: Amortized constant time.
   void push_back(T &&x);
   #else
   BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back)
   #endif
 
   #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
   //! <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 T's copy/move constructor/assignment throws.
   //!
   //! <b>Complexity</b>: If position is end(), amortized constant time
   //!   Linear time otherwise.
   iterator insert(const_iterator position, const T &x);

   //! <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, T &&x);
   #else
   BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator)
   #endif

   //! <b>Requires</b>: p must be a valid iterator of *this.
   //!
   //! <b>Effects</b>: Insert n copies of x before pos.
   //!
   //! <b>Returns</b>: an iterator to the first inserted element or p if n is 0.
   //!
   //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
   //!
   //! <b>Complexity</b>: Linear to n.
   iterator insert(const_iterator p, size_type n, const T& x)
   {
      container_detail::insert_n_copies_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
      return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy, alloc_version());
   }

   //! <b>Requires</b>: p must be a valid iterator of *this.
   //!
   //! <b>Effects</b>: Insert a copy of the [first, last) range before pos.
   //!
   //! <b>Returns</b>: an iterator to the first inserted element or pos if first == last.
   //!
   //! <b>Throws</b>: If memory allocation throws, T's constructor from a
   //!   dereferenced InpIt throws or T's copy/move constructor/assignment throws.
   //!
   //! <b>Complexity</b>: Linear to std::distance [first, last).
   template <class InIt>
   iterator insert(const_iterator pos, InIt first, InIt last
      #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
      , typename container_detail::enable_if_c
         < !container_detail::is_convertible<InIt, size_type>::value
            && container_detail::is_input_iterator<InIt>::value
         >::type * = 0
      #endif
      )
   {
      const size_type n_pos = pos - this->cbegin();
      iterator it(vector_iterator_get_ptr(pos));
      for(;first != last; ++first){
         it = this->emplace(it, *first);
         ++it;
      }
      return iterator(this->m_holder.start() + n_pos);
   }

   #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
   template <class FwdIt>
   iterator insert(const_iterator pos, FwdIt first, FwdIt last
      , typename container_detail::enable_if_c
         < !container_detail::is_convertible<FwdIt, size_type>::value
            && !container_detail::is_input_iterator<FwdIt>::value
         >::type * = 0
      )
   {
      container_detail::insert_range_proxy<Allocator, FwdIt, T*> proxy(this->m_holder.alloc(), first);
      return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), std::distance(first, last), proxy, alloc_version());
   }
   #endif

   //! <b>Effects</b>: Removes the last element from the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant time.
   void pop_back() BOOST_CONTAINER_NOEXCEPT
   {
      //Destroy last element
      --this->m_holder.m_size;
      this->priv_destroy(container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size);
   }

   //! <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)
   {
      T *const pos = container_detail::to_raw_pointer(vector_iterator_get_ptr(position));
      T *const beg = container_detail::to_raw_pointer(this->m_holder.start());
      //Move elements forward and destroy last
      this->priv_destroy(::boost::move(pos + 1, beg + this->m_holder.m_size, pos));
      --this->m_holder.m_size;
      return iterator(vector_iterator_get_ptr(position));
   }

   //! <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)
   {
      if (first != last){
         T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
         T* const ptr = container_detail::to_raw_pointer(boost::move
            (container_detail::to_raw_pointer(vector_iterator_get_ptr(last))
            ,end_pos
            ,container_detail::to_raw_pointer(vector_iterator_get_ptr(first))
            ));
         const size_type destroyed = (end_pos - ptr);
         boost::container::destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed);
         this->m_holder.m_size -= destroyed;
      }
      return iterator(vector_iterator_get_ptr(first));
   }

   //! <b>Effects</b>: Swaps the contents of *this and x.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Constant.
   void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_same<alloc_version, allocator_v0>::value))
   {
      //Just swap internals in case of !allocator_v0. Otherwise, deep swap
      this->m_holder.swap(x.m_holder);
      //And now the allocator
      container_detail::bool_<allocator_traits_type::propagate_on_container_swap::value> flag;
      container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), flag);
   }

   #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED

   //! <b>Effects</b>: Swaps the contents of *this and x.
   //!
   //! <b>Throws</b>: If T's move constructor throws.
   //!
   //! <b>Complexity</b>: Linear
   //!
   //! <b>Note</b>: non-standard extension.
   template<class OtherAllocator>
   void swap(vector<T, OtherAllocator> & x)
   {
      this->m_holder.swap(x.m_holder);
   }

   #endif   //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED

   //! <b>Effects</b>: Erases all the elements of the vector.
   //!
   //! <b>Throws</b>: Nothing.
   //!
   //! <b>Complexity</b>: Linear to the number of elements in the vector.
   void clear() BOOST_CONTAINER_NOEXCEPT
   {  this->priv_destroy_all();  }

   /// @cond

   //Absolutely experimental. This function might change, disappear or simply crash!
   template<class BiDirPosConstIt, class BiDirValueIt>
   void insert_ordered_at(size_type element_count, BiDirPosConstIt last_position_it, BiDirValueIt last_value_it)
   {
      const size_type *dummy = 0;
      this->priv_insert_ordered_at(element_count, last_position_it, false, &dummy[0], last_value_it);
   }

   //Absolutely experimental. This function might change, disappear or simply crash!
   template<class BiDirPosConstIt, class BiDirSkipConstIt, class BiDirValueIt>
   void insert_ordered_at(size_type element_count, BiDirPosConstIt last_position_it, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it)
   {
      this->priv_insert_ordered_at(element_count, last_position_it, true, last_skip_it, last_value_it);
   }

   private:

   template<class OtherAllocator, class AllocVersion>
   void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
      , AllocVersion
      , typename container_detail::enable_if_c
         < container_detail::is_same<AllocVersion, allocator_v0>::value &&
           !container_detail::is_same<OtherAllocator, allocator_type>::value
         >::type * = 0)
   {
      if(this->capacity() < x.size()){
         throw_bad_alloc();
      }
      this->priv_move_assign_impl(boost::move(x), AllocVersion());
   }

   template<class OtherAllocator, class AllocVersion>
   void priv_move_assign(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
      , AllocVersion
      , typename container_detail::enable_if_c
         < !container_detail::is_same<AllocVersion, allocator_v0>::value ||
           container_detail::is_same<OtherAllocator, allocator_type>::value
         >::type * = 0)
   {
      this->priv_move_assign_impl(boost::move(x), AllocVersion());
   }

   template<class OtherAllocator, class AllocVersion>
   void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
      , AllocVersion
      , typename container_detail::enable_if_c
         < container_detail::is_same<AllocVersion, allocator_v0>::value
         >::type * = 0)
   {
      T* const this_start  = container_detail::to_raw_pointer(m_holder.start());
      T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
      const size_type this_sz  = m_holder.m_size;
      const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
      boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz);
      this->m_holder.m_size = other_sz;
   }

   template<class OtherAllocator, class AllocVersion>
   void priv_move_assign_impl(BOOST_RV_REF_BEG vector<T, OtherAllocator> BOOST_RV_REF_END x
      , AllocVersion
      , typename container_detail::enable_if_c
         < !container_detail::is_same<AllocVersion, allocator_v0>::value
         >::type * = 0)
   {
      //for move constructor, no aliasing (&x != this) is assummed.
      allocator_type &this_alloc = this->m_holder.alloc();
      allocator_type &x_alloc    = x.m_holder.alloc();
      //If allocators are equal we can just swap pointers
      if(this_alloc == x_alloc){
         //Destroy objects but retain memory in case x reuses it in the future
         this->clear();
         this->m_holder.swap(x.m_holder);
         //Move allocator if needed
         container_detail::bool_<allocator_traits_type::
            propagate_on_container_move_assignment::value> flag;
         container_detail::move_alloc(this_alloc, x_alloc, flag);
      }
      //If unequal allocators, then do a one by one move
      else{
         //TO-DO: optimize this
         this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start()))
                     , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)));
      }
   }

   template<class AllocVersion>
   void priv_copy_assign(const vector &x, AllocVersion
      , typename container_detail::enable_if_c
         < container_detail::is_same<AllocVersion, allocator_v0>::value
         >::type * = 0)
   {
      T* const this_start  = container_detail::to_raw_pointer(m_holder.start());
      T* const other_start = container_detail::to_raw_pointer(x.m_holder.start());
      const size_type this_sz  = m_holder.m_size;
      const size_type other_sz = static_cast<size_type>(x.m_holder.m_size);
      boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz);
      this->m_holder.m_size = other_sz;
   }

   template<class AllocVersion>
   void priv_copy_assign(const vector &x, AllocVersion
      , typename container_detail::enable_if_c
         < !container_detail::is_same<AllocVersion, allocator_v0>::value
         >::type * = 0)
   {
      allocator_type &this_alloc     = this->m_holder.alloc();
      const allocator_type &x_alloc  = x.m_holder.alloc();
      container_detail::bool_<allocator_traits_type::
         propagate_on_container_copy_assignment::value> flag;
      if(flag && this_alloc != x_alloc){
         this->clear();
         this->shrink_to_fit();
      }
      container_detail::assign_alloc(this_alloc, x_alloc, flag);
      this->assign( container_detail::to_raw_pointer(x.m_holder.start())
                  , container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size));
   }

   void priv_reserve(size_type, allocator_v0)
   {
      throw_bad_alloc();
   }

   void priv_reserve(size_type new_cap, allocator_v1)
   {
      //There is not enough memory, allocate a new buffer
      pointer p = this->m_holder.allocate(new_cap);
      //Backwards (and possibly forward) expansion
      #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
      ++this->num_alloc;
      #endif
      T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start());
      const size_type sz = m_holder.m_size;
      ::boost::container::uninitialized_move_alloc_n_source
         ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) );
      if(this->m_holder.capacity()){
         if(!value_traits::trivial_dctr_after_move)
            boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz);
         this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity());
      }
      this->m_holder.start(p);
      this->m_holder.capacity(new_cap);
   }

   void priv_reserve(size_type new_cap, allocator_v2)
   {
      //There is not enough memory, allocate a new
      //buffer or expand the old one.
      bool same_buffer_start;
      size_type real_cap = 0;
      std::pair<pointer, bool> ret =
         this->m_holder.allocation_command
            (allocate_new | expand_fwd | expand_bwd,
               new_cap, new_cap, real_cap, this->m_holder.start());

      //Check for forward expansion
      same_buffer_start = ret.second && this->m_holder.start() == ret.first;
      if(same_buffer_start){
         #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
         ++this->num_expand_fwd;
         #endif
         this->m_holder.capacity(real_cap);
      }
      //If there is no forward expansion, move objects
      else{
         //Backwards (and possibly forward) expansion
         if(ret.second){
            //We will reuse insert code, so create a dummy input iterator
            container_detail::insert_range_proxy<Allocator, boost::move_iterator<T*>, T*>
               proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0));
            #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
            ++this->num_expand_bwd;
            #endif
            this->priv_forward_range_insert_expand_backwards
               ( container_detail::to_raw_pointer(ret.first)
               , real_cap
               , container_detail::to_raw_pointer(this->m_holder.start())
               , 0
               , proxy);
         }
         //New buffer
         else{
            #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
            ++this->num_alloc;
            #endif
            T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start());
            const size_type sz = m_holder.m_size;
            ::boost::container::uninitialized_move_alloc_n_source
               ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) );
            if(this->m_holder.capacity()){
               if(!value_traits::trivial_dctr_after_move)
                  boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz);
               this->m_holder.deallocate(this->m_holder.start(), this->m_holder.capacity());
            }
            this->m_holder.start(ret.first);
            this->m_holder.capacity(real_cap);
         }
      }
   }

   template<class Proxy>
   void priv_uninitialized_fill(Proxy proxy, size_type n) const
   {
      //Copy first new elements in pos
      proxy.uninitialized_copy_n_and_update
         (container_detail::to_raw_pointer(this->m_holder.start()), n);
      //m_holder.size was already initialized to n in vector_alloc_holder's constructor
   }

   void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT
   {
      if(!value_traits::trivial_dctr)
         allocator_traits_type::destroy(this->get_stored_allocator(), p);
   }

   void priv_destroy_last_n(size_type n) BOOST_CONTAINER_NOEXCEPT
   {
      T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
      boost::container::destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n);
      this->m_holder.m_size -= n;
   }

   void priv_destroy_all() BOOST_CONTAINER_NOEXCEPT
   {
      boost::container::destroy_alloc_n
         (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size);
      this->m_holder.m_size = 0;
   }

   template<class U>
   iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x)
   {
      return this->priv_forward_range_insert
         ( vector_iterator_get_ptr(p), 1, container_detail::get_insert_value_proxy<T*>(this->m_holder.alloc()
         , ::boost::forward<U>(x)), alloc_version());
   }

   void priv_push_back(const T &x)
   {
      if (this->m_holder.m_size < this->m_holder.capacity()){
         //There is more memory, just construct a new object at the end
         allocator_traits_type::construct
            ( this->m_holder.alloc()
            , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size)
            , x );
         ++this->m_holder.m_size;
      }
      else{
         container_detail::insert_copy_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
         this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version());
      }
   }

   void priv_push_back(BOOST_RV_REF(T) x)
   {
      if (this->m_holder.m_size < this->m_holder.capacity()){
         //There is more memory, just construct a new object at the end
         allocator_traits_type::construct
            ( this->m_holder.alloc()
            , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size)
            , ::boost::move(x) );
         ++this->m_holder.m_size;
      }
      else{
         container_detail::insert_move_proxy<Allocator, T*> proxy(this->m_holder.alloc(), x);
         this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version());
      }
   }

   void priv_shrink_to_fit(allocator_v0) BOOST_CONTAINER_NOEXCEPT
   {}

   void priv_shrink_to_fit(allocator_v1)
   {
      const size_type cp = this->m_holder.capacity();
      if(cp){
         const size_type sz = this->size();
         if(!sz){
            this->m_holder.alloc().deallocate(this->m_holder.m_start, cp);
            this->m_holder.m_start     = pointer();
            this->m_holder.m_capacity  = 0;
         }
         else if(sz < cp){
            //Allocate a new buffer.
            pointer p = this->m_holder.allocate(sz);

            //We will reuse insert code, so create a dummy input iterator
            container_detail::insert_range_proxy<Allocator, boost::move_iterator<T*>, T*>
               proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0));
            #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
            ++this->num_alloc;
            #endif
            this->priv_forward_range_insert_new_allocation
               ( container_detail::to_raw_pointer(p)
               , sz
               , container_detail::to_raw_pointer(this->m_holder.start())
               , 0
               , proxy);
         }
      }
   }

   void priv_shrink_to_fit(allocator_v2) BOOST_CONTAINER_NOEXCEPT
   {
      const size_type cp = this->m_holder.capacity();
      if(cp){
         const size_type sz = this->size();
         if(!sz){
            this->m_holder.alloc().deallocate(this->m_holder.m_start, cp);
            this->m_holder.m_start     = pointer();
            this->m_holder.m_capacity  = 0;
         }
         else{
            size_type received_size;
            if(this->m_holder.allocation_command
               ( shrink_in_place | nothrow_allocation
               , cp, sz, received_size, this->m_holder.start()).first){
               this->m_holder.capacity(received_size);
               #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
               ++this->num_shrink;
               #endif
            }
         }
      }
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert_no_capacity
      (const pointer &pos, const size_type, const InsertionProxy , allocator_v0)
   {
      throw_bad_alloc();
      return iterator(pos);
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert_no_capacity
      (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1)
   {
      //Check if we have enough memory or try to expand current memory
      const size_type n_pos = pos - this->m_holder.start();
      T *const raw_pos = container_detail::to_raw_pointer(pos);

      const size_type new_cap = this->m_holder.next_capacity(n);
      T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap));
      #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
      ++this->num_alloc;
      #endif
      this->priv_forward_range_insert_new_allocation
         ( new_buf, new_cap, raw_pos, n, insert_range_proxy);
      return iterator(this->m_holder.start() + n_pos);
   }


   template <class InsertionProxy>
   iterator priv_forward_range_insert_no_capacity
      (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2)
   {
      //Check if we have enough memory or try to expand current memory
      T *const raw_pos = container_detail::to_raw_pointer(pos);
      const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start());

      size_type real_cap = 0;
      //There is not enough memory, allocate a new
      //buffer or expand the old one.
      std::pair<pointer, bool> ret = (this->m_holder.allocation_command
            (allocate_new | expand_fwd | expand_bwd,
               this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start()));

      //Buffer reallocated
      if(ret.second){
         //Forward expansion, delay insertion
         if(this->m_holder.start() == ret.first){
            #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
            ++this->num_expand_fwd;
            #endif
            this->m_holder.capacity(real_cap);
            //Expand forward
            this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
         }
         //Backwards (and possibly forward) expansion
         else{
            #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
            ++this->num_expand_bwd;
            #endif
            this->priv_forward_range_insert_expand_backwards
               ( container_detail::to_raw_pointer(ret.first)
               , real_cap, raw_pos, n, insert_range_proxy);
         }
      }
      //New buffer
      else{
         #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
         ++this->num_alloc;
         #endif
         this->priv_forward_range_insert_new_allocation
            ( container_detail::to_raw_pointer(ret.first)
            , real_cap, raw_pos, n, insert_range_proxy);
      }

      return iterator(this->m_holder.start() + n_pos);
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert
      (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0)
   {
      //Check if we have enough memory or try to expand current memory
      const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;

      if (n > remaining){
         //This will trigger an error
         throw_bad_alloc();
      }
      const size_type n_pos = pos - this->m_holder.start();
      T *const raw_pos = container_detail::to_raw_pointer(pos);
      this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
      return iterator(this->m_holder.start() + n_pos);
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert
      (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1)
   {
      //Check if we have enough memory or try to expand current memory
      const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;
      T *const raw_pos = container_detail::to_raw_pointer(pos);

      if (n <= remaining){
         const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start());
         this->priv_forward_range_insert_expand_forward
            (raw_pos, n, insert_range_proxy);
         return iterator(this->m_holder.start() + n_pos);
      }
      else{
         return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version());
      }
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert
      (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2)
   {
      //Check if we have enough memory or try to expand current memory
      const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;

      bool same_buffer_start = n <= remaining;
      if (!same_buffer_start){
         return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version());
      }
      else{
         //Expand forward
         T *const raw_pos = container_detail::to_raw_pointer(pos);
         const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start());
         this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy);
         return iterator(this->m_holder.start() + n_pos);
      }
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert_at_end
      (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0)
   {
      //Check if we have enough memory or try to expand current memory
      const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size;

      if (n > remaining){
         //This will trigger an error
         throw_bad_alloc();
      }
      this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy);
      return this->end();
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert_at_end
      (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1)
   {
      return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v1());
   }

   template <class InsertionProxy>
   iterator priv_forward_range_insert_at_end
      (const size_type n, const InsertionProxy insert_range_proxy, allocator_v2)
   {
      return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v2());
   }

   //Absolutely experimental. This function might change, disappear or simply crash!
   template<class BiDirPosConstIt, class BiDirSkipConstIt, class BiDirValueIt>
   void priv_insert_ordered_at( size_type element_count, BiDirPosConstIt last_position_it
                              , bool do_skip, BiDirSkipConstIt last_skip_it, BiDirValueIt last_value_it)
   {
      const size_type old_size_pos = this->size();
      this->reserve(old_size_pos + element_count);
      T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start());
      size_type insertions_left = element_count;
      size_type next_pos = old_size_pos;
      size_type hole_size = element_count;

      //Exception rollback. If any copy throws before the hole is filled, values
      //already inserted/copied at the end of the buffer will be destroyed.
      typename value_traits::ArrayDestructor past_hole_values_destroyer
         (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u));
      //Loop for each insertion backwards, first moving the elements after the insertion point,
      //then inserting the element.
      while(insertions_left){
         if(do_skip){
            size_type n = *(--last_skip_it);
            std::advance(last_value_it, -difference_type(n));
         }
         const size_type pos = static_cast<size_type>(*(--last_position_it));
         BOOST_ASSERT(pos <= old_size_pos);
         //If needed shift the range after the insertion point and the previous insertion point.
         //Function will take care if the shift crosses the size() boundary, using copy/move
         //or uninitialized copy/move if necessary.
         size_type new_hole_size = (pos != next_pos)
            ? priv_insert_ordered_at_shift_range(pos, next_pos, this->size(), insertions_left)
            : hole_size
            ;
         if(new_hole_size > 0){
            //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards
            past_hole_values_destroyer.increment_size_backwards(next_pos - pos);
            //Insert the new value in the hole
            allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it));
            --new_hole_size;
            if(new_hole_size == 0){
               //Hole was just filled, disable exception rollback and change vector size
               past_hole_values_destroyer.release();
               this->m_holder.m_size += element_count;
            }
            else{
               //The hole was reduced by the new insertion by one
               past_hole_values_destroyer.increment_size_backwards(size_type(1u));
            }
         }
         else{
            if(hole_size){
               //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size
               past_hole_values_destroyer.release();
               this->m_holder.m_size += element_count;
            }
            //Insert the new value in the already constructed range
            begin_ptr[pos + insertions_left - 1] = *(--last_value_it);
         }
         --insertions_left;
         hole_size = new_hole_size;
         next_pos = pos;
      }
   }

   //Takes the range pointed by [first_pos, last_pos) and shifts it to the right
   //by 'shift_count'. 'limit_pos' marks the end of constructed elements.
   //
   //Precondition: first_pos <= last_pos <= limit_pos
   //
   //The shift operation might cross limit_pos so elements to moved beyond limit_pos
   //are uninitialized_moved with an allocator. Other elements are moved.
   //
   //The shift operation might left uninitialized elements after limit_pos
   //and the number of uninitialized elements is returned by the function.
   //
   //Old situation:
   //       first_pos   last_pos         old_limit
   //             |       |                  | 
   // ____________V_______V__________________V_____________
   //|   prefix   | range |     suffix       |raw_mem      ~
   //|____________|_______|__________________|_____________~
   //
   //New situation in Case Allocator (hole_size == 0):
   // range is moved through move assignments
   //
   //       first_pos   last_pos         limit_pos
   //             |       |                  | 
   // ____________V_______V__________________V_____________
   //|   prefix'  |       |  | range |suffix'|raw_mem      ~
   //|________________+______|___^___|_______|_____________~
   //                 |          |
   //                 |_>_>_>_>_>^                    
   //
   //
   //New situation in Case B (hole_size > 0):
   // range is moved through uninitialized moves
   //
   //       first_pos   last_pos         limit_pos
   //             |       |                  | 
   // ____________V_______V__________________V________________
   //|    prefix' |       |                  | [hole] | range |
   //|_______________________________________|________|___^___|
   //                 |                                   |
   //                 |_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_>_^
   //
   //New situation in Case C (hole_size == 0):
   // range is moved through move assignments and uninitialized moves
   //
   //       first_pos   last_pos         limit_pos
   //             |       |                  | 
   // ____________V_______V__________________V___
   //|   prefix'  |       |              | range |
   //|___________________________________|___^___|
   //                 |                      |
   //                 |_>_>_>_>_>_>_>_>_>_>_>^
   size_type priv_insert_ordered_at_shift_range
      (size_type first_pos, size_type last_pos, size_type limit_pos, size_type shift_count)
   {
      BOOST_ASSERT(first_pos <= last_pos);
      BOOST_ASSERT(last_pos <= limit_pos);
      //
      T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start());
      T* const first_ptr = begin_ptr + first_pos;
      T* const last_ptr  = begin_ptr + last_pos;

      size_type hole_size = 0;
      //Case Allocator:
      if((last_pos + shift_count) <= limit_pos){
         //All move assigned
         boost::move_backward(first_ptr, last_ptr, last_ptr + shift_count);
      }
      //Case B:
      else if((first_pos + shift_count) >= limit_pos){
         //All uninitialized_moved
         ::boost::container::uninitialized_move_alloc
            (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count);
         hole_size = last_pos + shift_count - limit_pos;
      }
      //Case C:
      else{
         //Some uninitialized_moved
         T* const limit_ptr    = begin_ptr + limit_pos;
         T* const boundary_ptr = limit_ptr - shift_count;
         ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), boundary_ptr, last_ptr, limit_ptr);
         //The rest is move assigned
         boost::move_backward(first_ptr, boundary_ptr, limit_ptr);
      }
      return hole_size;
   }

   private:
   template <class InsertionProxy>
   void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy)
   {
      T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
      insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n);
      this->m_holder.m_size += n;
   }

   template <class InsertionProxy>
   void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy)
   {
      //n can't be 0, because there is nothing to do in that case
      if(!n) return;
      //There is enough memory
      T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size;
      const size_type elems_after = old_finish - pos;

      if (!elems_after){
         insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n);
         this->m_holder.m_size += n;
      }
      else if (elems_after >= n){
         //New elements can be just copied.
         //Move to uninitialized memory last objects
         ::boost::container::uninitialized_move_alloc
            (this->m_holder.alloc(), old_finish - n, old_finish, old_finish);
         this->m_holder.m_size += n;
         //Copy previous to last objects to the initialized end
         boost::move_backward(pos, old_finish - n, old_finish);
         //Insert new objects in the pos
         insert_range_proxy.copy_n_and_update(pos, n);
      }
      else {
         //The new elements don't fit in the [pos, end()) range.

         //Copy old [pos, end()) elements to the uninitialized memory (a gap is created)
         ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n);
         BOOST_TRY{
            //Copy first new elements in pos (gap is still there)
            insert_range_proxy.copy_n_and_update(pos, elems_after);
            //Copy to the beginning of the unallocated zone the last new elements (the gap is closed).
            insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n - elems_after);
            this->m_holder.m_size += n;
         }
         BOOST_CATCH(...){
            boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after);
            BOOST_RETHROW
         }
         BOOST_CATCH_END
      }
   }

   template <class InsertionProxy>
   void priv_forward_range_insert_new_allocation
      (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy)
   {
      //n can be zero, if we want to reallocate!
      T *new_finish = new_start;
      T *old_finish;
      //Anti-exception rollbacks
      typename value_traits::ArrayDeallocator scoped_alloc(new_start, this->m_holder.alloc(), new_cap);
      typename value_traits::ArrayDestructor constructed_values_destroyer(new_start, this->m_holder.alloc(), 0u);

      //Initialize with [begin(), pos) old buffer
      //the start of the new buffer
      T *old_buffer = container_detail::to_raw_pointer(this->m_holder.start());
      if(old_buffer){
         new_finish = ::boost::container::uninitialized_move_alloc
            (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.start()), pos, old_finish = new_finish);
         constructed_values_destroyer.increment_size(new_finish - old_finish);
      }
      //Initialize new objects, starting from previous point
      insert_range_proxy.uninitialized_copy_n_and_update(old_finish = new_finish, n);
      new_finish += n;
      constructed_values_destroyer.increment_size(new_finish - old_finish);
      //Initialize from the rest of the old buffer,
      //starting from previous point
      if(old_buffer){
         new_finish = ::boost::container::uninitialized_move_alloc
            (this->m_holder.alloc(), pos, old_buffer + this->m_holder.m_size, new_finish);
         //Destroy and deallocate old elements
         //If there is allocated memory, destroy and deallocate
         if(!value_traits::trivial_dctr_after_move)
            boost::container::destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size);
         this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity());
      }
      this->m_holder.start(new_start);
      this->m_holder.m_size = new_finish - new_start;
      this->m_holder.capacity(new_cap);
      //All construction successful, disable rollbacks
      constructed_values_destroyer.release();
      scoped_alloc.release();
   }

   template <class InsertionProxy>
   void priv_forward_range_insert_expand_backwards
         (T* const new_start, const size_type new_capacity,
          T* const pos, const size_type n, InsertionProxy insert_range_proxy)
   {
      //n can be zero to just expand capacity
      //Backup old data
      T* const old_start  = container_detail::to_raw_pointer(this->m_holder.start());
      T* const old_finish = old_start + this->m_holder.m_size;
      const size_type old_size = this->m_holder.m_size;

      //We can have 8 possibilities:
      const size_type elemsbefore = static_cast<size_type>(pos - old_start);
      const size_type s_before    = static_cast<size_type>(old_start - new_start);
      const size_type before_plus_new = elemsbefore + n;

      //Update the vector buffer information to a safe state
      this->m_holder.start(new_start);
      this->m_holder.capacity(new_capacity);
      this->m_holder.m_size = 0;

      //If anything goes wrong, this object will destroy
      //all the old objects to fulfill previous vector state
      typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), old_size);
      //Check if s_before is big enough to hold the beginning of old data + new data
      if(s_before >= before_plus_new){
         //Copy first old values before pos, after that the new objects
         T *const new_elem_pos = ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start);
         this->m_holder.m_size = elemsbefore;
         insert_range_proxy.uninitialized_copy_n_and_update(new_elem_pos, n);
         this->m_holder.m_size += n;
         //Check if s_before is so big that even copying the old data + new data
         //there is a gap between the new data and the old data
         const size_type new_size = old_size + n;
         if(s_before >= new_size){
            //Old situation:
            // _________________________________________________________
            //|            raw_mem                | old_begin | old_end |
            //| __________________________________|___________|_________|
            //
            //New situation:
            // _________________________________________________________
            //| old_begin |    new   | old_end |         raw_mem        |
            //|___________|__________|_________|________________________|
            //
            //Now initialize the rest of memory with the last old values
            ::boost::container::uninitialized_move_alloc
               (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new);
            //All new elements correctly constructed, avoid new element destruction
            this->m_holder.m_size = new_size;
            //Old values destroyed automatically with "old_values_destroyer"
            //when "old_values_destroyer" goes out of scope unless the have trivial
            //destructor after move.
            if(value_traits::trivial_dctr_after_move)
               old_values_destroyer.release();
         }
         //s_before is so big that divides old_end
         else{
            //Old situation:
            // __________________________________________________
            //|            raw_mem         | old_begin | old_end |
            //| ___________________________|___________|_________|
            //
            //New situation:
            // __________________________________________________
            //| old_begin |   new    | old_end |  raw_mem        |
            //|___________|__________|_________|_________________|
            //
            //Now initialize the rest of memory with the last old values
            //All new elements correctly constructed, avoid new element destruction
            const size_type raw_gap = s_before - before_plus_new;
            //Now initialize the rest of s_before memory with the
            //first of elements after new values
            ::boost::container::uninitialized_move_alloc_n
               (this->m_holder.alloc(), pos, raw_gap, new_start + before_plus_new);
            //Update size since we have a contiguous buffer
            this->m_holder.m_size = old_size + s_before;
            //All new elements correctly constructed, avoid old element destruction
            old_values_destroyer.release();
            //Now copy remaining last objects in the old buffer begin
            T * const to_destroy = ::boost::move(pos + raw_gap, old_finish, old_start);
            //Now destroy redundant elements except if they were moved and
            //they have trivial destructor after move
            size_type n_destroy =  old_finish - to_destroy;
            if(!value_traits::trivial_dctr_after_move)
               boost::container::destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy);
            this->m_holder.m_size -= n_destroy;
         }
      }
      else{
         //Check if we have to do the insertion in two phases
         //since maybe s_before is not big enough and
         //the buffer was expanded both sides
         //
         //Old situation:
         // _________________________________________________
         //| raw_mem | old_begin + old_end |  raw_mem        |
         //|_________|_____________________|_________________|
         //
         //New situation with do_after:
         // _________________________________________________
         //|     old_begin + new + old_end     |  raw_mem    |
         //|___________________________________|_____________|
         //
         //New without do_after:
         // _________________________________________________
         //| old_begin + new + old_end  |  raw_mem           |
         //|____________________________|____________________|
         //
         const bool do_after = n > s_before;

         //Now we can have two situations: the raw_mem of the
         //beginning divides the old_begin, or the new elements:
         if (s_before <= elemsbefore) {
            //The raw memory divides the old_begin group:
            //
            //If we need two phase construction (do_after)
            //new group is divided in new = new_beg + new_end groups
            //In this phase only new_beg will be inserted
            //
            //Old situation:
            // _________________________________________________
            //| raw_mem | old_begin | old_end |  raw_mem        |
            //|_________|___________|_________|_________________|
            //
            //New situation with do_after(1):
            //This is not definitive situation, the second phase
            //will include
            // _________________________________________________
            //| old_begin | new_beg | old_end |  raw_mem        |
            //|___________|_________|_________|_________________|
            //
            //New situation without do_after:
            // _________________________________________________
            //| old_begin | new | old_end |  raw_mem            |
            //|___________|_____|_________|_____________________|
            //
            //Copy the first part of old_begin to raw_mem
            ::boost::container::uninitialized_move_alloc_n
               (this->m_holder.alloc(), old_start, s_before, new_start);
            //The buffer is all constructed until old_end,
            //release destroyer and update size
            old_values_destroyer.release();
            this->m_holder.m_size = old_size + s_before;
            //Now copy the second part of old_begin overwriting itself
            T *const next = ::boost::move(old_start + s_before, pos, old_start);
            if(do_after){
               //Now copy the new_beg elements
               insert_range_proxy.copy_n_and_update(next, s_before);
            }
            else{
               //Now copy the all the new elements
               insert_range_proxy.copy_n_and_update(next, n);
               //Now displace old_end elements
               T* const move_end   = ::boost::move(pos, old_finish, next + n);
               //Destroy remaining moved elements from old_end except if
               //they have trivial destructor after being moved
               const size_type n_destroy = s_before - n;
               if(!value_traits::trivial_dctr_after_move)
                  boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy);
               this->m_holder.m_size -= n_destroy;
            }
         }
         else {
            //If we have to expand both sides,
            //we will play if the first new values so
            //calculate the upper bound of new values

            //The raw memory divides the new elements
            //
            //If we need two phase construction (do_after)
            //new group is divided in new = new_beg + new_end groups
            //In this phase only new_beg will be inserted
            //
            //Old situation:
            // _______________________________________________________
            //|   raw_mem     | old_begin | old_end |  raw_mem        |
            //|_______________|___________|_________|_________________|
            //
            //New situation with do_after():
            // ____________________________________________________
            //| old_begin |    new_beg    | old_end |  raw_mem     |
            //|___________|_______________|_________|______________|
            //
            //New situation without do_after:
            // ______________________________________________________
            //| old_begin | new | old_end |  raw_mem                 |
            //|___________|_____|_________|__________________________|
            //
            //First copy whole old_begin and part of new to raw_mem
            T * const new_pos = ::boost::container::uninitialized_move_alloc
               (this->m_holder.alloc(), old_start, pos, new_start);
            this->m_holder.m_size = elemsbefore;
            const size_type mid_n = s_before - elemsbefore;
            insert_range_proxy.uninitialized_copy_n_and_update(new_pos, mid_n);
            //The buffer is all constructed until old_end,
            //release destroyer
            this->m_holder.m_size = old_size + s_before;
            old_values_destroyer.release();

            if(do_after){
               //Copy new_beg part
               insert_range_proxy.copy_n_and_update(old_start, elemsbefore);
            }
            else{
               //Copy all new elements
               const size_type rest_new = n - mid_n;
               insert_range_proxy.copy_n_and_update(old_start, rest_new);
               T* move_start = old_start + rest_new;
               //Displace old_end
               T* move_end = ::boost::move(pos, old_finish, move_start);
               //Destroy remaining moved elements from old_end except if they
               //have trivial destructor after being moved
               size_type n_destroy = s_before - n;
               if(!value_traits::trivial_dctr_after_move)
                  boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy);
               this->m_holder.m_size -= n_destroy;
            }
         }

         //This is only executed if two phase construction is needed
         if(do_after){
            //The raw memory divides the new elements
            //
            //Old situation:
            // ______________________________________________________
            //|   raw_mem    | old_begin |  old_end   |  raw_mem     |
            //|______________|___________|____________|______________|
            //
            //New situation with do_after(1):
            // _______________________________________________________
            //| old_begin   +   new_beg  | new_end |old_end | raw_mem |
            //|__________________________|_________|________|_________|
            //
            //New situation with do_after(2):
            // ______________________________________________________
            //| old_begin      +       new            | old_end |raw |
            //|_______________________________________|_________|____|
            //
            const size_type n_after    = n - s_before;
            const size_type elemsafter = old_size - elemsbefore;

            //We can have two situations:
            if (elemsafter >= n_after){
               //The raw_mem from end will divide displaced old_end
               //
               //Old situation:
               // ______________________________________________________
               //|   raw_mem    | old_begin |  old_end   |  raw_mem     |
               //|______________|___________|____________|______________|
               //
               //New situation with do_after(1):
               // _______________________________________________________
               //| old_begin   +   new_beg  | new_end |old_end | raw_mem |
               //|__________________________|_________|________|_________|
               //
               //First copy the part of old_end raw_mem
               T* finish_n = old_finish - n_after;
               ::boost::container::uninitialized_move_alloc
                  (this->m_holder.alloc(), finish_n, old_finish, old_finish);
               this->m_holder.m_size += n_after;
               //Displace the rest of old_end to the new position
               boost::move_backward(pos, finish_n, old_finish);
               //Now overwrite with new_end
               //The new_end part is [first + (n - n_after), last)
               insert_range_proxy.copy_n_and_update(pos, n_after);
            }
            else {
               //The raw_mem from end will divide new_end part
               //
               //Old situation:
               // _____________________________________________________________
               //|   raw_mem    | old_begin |  old_end   |  raw_mem            |
               //|______________|___________|____________|_____________________|
               //
               //New situation with do_after(2):
               // _____________________________________________________________
               //| old_begin   +   new_beg  |     new_end   |old_end | raw_mem |
               //|__________________________|_______________|________|_________|
               //

               const size_type mid_last_dist = n_after - elemsafter;
               //First initialize data in raw memory

               //Copy to the old_end part to the uninitialized zone leaving a gap.
               ::boost::container::uninitialized_move_alloc
                  (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist);

               BOOST_TRY{
                  //Copy the first part to the already constructed old_end zone
                  insert_range_proxy.copy_n_and_update(pos, elemsafter);
                  //Copy the rest to the uninitialized zone filling the gap
                  insert_range_proxy.uninitialized_copy_n_and_update(old_finish, mid_last_dist);
                  this->m_holder.m_size += n_after;
               }
               BOOST_CATCH(...){
                  boost::container::destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist);
                  BOOST_RETHROW
               }
               BOOST_CATCH_END
/*
               size_type mid_last_dist = n_after - elemsafter;
               //First initialize data in raw memory

               //The new_end part is [first + (n - n_after), last)
               insert_range_proxy.uninitialized_copy_last_and_update(old_finish, elemsafter);
               this->m_holder.m_size += mid_last_dist;
               ::boost::container::uninitialized_move_alloc
                  (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist);
               this->m_holder.m_size += n_after - mid_last_dist;
               //Now copy the part of new_end over constructed elements
               insert_range_proxy.copy_remaining_to(pos);*/
            }
         }
      }
   }

   void priv_check_range(size_type n) const
   {
      //If n is out of range, throw an out_of_range exception
      if (n >= this->size()){
         throw_out_of_range("vector::at out of range");
      }
   }

   #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS
   public:
   unsigned int num_expand_fwd;
   unsigned int num_expand_bwd;
   unsigned int num_shrink;
   unsigned int num_alloc;
   void reset_alloc_stats()
   {  num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0;   }
   #endif
   /// @endcond
};

template <class T, class Allocator>
inline bool
operator==(const vector<T, Allocator>& x, const vector<T, Allocator>& y)
{
   //Check first size and each element if needed
   return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin());
}

template <class T, class Allocator>
inline bool
operator!=(const vector<T, Allocator>& x, const vector<T, Allocator>& y)
{
   //Check first size and each element if needed
  return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin());
}

template <class T, class Allocator>
inline bool
operator<(const vector<T, Allocator>& x, const vector<T, Allocator>& y)
{
   return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}

template <class T, class Allocator>
inline void swap(vector<T, Allocator>& x, vector<T, Allocator>& y)
{  x.swap(y);  }

}}

/// @cond

namespace boost {


//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class T, class Allocator>
struct has_trivial_destructor_after_move<boost::container::vector<T, Allocator> >
   : public ::boost::has_trivial_destructor_after_move<Allocator>
{};


}

//#define BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD

#ifdef BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD

namespace std {

template <class T, class Allocator>
inline void swap(boost::container::vector<T, Allocator>& x, boost::container::vector<T, Allocator>& y)
{  x.swap(y);  }

}  //namespace std {

#endif

/// @endcond

#include <boost/container/detail/config_end.hpp>

#endif //   #ifndef  BOOST_CONTAINER_CONTAINER_VECTOR_HPP

