stl_vector.h: Use new allocator model in C++0x mode.
authorJonathan Wakely <jwakely.gcc@gmail.com>
Sat, 9 Jul 2011 13:06:29 +0000 (13:06 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Sat, 9 Jul 2011 13:06:29 +0000 (14:06 +0100)
2011-07-09  Jonathan Wakely  <jwakely.gcc@gmail.com>

* include/bits/stl_vector.h: Use new allocator model in C++0x mode.
* include/bits/vector.tcc: Likewise.
* testsuite/util/testsuite_allocator.h (propagating_allocator): Define.
* testsuite/23_containers/vector/allocator/copy_assign.cc: New.
* testsuite/23_containers/vector/allocator/noexcept.cc: New.
* testsuite/23_containers/vector/allocator/copy.cc: New.
* testsuite/23_containers/vector/allocator/swap.cc: New.
* testsuite/23_containers/vector/allocator/move_assign.cc: New.
* testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
Adjust dg-error line numbers.
* testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
Likewise.
* testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
Likewise.

From-SVN: r176078

13 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_vector.h
libstdc++-v3/include/bits/vector.tcc
libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
libstdc++-v3/testsuite/util/testsuite_allocator.h

index bd2a0cd9f513a2a8e257b3ed62a1659fe1873302..1304b9241e2800599a953fef85abfd8502d027d4 100644 (file)
@@ -1,3 +1,22 @@
+2011-07-09  Jonathan Wakely  <jwakely.gcc@gmail.com>
+
+       * include/bits/stl_vector.h: Use new allocator model in C++0x mode.
+       * include/bits/vector.tcc: Likewise.
+       * testsuite/util/testsuite_allocator.h (propagating_allocator): Define.
+       * testsuite/23_containers/vector/allocator/copy_assign.cc: New.
+       * testsuite/23_containers/vector/allocator/noexcept.cc: New.
+       * testsuite/23_containers/vector/allocator/copy.cc: New.
+       * testsuite/23_containers/vector/allocator/swap.cc: New.
+       * testsuite/23_containers/vector/allocator/move_assign.cc: New.
+       * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
+       Adjust dg-error line numbers.
+       * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc:
+       Likewise.
+       * testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc:
+       Likewise.
+       * testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc:
+       Likewise.
+
 2011-07-09  Jonathan Wakely  <jwakely.gcc@gmail.com>
 
        * include/ext/alloc_traits.h (__allocator_always_compares_equal): New
index 929bcbe7ba15611c306738d4e157934ab45beb1d..0211033a456fa709773c255d5c55eb2acbac12b8 100644 (file)
@@ -71,13 +71,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     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)
@@ -93,6 +95,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          _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:
@@ -118,30 +127,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _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(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
 
@@ -152,16 +161,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     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;
+      }
     };
 
 
@@ -196,10 +214,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
     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;
@@ -283,7 +302,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  @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,
@@ -301,6 +321,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       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.
        *  @param  l  An initializer_list.
@@ -377,12 +420,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  @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;
       }
 
@@ -834,7 +897,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
        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
@@ -864,7 +928,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       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__
@@ -1024,16 +1088,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       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());
       }
 
       /**
index fd576dbd2df083b729b65b5d1e31b06274b64622..85b514b561b00ce2ccacf72cdcfc22d71c43996f 100644 (file)
@@ -94,8 +94,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
          {
-           this->_M_impl.construct(this->_M_impl._M_finish,
-                                   std::forward<_Args>(__args)...);
+           _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+                                    std::forward<_Args>(__args)...);
            ++this->_M_impl._M_finish;
          }
        else
@@ -112,7 +112,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
          && __position == end())
        {
-         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
@@ -138,7 +138,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (__position + 1 != end())
        _GLIBCXX_MOVE3(__position + 1, end(), __position);
       --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);
       return __position;
     }
 
@@ -160,6 +160,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (&__x != this)
        {
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+         if (_Alloc_traits::_S_propagate_on_copy_assign())
+           {
+             if (!_Alloc_traits::_S_always_equal()
+                 && _M_get_Tp_allocator() != __x._M_get_Tp_allocator())
+               {
+                 // replacement allocator cannot free existing storage
+                 this->clear();
+                 _M_deallocate(this->_M_impl._M_start,
+                               this->_M_impl._M_end_of_storage
+                               - this->_M_impl._M_start);
+               }
+             std::__alloc_on_copy(_M_get_Tp_allocator(),
+                                  __x._M_get_Tp_allocator());
+           }
+#endif
          const size_type __xlen = __x.size();
          if (__xlen > capacity())
            {
@@ -277,8 +293,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage
            && __position == end())
          {
-           this->_M_impl.construct(this->_M_impl._M_finish,
-                                   std::forward<_Args>(__args)...);
+           _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+                                    std::forward<_Args>(__args)...);
            ++this->_M_impl._M_finish;
          }
        else
@@ -300,9 +316,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
        {
-         this->_M_impl.construct(this->_M_impl._M_finish,
-                                 _GLIBCXX_MOVE(*(this->_M_impl._M_finish
-                                                 - 1)));
+         _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+                                  _GLIBCXX_MOVE(*(this->_M_impl._M_finish
+                                                  - 1)));
          ++this->_M_impl._M_finish;
 #ifndef __GXX_EXPERIMENTAL_CXX0X__
          _Tp __x_copy = __x;
@@ -329,11 +345,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
              // case, where the moves could alter a new element belonging
              // to the existing vector.  This is an issue only for callers
              // taking the element by const lvalue ref (see 23.1/13).
-             this->_M_impl.construct(__new_start + __elems_before,
+             _Alloc_traits::construct(this->_M_impl,
+                                      __new_start + __elems_before,
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
-                                     std::forward<_Args>(__args)...);
+                                      std::forward<_Args>(__args)...);
 #else
-                                     __x);
+                                      __x);
 #endif
              __new_finish = 0;
 
@@ -352,7 +369,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
           __catch(...)
            {
              if (!__new_finish)
-               this->_M_impl.destroy(__new_start + __elems_before);
+               _Alloc_traits::destroy(this->_M_impl,
+                                      __new_start + __elems_before);
              else
                std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
              _M_deallocate(__new_start, __len);
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc
new file mode 100644 (file)
index 0000000..bcd521e
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc
new file mode 100644 (file)
index 0000000..0e2050e
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc
new file mode 100644 (file)
index 0000000..2a792c6
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(0 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc
new file mode 100644 (file)
index 0000000..8bde430
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+struct T { int i; };
+
+namespace __gnu_test
+{
+  inline void
+  swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+  noexcept(false)
+  {
+    typedef uneq_allocator<T> base_alloc;
+    swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+  }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  typedef std::allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1;
+  test_type v2;
+  // this is a GNU extension for std::allocator
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc
new file mode 100644 (file)
index 0000000..808753e
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++0x" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(2 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
index eba024c0c8ca0291a7b62a3c5f0251bb1fd54e76..8ff85455db71c91ce0023de0bc65dee7141ec7dd 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1157 }
+// { dg-error "no matching" "" { target *-*-* } 1218 }
 
 #include <vector>
 
index 24c14ce6bba58737b31ce0eb32ac144ecbc069fd..344f1a68170f39dce62c3c6ba8c3303f4c621a9b 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1087 }
+// { dg-error "no matching" "" { target *-*-* } 1148 }
 
 #include <vector>
 
index b765096d9d482e63b6d7c8772e4be7c353c21402..7f3c52e805894776558bb9640b8e182516998aaf 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1087 }
+// { dg-error "no matching" "" { target *-*-* } 1148 }
 
 #include <vector>
 #include <utility>
index 083f2e0d26c7138ce812a51a68824d54d49f7ae1..c2337c82c657be16ab4b32d12ca7c8b647f2f78e 100644 (file)
@@ -18,7 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1198 }
+// { dg-error "no matching" "" { target *-*-* } 1259 }
 
 #include <vector>
 
index 95e8d0dbaac193957d2695a68a8e1660d334cdaf..3b9fb28b9011467357eb01d5b31068f039a9af36 100644 (file)
@@ -371,6 +371,68 @@ namespace __gnu_test
       
       int personality;
     };
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+  // An uneq_allocator which can be used to test allocator propagation.
+  template<typename Tp, bool Propagate>
+    class propagating_allocator : public uneq_allocator<Tp>
+    {
+      typedef uneq_allocator<Tp> base_alloc;
+      base_alloc& base() { return *this; }
+      const base_alloc& base() const  { return *this; }
+      void swap_base(base_alloc& b) { swap(b, this->base()); }
+
+      typedef std::integral_constant<bool, Propagate> trait_type;
+
+    public:
+      template<typename Up>
+       struct rebind { typedef propagating_allocator<Up, Propagate> other; };
+
+      propagating_allocator(int i) noexcept
+      : base_alloc(i)
+      { }
+
+      template<typename Up>
+       propagating_allocator(const propagating_allocator<Up, Propagate>& a)
+               noexcept
+       : base_alloc(a)
+       { }
+
+      propagating_allocator() noexcept = default;
+
+      propagating_allocator(const propagating_allocator&) noexcept = default;
+
+      template<bool P2>
+       propagating_allocator&
+       operator=(const propagating_allocator<Tp, P2>& a) noexcept
+       {
+         static_assert(P2, "assigning propagating_allocator<T, true>");
+         propagating_allocator(a).swap_base(*this);
+       }
+
+      // postcondition: a.get_personality() == 0
+      propagating_allocator(propagating_allocator&& a) noexcept
+      : base_alloc()
+      { swap_base(a); }
+
+      // postcondition: a.get_personality() == 0
+      propagating_allocator&
+      operator=(propagating_allocator&& a) noexcept
+      {
+       propagating_allocator(std::move(a)).swap_base(*this);
+       return *this;
+      }
+
+      typedef trait_type propagate_on_container_copy_assignment;
+      typedef trait_type propagate_on_container_move_assignment;
+      typedef trait_type propagate_on_container_swap;
+
+      propagating_allocator select_on_container_copy_construction() const
+      { return Propagate ? *this : propagating_allocator(); }
+    };
+
+#endif
+
 } // namespace __gnu_test
 
 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H