stl_vector.h: Use new allocator model in C++0x mode.
[gcc.git] / libstdc++-v3 / include / bits / stl_vector.h
index d51578c9e059fe3986c441e2c0a005af7a79acef..0211033a456fa709773c255d5c55eb2acbac12b8 100644 (file)
@@ -1,7 +1,7 @@
 // Vector implementation -*- C++ -*-
 
-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-// Free Software Foundation, Inc.
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+// 2011 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -49,9 +49,9 @@
  * purpose.  It is provided "as is" without express or implied warranty.
  */
 
-/** @file stl_vector.h
+/** @file bits/stl_vector.h
  *  This is an internal header file, included by other library headers.
- *  You should not attempt to use it directly.
+ *  Do not attempt to use it directly. @headername{vector}
  */
 
 #ifndef _STL_VECTOR_H
 #include <bits/concept_check.h>
 #include <initializer_list>
 
-_GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
   /// See bits/stl_deque.h's _Deque_base for an explanation.
   template<typename _Tp, typename _Alloc>
     struct _Vector_base
     {
       typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
+      typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
+               pointer;
 
       struct _Vector_impl 
       : public _Tp_alloc_type
       {
-       typename _Tp_alloc_type::pointer _M_start;
-       typename _Tp_alloc_type::pointer _M_finish;
-       typename _Tp_alloc_type::pointer _M_end_of_storage;
+       pointer _M_start;
+       pointer _M_finish;
+       pointer _M_end_of_storage;
 
        _Vector_impl()
        : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0)
@@ -84,21 +88,35 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        _Vector_impl(_Tp_alloc_type const& __a)
        : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
        { }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+       _Vector_impl(_Tp_alloc_type&& __a)
+       : _Tp_alloc_type(std::move(__a)),
+         _M_start(0), _M_finish(0), _M_end_of_storage(0)
+       { }
+#endif
+
+       void _M_swap_data(_Vector_impl& __x)
+       {
+         std::swap(_M_start, __x._M_start);
+         std::swap(_M_finish, __x._M_finish);
+         std::swap(_M_end_of_storage, __x._M_end_of_storage);
+       }
       };
       
     public:
       typedef _Alloc allocator_type;
 
       _Tp_alloc_type&
-      _M_get_Tp_allocator()
+      _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
       { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
 
       const _Tp_alloc_type&
-      _M_get_Tp_allocator() const
+      _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
       { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
 
       allocator_type
-      get_allocator() const
+      get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
       _Vector_base()
@@ -109,30 +127,30 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
 
       _Vector_base(size_t __n)
       : _M_impl()
-      {
-       this->_M_impl._M_start = this->_M_allocate(__n);
-       this->_M_impl._M_finish = this->_M_impl._M_start;
-       this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
-      }
+      { _M_create_storage(__n); }
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
-      {
-       this->_M_impl._M_start = this->_M_allocate(__n);
-       this->_M_impl._M_finish = this->_M_impl._M_start;
-       this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
-      }
+      { _M_create_storage(__n); }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
+      _Vector_base(_Tp_alloc_type&& __a)
+      : _M_impl(std::move(__a)) { }
+
       _Vector_base(_Vector_base&& __x)
-      : _M_impl(__x._M_get_Tp_allocator())
+      : _M_impl(std::move(__x._M_get_Tp_allocator()))
+      { this->_M_impl._M_swap_data(__x._M_impl); }
+
+      _Vector_base(_Vector_base&& __x, const allocator_type& __a)
+      : _M_impl(__a)
       {
-       this->_M_impl._M_start = __x._M_impl._M_start;
-       this->_M_impl._M_finish = __x._M_impl._M_finish;
-       this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage;
-       __x._M_impl._M_start = 0;
-       __x._M_impl._M_finish = 0;
-       __x._M_impl._M_end_of_storage = 0;
+       if (__x.get_allocator() == __a)
+         this->_M_impl._M_swap_data(__x._M_impl);
+       else
+         {
+           size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;
+           _M_create_storage(__n);
+         }
       }
 #endif
 
@@ -143,16 +161,25 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
     public:
       _Vector_impl _M_impl;
 
-      typename _Tp_alloc_type::pointer
+      pointer
       _M_allocate(size_t __n)
       { return __n != 0 ? _M_impl.allocate(__n) : 0; }
 
       void
-      _M_deallocate(typename _Tp_alloc_type::pointer __p, size_t __n)
+      _M_deallocate(pointer __p, size_t __n)
       {
        if (__p)
          _M_impl.deallocate(__p, __n);
       }
+
+    private:
+      void
+      _M_create_storage(size_t __n)
+      {
+       this->_M_impl._M_start = this->_M_allocate(__n);
+       this->_M_impl._M_finish = this->_M_impl._M_start;
+       this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
+      }
     };
 
 
@@ -187,10 +214,11 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
 
     public:
       typedef _Tp                                       value_type;
-      typedef typename _Tp_alloc_type::pointer           pointer;
-      typedef typename _Tp_alloc_type::const_pointer     const_pointer;
-      typedef typename _Tp_alloc_type::reference         reference;
-      typedef typename _Tp_alloc_type::const_reference   const_reference;
+      typedef typename _Base::pointer                    pointer;
+      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>  _Alloc_traits;
+      typedef typename _Alloc_traits::const_pointer      const_pointer;
+      typedef typename _Alloc_traits::reference          reference;
+      typedef typename _Alloc_traits::const_reference    const_reference;
       typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
       typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
       const_iterator;
@@ -274,7 +302,8 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  @a x (for fast expansion) will not be copied.
        */
       vector(const vector& __x)
-      : _Base(__x.size(), __x._M_get_Tp_allocator())
+      : _Base(__x.size(),
+        _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()))
       { this->_M_impl._M_finish =
          std::__uninitialized_copy_a(__x.begin(), __x.end(),
                                      this->_M_impl._M_start,
@@ -289,8 +318,31 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  The newly-created %vector contains the exact contents of @a x.
        *  The contents of @a x are a valid, but unspecified %vector.
        */
-      vector(vector&& __x)
-      : _Base(std::forward<_Base>(__x)) { }
+      vector(vector&& __x) noexcept
+      : _Base(std::move(__x)) { }
+
+      /// Copy constructor with alternative allocator
+      vector(const vector& __x, const allocator_type& __a)
+      : _Base(__x.size(), __a)
+      { this->_M_impl._M_finish =
+         std::__uninitialized_copy_a(__x.begin(), __x.end(),
+                                     this->_M_impl._M_start,
+                                     _M_get_Tp_allocator());
+      }
+
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+      : _Base(std::move(__rv), __m)
+      {
+       if (__rv.get_allocator() != __m)
+         {
+           this->_M_impl._M_finish =
+             std::__uninitialized_move_a(__rv.begin(), __rv.end(),
+                                         this->_M_impl._M_start,
+                                         _M_get_Tp_allocator());
+           __rv.clear();
+         }
+      }
 
       /**
        *  @brief  Builds a %vector from an initializer list.
@@ -344,7 +396,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  not touched in any way.  Managing the pointer is the user's
        *  responsibility.
        */
-      ~vector()
+      ~vector() _GLIBCXX_NOEXCEPT
       { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                      _M_get_Tp_allocator()); }
 
@@ -368,12 +420,32 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  @a x is a valid, but unspecified %vector.
        */
       vector&
-      operator=(vector&& __x)
+      operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
       {
-       // NB: DR 1204.
-       // NB: DR 675.
-       this->clear();
-       this->swap(__x);
+       if (_Alloc_traits::_S_propagate_on_move_assign())
+         {
+           // We're moving the rvalue's allocator so can move the data too.
+           const vector __tmp(std::move(*this));     // discard existing data
+           this->_M_impl._M_swap_data(__x._M_impl);
+           std::__alloc_on_move(_M_get_Tp_allocator(),
+                                __x._M_get_Tp_allocator());
+         }
+       else if (_Alloc_traits::_S_always_equal()
+                || __x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
+         {
+           // The rvalue's allocator can free our storage and vice versa,
+           // so can swap the data storage after destroying our contents.
+           this->clear();
+           this->_M_impl._M_swap_data(__x._M_impl);
+         }
+       else
+         {
+           // The rvalue's allocator cannot be moved, or is not equal,
+           // so we need to individually move each element.
+           this->assign(std::__make_move_if_noexcept_iterator(__x.begin()),
+                        std::__make_move_if_noexcept_iterator(__x.end()));
+           __x.clear();
+         }
        return *this;
       }
 
@@ -458,7 +530,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  element order.
        */
       iterator
-      begin()
+      begin() _GLIBCXX_NOEXCEPT
       { return iterator(this->_M_impl._M_start); }
 
       /**
@@ -467,7 +539,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  element order.
        */
       const_iterator
-      begin() const
+      begin() const _GLIBCXX_NOEXCEPT
       { return const_iterator(this->_M_impl._M_start); }
 
       /**
@@ -476,7 +548,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  element order.
        */
       iterator
-      end()
+      end() _GLIBCXX_NOEXCEPT
       { return iterator(this->_M_impl._M_finish); }
 
       /**
@@ -485,7 +557,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  ordinary element order.
        */
       const_iterator
-      end() const
+      end() const _GLIBCXX_NOEXCEPT
       { return const_iterator(this->_M_impl._M_finish); }
 
       /**
@@ -494,7 +566,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  element order.
        */
       reverse_iterator
-      rbegin()
+      rbegin() _GLIBCXX_NOEXCEPT
       { return reverse_iterator(end()); }
 
       /**
@@ -503,7 +575,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  reverse element order.
        */
       const_reverse_iterator
-      rbegin() const
+      rbegin() const _GLIBCXX_NOEXCEPT
       { return const_reverse_iterator(end()); }
 
       /**
@@ -512,7 +584,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  in reverse element order.
        */
       reverse_iterator
-      rend()
+      rend() _GLIBCXX_NOEXCEPT
       { return reverse_iterator(begin()); }
 
       /**
@@ -521,7 +593,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  is done in reverse element order.
        */
       const_reverse_iterator
-      rend() const
+      rend() const _GLIBCXX_NOEXCEPT
       { return const_reverse_iterator(begin()); }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
@@ -531,7 +603,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  element order.
        */
       const_iterator
-      cbegin() const
+      cbegin() const noexcept
       { return const_iterator(this->_M_impl._M_start); }
 
       /**
@@ -540,7 +612,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  ordinary element order.
        */
       const_iterator
-      cend() const
+      cend() const noexcept
       { return const_iterator(this->_M_impl._M_finish); }
 
       /**
@@ -549,7 +621,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  reverse element order.
        */
       const_reverse_iterator
-      crbegin() const
+      crbegin() const noexcept
       { return const_reverse_iterator(end()); }
 
       /**
@@ -558,19 +630,19 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  is done in reverse element order.
        */
       const_reverse_iterator
-      crend() const
+      crend() const noexcept
       { return const_reverse_iterator(begin()); }
 #endif
 
       // [23.2.4.2] capacity
       /**  Returns the number of elements in the %vector.  */
       size_type
-      size() const
+      size() const _GLIBCXX_NOEXCEPT
       { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
 
       /**  Returns the size() of the largest possible %vector.  */
       size_type
-      max_size() const
+      max_size() const _GLIBCXX_NOEXCEPT
       { return _M_get_Tp_allocator().max_size(); }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
@@ -637,7 +709,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
       /**  A non-binding request to reduce capacity() to size().  */
       void
       shrink_to_fit()
-      { std::__shrink_to_fit<vector>::_S_do_it(*this); }
+      { _M_shrink_to_fit(); }
 #endif
 
       /**
@@ -645,7 +717,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  hold before needing to allocate more memory.
        */
       size_type
-      capacity() const
+      capacity() const _GLIBCXX_NOEXCEPT
       { return size_type(this->_M_impl._M_end_of_storage
                         - this->_M_impl._M_start); }
 
@@ -654,7 +726,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  equal end().)
        */
       bool
-      empty() const
+      empty() const _GLIBCXX_NOEXCEPT
       { return begin() == end(); }
 
       /**
@@ -798,7 +870,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
 #else
       pointer
 #endif
-      data()
+      data() _GLIBCXX_NOEXCEPT
       { return std::__addressof(front()); }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
@@ -806,7 +878,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
 #else
       const_pointer
 #endif
-      data() const
+      data() const _GLIBCXX_NOEXCEPT
       { return std::__addressof(front()); }
 
       // [23.2.4.3] modifiers
@@ -825,7 +897,8 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
       {
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
          {
-           this->_M_impl.construct(this->_M_impl._M_finish, __x);
+           _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+                                    __x);
            ++this->_M_impl._M_finish;
          }
        else
@@ -855,7 +928,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
       pop_back()
       {
        --this->_M_impl._M_finish;
-       this->_M_impl.destroy(this->_M_impl._M_finish);
+       _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
       }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
@@ -1015,16 +1088,13 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        */
       void
       swap(vector& __x)
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+                       noexcept(_Alloc_traits::_S_nothrow_swap())
+#endif
       {
-       std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
-       std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
-       std::swap(this->_M_impl._M_end_of_storage,
-                 __x._M_impl._M_end_of_storage);
-
-       // _GLIBCXX_RESOLVE_LIB_DEFECTS
-       // 431. Swapping containers with unequal allocators.
-       std::__alloc_swap<_Tp_alloc_type>::_S_do_it(_M_get_Tp_allocator(),
-                                                   __x._M_get_Tp_allocator());
+       this->_M_impl._M_swap_data(__x._M_impl);
+       _Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
+                                 __x._M_get_Tp_allocator());
       }
 
       /**
@@ -1034,7 +1104,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
        *  the user's responsibility.
        */
       void
-      clear()
+      clear() _GLIBCXX_NOEXCEPT
       { _M_erase_at_end(this->_M_impl._M_start); }
 
     protected:
@@ -1220,6 +1290,9 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
       // Called by resize(n).
       void
       _M_default_append(size_type __n);
+
+      bool
+      _M_shrink_to_fit();
 #endif
 
       // Called by insert(p,x)
@@ -1319,6 +1392,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
     swap(vector<_Tp, _Alloc>& __x, vector<_Tp, _Alloc>& __y)
     { __x.swap(__y); }
 
-_GLIBCXX_END_NESTED_NAMESPACE
+_GLIBCXX_END_NAMESPACE_CONTAINER
+} // namespace std
 
 #endif /* _STL_VECTOR_H */