public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [v3] add <scoped_allocator>
@ 2011-07-09 14:44 Jonathan Wakely
  2011-07-18 17:08 ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2011-07-09 14:44 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 838 bytes --]

This adds the new <scoped_allocator> header. Currently only
std::vector has the necessary support for C++0x allocators to be
usable with std::scoped_allocator_adaptor.

        * include/Makefile.am: Add new header.
        * include/Makefile.in: Regenerate.
        * include/std/scoped_allocator: New.
        * doc/xml/manual/status_cxx200x.xml: Update.
        * testsuite/20_util/scoped_allocator/1.cc: New.
        * testsuite/20_util/scoped_allocator/propagation.cc: New.
        * testsuite/20_util/scoped_allocator/requirements/typedefs.cc: New.
        * testsuite/20_util/scoped_allocator/requirements/
        explicit_instantiation.cc: New.

Tested x86_64-linux, commited to trunk

Remaining allocator work is to make the other containers and
std::shared_ptr use the new C++0x model, and make std::function use an
allocator.

[-- Attachment #2: allocs.txt --]
[-- Type: text/plain, Size: 28529 bytes --]

Index: include/bits/stl_vector.h
===================================================================
--- include/bits/stl_vector.h	(revision 176072)
+++ include/bits/stl_vector.h	(working copy)
@@ -71,13 +71,15 @@
     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 @@
 	  _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 @@
 
       _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 @@
     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 @@
 
     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 @@
        *  @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 @@
       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 @@
        *  @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 @@
       {
 	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 @@
       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 @@
        */
       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: include/bits/vector.tcc
===================================================================
--- include/bits/vector.tcc	(revision 176072)
+++ include/bits/vector.tcc	(working copy)
@@ -94,8 +94,8 @@
       {
 	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 @@
       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 @@
       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 @@
     {
       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 @@
 	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 @@
     {
       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 @@
 	      // 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 @@
           __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);
Index: testsuite/util/testsuite_allocator.h
===================================================================
--- testsuite/util/testsuite_allocator.h	(revision 176072)
+++ testsuite/util/testsuite_allocator.h	(working copy)
@@ -371,6 +371,68 @@
       
       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
Index: testsuite/23_containers/vector/allocator/copy_assign.cc
===================================================================
--- testsuite/23_containers/vector/allocator/copy_assign.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/copy_assign.cc	(revision 0)
@@ -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;
+}
Index: testsuite/23_containers/vector/allocator/noexcept.cc
===================================================================
--- testsuite/23_containers/vector/allocator/noexcept.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/noexcept.cc	(revision 0)
@@ -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;
+}
Index: testsuite/23_containers/vector/allocator/copy.cc
===================================================================
--- testsuite/23_containers/vector/allocator/copy.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/copy.cc	(revision 0)
@@ -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;
+}
Index: testsuite/23_containers/vector/allocator/swap.cc
===================================================================
--- testsuite/23_containers/vector/allocator/swap.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/swap.cc	(revision 0)
@@ -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: testsuite/23_containers/vector/allocator/move_assign.cc
===================================================================
--- testsuite/23_containers/vector/allocator/move_assign.cc	(revision 0)
+++ testsuite/23_containers/vector/allocator/move_assign.cc	(revision 0)
@@ -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;
+}
Index: testsuite/23_containers/vector/requirements/dr438/assign_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/assign_neg.cc	(working copy)
@@ -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: testsuite/23_containers/vector/requirements/dr438/insert_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/insert_neg.cc	(working copy)
@@ -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: testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc	(working copy)
@@ -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: testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc
===================================================================
--- testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(revision 176072)
+++ testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc	(working copy)
@@ -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: doc/xml/manual/status_cxx200x.xml
===================================================================
--- doc/xml/manual/status_cxx200x.xml	(revision 176078)
+++ doc/xml/manual/status_cxx200x.xml	(working copy)
@@ -1009,52 +1009,47 @@ particular release.
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
+      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>20.12</entry>
       <entry>Scoped allocator adaptor</entry>
-      <entry/>
+      <entry>Partial</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.1</entry>
       <entry>Header <code>&lt;scoped_allocator&gt;</code> synopsis</entry>
       <entry/>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.2</entry>
       <entry>Scoped allocator adaptor member types</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.3</entry>
       <entry>Scoped allocator adaptor constructors</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
+      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>20.12.4</entry>
       <entry>Scoped allocator adaptor members</entry>
-      <entry>N</entry>
+      <entry>Partial</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.5</entry>
       <entry>Scoped allocator operators</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.13</entry>
       <entry>Class <code>type_index</code></entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [v3] add <scoped_allocator>
  2011-07-09 14:44 [v3] add <scoped_allocator> Jonathan Wakely
@ 2011-07-18 17:08 ` Jonathan Wakely
  2011-07-20 15:55   ` Ed Smith-Rowland
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2011-07-18 17:08 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 901 bytes --]

On 9 July 2011 14:46, Jonathan Wakely wrote:
> This adds the new <scoped_allocator> header. Currently only
> std::vector has the necessary support for C++0x allocators to be
> usable with std::scoped_allocator_adaptor.
>
>        * include/Makefile.am: Add new header.
>        * include/Makefile.in: Regenerate.
>        * include/std/scoped_allocator: New.
>        * doc/xml/manual/status_cxx200x.xml: Update.
>        * testsuite/20_util/scoped_allocator/1.cc: New.
>        * testsuite/20_util/scoped_allocator/propagation.cc: New.
>        * testsuite/20_util/scoped_allocator/requirements/typedefs.cc: New.
>        * testsuite/20_util/scoped_allocator/requirements/
>        explicit_instantiation.cc: New.
>
> Tested x86_64-linux, commited to trunk

Thanks to Francois for pointing out I attached the wrong patch, this
is the patch matching the changelog above, in r176079

[-- Attachment #2: sa.txt --]
[-- Type: text/plain, Size: 28793 bytes --]

Index: doc/xml/manual/status_cxx200x.xml
===================================================================
--- doc/xml/manual/status_cxx200x.xml	(revision 176078)
+++ doc/xml/manual/status_cxx200x.xml	(revision 176079)
@@ -1009,52 +1009,47 @@
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
+      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>20.12</entry>
       <entry>Scoped allocator adaptor</entry>
+      <entry>Partial</entry>
       <entry/>
-      <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.1</entry>
       <entry>Header <code>&lt;scoped_allocator&gt;</code> synopsis</entry>
       <entry/>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.2</entry>
       <entry>Scoped allocator adaptor member types</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.3</entry>
       <entry>Scoped allocator adaptor constructors</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
+      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>20.12.4</entry>
       <entry>Scoped allocator adaptor members</entry>
-      <entry>N</entry>
+      <entry>Partial</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.12.5</entry>
       <entry>Scoped allocator operators</entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry>20.13</entry>
       <entry>Class <code>type_index</code></entry>
-      <entry>N</entry>
+      <entry>Y</entry>
       <entry/>
     </row>
     <row>
Index: include/Makefile.in
===================================================================
--- include/Makefile.in	(revision 176078)
+++ include/Makefile.in	(revision 176079)
@@ -310,6 +310,7 @@
 	${std_srcdir}/random \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
+	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
Index: include/std/scoped_allocator
===================================================================
--- include/std/scoped_allocator	(revision 0)
+++ include/std/scoped_allocator	(revision 176079)
@@ -0,0 +1,373 @@
+// <scoped_allocator> -*- C++ -*-
+
+// Copyright (C) 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
+// 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/scoped_allocator
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _SCOPED_ALLOCATOR
+#define _SCOPED_ALLOCATOR 1
+
+#pragma GCC system_header
+
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
+# include <bits/c++0x_warning.h>
+#else
+
+#include <utility>
+#include <tuple>
+#include <bits/alloc_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<template<typename> class _Pred, typename... _Allocs>
+    struct __any_of;
+
+  template<template<typename> class _Pred, typename _Alloc, typename... _Allocs>
+    struct __any_of<_Pred, _Alloc, _Allocs...>
+    : __or_<_Pred<_Alloc>, __any_of<_Pred, _Allocs...>>
+    { };
+
+  template<template<typename> class _Pred, typename _Alloc>
+    struct __any_of<_Pred, _Alloc>
+    : _Pred<_Alloc>
+    { };
+
+  /**
+   * @addtogroup allocators
+   * @{
+   */
+
+  template<typename _Alloc>
+    struct __propagate_on_copy
+    : allocator_traits<_Alloc>::propagate_on_container_copy_assignment
+    { };
+  template<typename _Alloc>
+    struct __propagate_on_move
+    : allocator_traits<_Alloc>::propagate_on_container_move_assignment
+    { };
+  template<typename _Alloc>
+    struct __propagate_on_swap
+    : allocator_traits<_Alloc>::propagate_on_container_swap
+    { };
+
+  
+  template<typename _Alloc>
+    inline auto
+    __do_outermost(_Alloc& __a, _Alloc&) -> decltype(__a.outer_allocator())
+    { return __a.outer_allocator(); }
+
+  template<typename _Alloc>
+    inline _Alloc&
+    __do_outermost(_Alloc& __a, ...)
+    { return __a; }
+
+  template<typename _Alloc>
+    inline auto
+    __outermost(_Alloc& __a) -> decltype(__do_outermost(__a, __a))
+    { return __do_outermost(__a, __a); }
+
+  template<typename _OuterAlloc, typename... _InnerAllocs>
+    class scoped_allocator_adaptor;
+
+      template<typename...> struct __inner_type_impl;
+
+      template<typename _Outer>
+      struct __inner_type_impl<_Outer>
+      {
+	typedef scoped_allocator_adaptor<_Outer> __type;
+
+        __inner_type_impl() = default;
+        __inner_type_impl(const __inner_type_impl&) = default;
+        __inner_type_impl(__inner_type_impl&&) = default;
+
+	template<typename _Alloc>
+	  __inner_type_impl(const __inner_type_impl<_Alloc>& __other)
+	  { }
+
+	template<typename _Alloc>
+	  __inner_type_impl(__inner_type_impl<_Alloc>&& __other)
+	  { }
+
+	__type& _M_get(__type* __p) noexcept { return *__p; }
+	const __type& _M_get(const __type* __p) const noexcept { return *__p; }
+
+	tuple<> _M_tie() const noexcept { return tuple<>(); }
+
+	bool operator==(const __inner_type_impl&) const noexcept
+        { return true; }
+      };
+
+      template<typename _Outer, typename _InnerHead, typename... _InnerTail>
+      struct __inner_type_impl<_Outer, _InnerHead, _InnerTail...>
+      {
+	typedef scoped_allocator_adaptor<_InnerHead, _InnerTail...> __type;
+
+	__inner_type_impl() = default;
+        __inner_type_impl(const __inner_type_impl&) = default;
+        __inner_type_impl(__inner_type_impl&&) = default;
+
+	template<typename... _Allocs>
+	  __inner_type_impl(const __inner_type_impl<_Allocs...>& __other)
+	  : _M_inner(__other._M_inner) { }
+
+	template<typename... _Allocs>
+	  __inner_type_impl(__inner_type_impl<_Allocs...>&& __other)
+	  : _M_inner(std::move(__other._M_inner)) { }
+
+	template<typename... _Args>
+	  explicit
+	  __inner_type_impl(_Args&&... __args)
+	  : _M_inner(std::forward<_Args>(__args)...) { }
+
+	__type& _M_get(void*) noexcept { return _M_inner; }
+	const __type& _M_get(const void*) const noexcept { return _M_inner; }
+
+	tuple<const _InnerHead&, const _InnerTail&...> _M_tie() const noexcept
+	{ return _M_inner._M_tie(); }
+
+	bool operator==(const __inner_type_impl& __other) const noexcept
+	{ return _M_inner == __other._M_inner; }
+
+      private:
+	template<typename...> friend class __inner_type_impl;
+	template<typename, typename...> friend class scoped_allocator_adaptor;
+
+	__type _M_inner;
+      };
+
+  template<typename _OuterAlloc, typename... _InnerAllocs>
+    class scoped_allocator_adaptor
+    : public _OuterAlloc
+    {
+      typedef allocator_traits<_OuterAlloc> __traits;
+
+      typedef __inner_type_impl<_OuterAlloc, _InnerAllocs...> __inner_type;
+      __inner_type _M_inner;
+
+      template<typename _Outer, typename... _Inner>
+        friend class scoped_allocator_adaptor;
+
+      template<typename...>
+        friend class __inner_type_impl;
+
+      tuple<const _OuterAlloc&, const _InnerAllocs&...>
+      _M_tie() const noexcept
+      { return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); }
+
+      
+      template<typename _Tp, typename... _Args>
+        void _M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args)
+        {
+          auto& __outer = __outermost(*this);
+	  typedef typename std::decay<decltype(__outer)>::type __outer_type;
+          typedef allocator_traits<__outer_type> __o_traits;
+          __o_traits::construct(__outer, __p, std::forward<_Args>(__args)...);
+        }
+
+      typedef __uses_alloc1<typename __inner_type::__type> __uses_alloc1_;
+      typedef __uses_alloc2<typename __inner_type::__type> __uses_alloc2_;
+
+      template<typename _Tp, typename... _Args>
+        void _M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args)
+        {
+          auto& __outer = __outermost(*this);
+	  typedef typename std::decay<decltype(__outer)>::type __outer_type;
+          typedef allocator_traits<__outer_type> __o_traits;
+          __o_traits::construct(__outer, __p, allocator_arg, inner_allocator(),
+                                std::forward<_Args>(__args)...);
+        }
+
+      template<typename _Tp, typename... _Args>
+        void _M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args)
+        {
+	  auto& __outer = __outermost(*this);
+	  typedef typename std::decay<decltype(__outer)>::type __outer_type;
+          typedef allocator_traits<__outer_type> __o_traits;
+          __o_traits::construct(__outer, __p, std::forward<_Args>(__args)...,
+                                inner_allocator());
+        }
+
+      template<typename _Alloc>
+        static _Alloc
+        _S_select_on_copy(const _Alloc& __a)
+        {
+          typedef allocator_traits<_Alloc> __a_traits;
+          return __a_traits::select_on_container_copy_construction(__a);
+        }
+
+      template<int... _Indices>
+        scoped_allocator_adaptor(tuple<const _OuterAlloc&,
+                                       const _InnerAllocs&...> __refs,
+                                 _Index_tuple<_Indices...>)
+        : _OuterAlloc(_S_select_on_copy(std::get<0>(__refs))),
+          _M_inner(_S_select_on_copy(std::get<_Indices+1>(__refs))...)
+        { }
+
+    public:
+      typedef _OuterAlloc                       outer_allocator_type;
+      typedef typename __inner_type::__type     inner_allocator_type;
+
+      typedef typename __traits::value_type             value_type;
+      typedef typename __traits::size_type              size_type;
+      typedef typename __traits::difference_type        difference_type;
+      typedef typename __traits::pointer                pointer;
+      typedef typename __traits::const_pointer          const_pointer;
+      typedef typename __traits::void_pointer           void_pointer;
+      typedef typename __traits::const_void_pointer     const_void_pointer;
+
+      typedef typename conditional<
+        __any_of<__propagate_on_copy, _OuterAlloc, _InnerAllocs...>::value,
+        true_type, false_type>::type propagate_on_container_copy_assignment;
+      typedef typename conditional<
+        __any_of<__propagate_on_move, _OuterAlloc, _InnerAllocs...>::value,
+        true_type, false_type>::type propagate_on_container_move_assignment;
+      typedef typename conditional<
+        __any_of<__propagate_on_swap, _OuterAlloc, _InnerAllocs...>::value,
+        true_type, false_type>::type propagate_on_container_swap;
+
+      template <class _Tp>
+        struct rebind
+        {
+          // TODO: use rebind_alloc<Tp> instead of __rebind_alloc<Tp>::__type
+          typedef scoped_allocator_adaptor<
+            typename __traits::template __rebind_alloc<_Tp>::__type,
+            _InnerAllocs...> other;
+        };
+
+      scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
+
+      template<typename _Outer2>
+        scoped_allocator_adaptor(_Outer2&& __outer,
+                                 const _InnerAllocs&... __inner)
+        : _OuterAlloc(std::forward<_Outer2>(__outer)),
+          _M_inner(__inner...)
+        { }
+
+      scoped_allocator_adaptor(const scoped_allocator_adaptor& __other)
+      : _OuterAlloc(__other.outer_allocator()),
+	_M_inner(__other._M_inner)
+      { }
+
+      scoped_allocator_adaptor(scoped_allocator_adaptor&& __other)
+      : _OuterAlloc(std::move(__other.outer_allocator())),
+	_M_inner(std::move(__other._M_inner))
+      { }
+
+      template<typename _Outer2>
+        scoped_allocator_adaptor(
+            const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other)
+        : _OuterAlloc(__other.outer_allocator()),
+          _M_inner(__other._M_inner)
+        { }
+
+      template<typename _Outer2>
+        scoped_allocator_adaptor(
+            scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
+        : _OuterAlloc(std::move(__other.outer_allocator())),
+          _M_inner(std::move(__other._M_inner))
+        { }
+
+      inner_allocator_type& inner_allocator() noexcept
+      { return _M_inner._M_get(this); }
+
+      const inner_allocator_type& inner_allocator() const noexcept
+      { return _M_inner._M_get(this); }
+
+      outer_allocator_type& outer_allocator() noexcept
+      { return static_cast<_OuterAlloc&>(*this); }
+
+      const outer_allocator_type& outer_allocator() const noexcept
+      { return static_cast<const _OuterAlloc&>(*this); }
+
+      pointer allocate(size_type __n)
+      { return __traits::allocate(outer_allocator(), __n); }
+
+      pointer allocate(size_type __n, const_void_pointer __hint)
+      { return __traits::allocate(outer_allocator(), __n, __hint); }
+
+      void deallocate(pointer __p, size_type __n)
+      { return __traits::deallocate(outer_allocator(), __p, __n); }
+
+      size_type max_size() const
+      { return __traits::max_size(outer_allocator()); }
+
+      template<typename _Tp, typename... _Args>
+        void construct(_Tp* __p, _Args&&... __args)
+        {
+          auto& __inner = inner_allocator();
+          auto __use_tag
+            = __use_alloc<_Tp, inner_allocator_type, _Args...>(__inner);
+          _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
+        }
+
+      // TODO: construct pairs
+
+      template<typename _Tp>
+        void destroy(_Tp* __p)
+        {
+          auto& __outer = __outermost(*this);
+	  typedef typename std::decay<decltype(__outer)>::type __outer_type;
+          allocator_traits<__outer_type>::destroy(__outer, __p);
+        }
+
+      scoped_allocator_adaptor
+      select_on_container_copy_construction() const
+      {
+        typedef typename _Build_index_tuple<sizeof...(_InnerAllocs)>::__type
+	    _Indices;
+        return scoped_allocator_adaptor(_M_tie(), _Indices());
+      }
+
+      template <typename _OutA1, typename _OutA2, typename... _InA>
+      friend bool
+      operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
+                 const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept;
+    };
+
+  template <typename _OutA1, typename _OutA2, typename... _InA>
+    inline bool
+    operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
+               const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
+    {
+      return __a.outer_allocator() == __b.outer_allocator()
+          && __a._M_inner == __b._M_inner;
+    }
+
+  template <typename _OutA1, typename _OutA2, typename... _InA>
+    inline bool
+    operator!=(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
+               const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
+    { return !(__a == __b); }
+
+  /// @}
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#endif // __GXX_EXPERIMENTAL_CXX0X__
+
+#endif // _SCOPED_ALLOCATOR
Index: include/Makefile.am
===================================================================
--- include/Makefile.am	(revision 176078)
+++ include/Makefile.am	(revision 176079)
@@ -58,6 +58,7 @@
 	${std_srcdir}/random \
 	${std_srcdir}/ratio \
 	${std_srcdir}/regex \
+	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 176078)
+++ ChangeLog	(revision 176079)
@@ -1,5 +1,17 @@
 2011-07-09  Jonathan Wakely  <jwakely.gcc@gmail.com>
 
+	* include/Makefile.am: Add new header.
+	* include/Makefile.in: Regenerate.
+	* include/std/scoped_allocator: New.
+	* doc/xml/manual/status_cxx200x.xml: Update.
+	* testsuite/20_util/scoped_allocator/1.cc: New.
+	* testsuite/20_util/scoped_allocator/propagation.cc: New.
+	* testsuite/20_util/scoped_allocator/requirements/typedefs.cc: New.
+	* testsuite/20_util/scoped_allocator/requirements/
+	explicit_instantiation.cc: New.
+
+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.
Index: testsuite/20_util/scoped_allocator/requirements/typedefs.cc
===================================================================
--- testsuite/20_util/scoped_allocator/requirements/typedefs.cc	(revision 0)
+++ testsuite/20_util/scoped_allocator/requirements/typedefs.cc	(revision 176079)
@@ -0,0 +1,67 @@
+// { dg-options "-std=gnu++0x" }
+//
+// Copyright (C) 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
+// 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/>.
+
+// 
+// NB: This file is for testing scoped_allocator with NO OTHER INCLUDES.
+
+#include <scoped_allocator>
+
+// { dg-do compile }
+
+template<typename T>
+  struct minimal_allocator
+  {
+    typedef T value_type;
+    minimal_allocator();
+    template <typename U>
+      minimal_allocator(const minimal_allocator<U>&);
+    T* allocate(unsigned long);
+    void deallocate(T*, unsigned long);
+  };
+
+struct S
+{
+  typedef minimal_allocator<short> allocator_type;
+  S(const allocator_type&);
+};
+
+void test01()
+{
+  typedef minimal_allocator<S>                      outer_type;
+  typedef minimal_allocator<S::allocator_type>      inner_type;
+  typedef std::scoped_allocator_adaptor<outer_type, inner_type> test_type;
+
+  // Check for required typedefs
+  typedef typename test_type::outer_allocator_type  outer_allocator_type;
+  typedef typename test_type::inner_allocator_type  inner_allocator_type;
+  typedef typename test_type::value_type            value_type;
+  typedef typename test_type::size_type             size_type;
+  typedef typename test_type::difference_type       difference_type;
+  typedef typename test_type::pointer               pointer;
+  typedef typename test_type::const_pointer         const_pointer;
+  typedef typename test_type::void_pointer          void_pointer;
+  typedef typename test_type::const_void_pointer    const_void_pointer;
+  typedef typename test_type::propagate_on_container_copy_assignment
+    propagate_on_container_copy_assignment;
+  typedef typename test_type::propagate_on_container_move_assignment
+    propagate_on_container_move_assignment;
+  typedef typename test_type::propagate_on_container_swap
+    propagate_on_container_swap;
+}
+
Index: testsuite/20_util/scoped_allocator/requirements/explicit_instantiation.cc
===================================================================
--- testsuite/20_util/scoped_allocator/requirements/explicit_instantiation.cc	(revision 0)
+++ testsuite/20_util/scoped_allocator/requirements/explicit_instantiation.cc	(revision 176079)
@@ -0,0 +1,47 @@
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 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
+// 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/>.
+
+// NB: This file is for testing memory with NO OTHER INCLUDES.
+
+#include <scoped_allocator>
+#include <memory>
+
+typedef short test_type;
+
+template<typename T>
+  struct minimal_allocator
+  {
+    typedef T value_type;
+    minimal_allocator();
+    template <typename U>
+      minimal_allocator(const minimal_allocator<U>&);
+    T* allocate(unsigned long);
+    void deallocate(T*, unsigned long);
+  };
+
+namespace std
+{
+  template struct scoped_allocator_adaptor<std::allocator<test_type>>;
+
+  template struct scoped_allocator_adaptor<minimal_allocator<test_type>>;
+
+  template struct scoped_allocator_adaptor<std::allocator<test_type>,
+                                           minimal_allocator<test_type>>;
+}
Index: testsuite/20_util/scoped_allocator/1.cc
===================================================================
--- testsuite/20_util/scoped_allocator/1.cc	(revision 0)
+++ testsuite/20_util/scoped_allocator/1.cc	(revision 176079)
@@ -0,0 +1,99 @@
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 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
+// 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/>.
+
+#include <memory>
+#include <scoped_allocator>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::uneq_allocator;
+
+struct Element
+{
+  typedef uneq_allocator<Element> allocator_type;
+
+  allocator_type alloc;
+
+  Element(const allocator_type& a = allocator_type()) : alloc(a) { }
+
+  Element(std::allocator_arg_t, const allocator_type& a, int i = 0)
+  : alloc(a) { }
+
+  Element(std::allocator_arg_t, const allocator_type& a, const Element&)
+  : alloc(a) { }
+
+  const allocator_type& get_allocator() const { return alloc; }
+};
+
+void test01()
+{
+  bool test __attribute((unused)) = false;
+
+  typedef std::scoped_allocator_adaptor<Element::allocator_type> alloc1_type;
+
+  typedef std::vector<Element, alloc1_type> EltVec;
+
+  alloc1_type a1(1);
+  Element e;
+  EltVec ev1(1, e, a1);
+  VERIFY( ev1[0].get_allocator().get_personality() == 1 );
+}
+
+void test02()
+{
+  bool test __attribute((unused)) = false;
+
+  typedef std::vector<Element, Element::allocator_type> EltVec;
+
+  typedef std::scoped_allocator_adaptor<EltVec::allocator_type,
+	                                Element::allocator_type> alloc_type;
+
+  typedef std::vector<EltVec, alloc_type> EltVecVec;
+
+  alloc_type a(1, 2);
+  Element e;
+  EltVec ev(1, e);
+  EltVecVec evv(1, ev, a);
+
+  VERIFY( evv.get_allocator().get_personality() == 1 );
+  VERIFY( evv[0].get_allocator().get_personality() == 2 );
+  VERIFY( evv[0][0].get_allocator().get_personality() == 2 );
+
+  alloc_type a2(3, 4);
+
+  EltVecVec evv2(evv, a2); // copy with a different allocator
+
+  VERIFY( evv2.get_allocator().get_personality() == 3 );
+  VERIFY( evv2[0].get_allocator().get_personality() == 4 );
+  VERIFY( evv2[0][0].get_allocator().get_personality() == 4 );
+
+  EltVecVec evv3(std::move(evv), a2); // move with a different allocator
+
+  VERIFY( evv3.get_allocator().get_personality() == 3 );
+  VERIFY( evv3[0].get_allocator().get_personality() == 4 );
+  VERIFY( evv3[0][0].get_allocator().get_personality() == 4 );
+
+}
+
+
+int main()
+{
+  test01();
+}
Index: testsuite/20_util/scoped_allocator/propagation.cc
===================================================================
--- testsuite/20_util/scoped_allocator/propagation.cc	(revision 0)
+++ testsuite/20_util/scoped_allocator/propagation.cc	(revision 176079)
@@ -0,0 +1,105 @@
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 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
+// 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/>.
+
+// test that propagate_on_container_xxx is true iff it is true for
+// any of the outer or inner allocators
+
+#include <scoped_allocator>
+
+using std::scoped_allocator_adaptor;
+
+typedef short test_type;
+
+template<typename T>
+  struct minimal_allocator
+  {
+    typedef T value_type;
+    minimal_allocator();
+    template <typename U>
+      minimal_allocator(const minimal_allocator<U>&);
+    T* allocate(std::size_t);
+    void deallocate(T*, std::size_t);
+  };
+
+template<typename T, bool copy, bool move, bool swap>
+  struct test_allocator : minimal_allocator<T>
+  {
+    struct propagate_on_container_copy_assignment
+    { static const bool value = copy; };
+
+    struct propagate_on_container_move_assignment
+    { static const bool value = move; };
+
+    struct propagate_on_container_swap
+    { static const bool value = swap; };
+  };
+
+template<typename A>
+  constexpr bool prop_on_copy()
+  {
+    typedef typename A::propagate_on_container_copy_assignment type;
+    return type::value;
+  }
+
+template<typename A>
+  constexpr bool prop_on_move()
+  {
+    typedef typename A::propagate_on_container_move_assignment type;
+    return type::value;
+  }
+
+template<typename A>
+  constexpr bool prop_on_swap()
+  {
+    typedef typename A::propagate_on_container_swap type;
+    return type::value;
+  }
+
+template<typename A, bool C, bool M, bool S>
+  constexpr bool test1()
+  {
+    static_assert( prop_on_copy<A>() == C, "copy" );
+    static_assert( prop_on_move<A>() == M, "move" );
+    static_assert( prop_on_swap<A>() == S, "swap" );
+    return true;
+  }
+
+template<bool C, bool M, bool S>
+  constexpr bool test2()
+  {
+    typedef minimal_allocator<test_type>       base_alloc;
+    typedef test_allocator<test_type, C, M, S> test_alloc;
+    typedef scoped_allocator_adaptor<base_alloc, test_alloc> scoped1;
+    typedef scoped_allocator_adaptor<test_alloc, base_alloc> scoped2;
+    typedef scoped_allocator_adaptor<test_alloc, test_alloc> scoped3;
+    return test1<scoped1, C, M, S>()
+        && test1<scoped2, C, M, S>()
+        && test1<scoped3, C, M, S>();
+  }
+
+static_assert( test2<false, false, false>(), "never propagate" );
+static_assert( test2<true, false, false>(), "propagate on copy" );
+static_assert( test2<false, true, false>(), "propagate on move" );
+static_assert( test2<false, false, true>(), "propagate on swap" );
+static_assert( test2<true, true, false>(), "propagate on copy & move" );
+static_assert( test2<true, false, true>(), "propagate on copy & swap" );
+static_assert( test2<false, true, true>(), "propagate on move & swap" );
+static_assert( test2<true, true, true>(), "always propagate" );
+

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [v3] add <scoped_allocator>
  2011-07-18 17:08 ` Jonathan Wakely
@ 2011-07-20 15:55   ` Ed Smith-Rowland
  2011-07-20 16:10     ` Paolo Carlini
  0 siblings, 1 reply; 4+ messages in thread
From: Ed Smith-Rowland @ 2011-07-20 15:55 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1101 bytes --]

On 07/18/2011 12:18 PM, Jonathan Wakely wrote:
> On 9 July 2011 14:46, Jonathan Wakely wrote:
>> This adds the new<scoped_allocator>  header. Currently only
>> std::vector has the necessary support for C++0x allocators to be
>> usable with std::scoped_allocator_adaptor.
>>
>>         * include/Makefile.am: Add new header.
>>         * include/Makefile.in: Regenerate.
>>         * include/std/scoped_allocator: New.
>>         * doc/xml/manual/status_cxx200x.xml: Update.
>>         * testsuite/20_util/scoped_allocator/1.cc: New.
>>         * testsuite/20_util/scoped_allocator/propagation.cc: New.
>>         * testsuite/20_util/scoped_allocator/requirements/typedefs.cc: New.
>>         * testsuite/20_util/scoped_allocator/requirements/
>>         explicit_instantiation.cc: New.
>>
>> Tested x86_64-linux, commited to trunkx
> Thanks to Francois for pointing out I attached the wrong patch, this
> is the patch matching the changelog above, in r176079
All,

Here is a trivial addition to include scoped_allocator in the 
precompiled headers.
It bootstrapped and regtested on x86_64 linux.

Ed


[-- Attachment #2: CL --]
[-- Type: text/plain, Size: 108 bytes --]

2011-07-20  Ed Smith-Rowland  <3dw4rd@verizon.net>

	* include/precompiled/stdc++.h: Add scoped_allocator.


[-- Attachment #3: patch --]
[-- Type: text/plain, Size: 685 bytes --]

Index: include/precompiled/stdc++.h
===================================================================
--- include/precompiled/stdc++.h	(revision 176462)
+++ include/precompiled/stdc++.h	(working copy)
@@ -1,6 +1,6 @@
 // C++ includes used for precompiling -*- C++ -*-
 
-// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+// Copyright (C) 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
@@ -106,6 +106,7 @@
 #include <random>
 #include <ratio>
 #include <regex>
+#include <scoped_allocator>
 #include <system_error>
 #include <thread>
 #include <tuple>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [v3] add <scoped_allocator>
  2011-07-20 15:55   ` Ed Smith-Rowland
@ 2011-07-20 16:10     ` Paolo Carlini
  0 siblings, 0 replies; 4+ messages in thread
From: Paolo Carlini @ 2011-07-20 16:10 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: Jonathan Wakely, libstdc++, gcc-patches

On 07/20/2011 05:34 PM, Ed Smith-Rowland wrote:
>
> Here is a trivial addition to include scoped_allocator in the 
> precompiled headers. It bootstrapped and regtested on x86_64 linux.
Applied, thanks.

Paolo.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-07-20 15:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-09 14:44 [v3] add <scoped_allocator> Jonathan Wakely
2011-07-18 17:08 ` Jonathan Wakely
2011-07-20 15:55   ` Ed Smith-Rowland
2011-07-20 16:10     ` Paolo Carlini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).