public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Simplify allocator use
@ 2014-06-25 20:56 Jonathan Wakely
  2014-06-25 23:06 ` Jonathan Wakely
  2014-06-26 11:31 ` Jonathan Wakely
  0 siblings, 2 replies; 6+ messages in thread
From: Jonathan Wakely @ 2014-06-25 20:56 UTC (permalink / raw)
  To: libstdc++, gcc-patches

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

A couple of related patches that came out of some work on std::list
and std::string which is not ready yet.

One adds an alias template to simplify rebinding allocators.

The other adds an RAII type to help manage pointers obtained from
allocators. The new type means I can remove several ugly try-catch
blocks that are all very similar in structure and have been bothering
me for some time. The new type also makes it trivial to support
allocators with fancy pointers, fixing long-standing (but not very
important) bugs in std::promise and std::shared_ptr.

Tested x86_64-linux, committed to trunk.

[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3686 bytes --]

commit 3309b9fc32a266f5bf296aec8e8fcbbe6f41d81b
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 25 20:16:16 2014 +0100

    	* include/bits/alloc_traits.h (__alloc_rebind): Define alias template.
    	* include/bits/forward_list.h (_Fwd_list_base): Use __alloc_rebind.
    	* include/bits/hashtable_policy.h (_Insert_base, _Hashtable_alloc):
    	Likewise.
    	* include/ext/alloc_traits.h: Fix comment.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 23fe8de..3afcc6f 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -72,6 +72,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef _Alloc<_Tp, _Args...> __type;
     };
 
+  template<typename _Ptr, typename _Tp>
+    using __alloc_rebind = typename __alloctr_rebind<_Ptr, _Tp>::__type;
+
   /**
    * @brief  Uniform interface to all allocator types.
    * @ingroup allocators
diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index 524fad1..7cf699e 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -274,13 +274,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     struct _Fwd_list_base
     {
     protected:
-      typedef typename __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
-      typedef typename _Alloc_traits::template rebind<_Tp>::other
-        _Tp_alloc_type;
-
-      typedef typename _Alloc_traits::template
-        rebind<_Fwd_list_node<_Tp>>::other _Node_alloc_type;
-
+      typedef __alloc_rebind<_Alloc, _Tp> 		  _Tp_alloc_type;
+      typedef __alloc_rebind<_Alloc, _Fwd_list_node<_Tp>> _Node_alloc_type;
       typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;
 
       struct _Fwd_list_impl 
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index ef15b0e..606fbab 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -701,8 +701,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __unique_keys = typename __hashtable_base::__unique_keys;
       using __ireturn_type = typename __hashtable_base::__ireturn_type;
       using __node_type = _Hash_node<_Value, _Traits::__hash_cached::value>;
-      using __node_alloc_type =
-	typename __alloctr_rebind<_Alloc, __node_type>::__type;
+      using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>;
       using __node_gen_type = _AllocNode<__node_alloc_type>;
 
       __hashtable&
@@ -1898,13 +1897,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       using __value_type = typename __node_type::value_type;
       using __value_alloc_type =
-	typename __alloctr_rebind<__node_alloc_type, __value_type>::__type;
+	__alloc_rebind<__node_alloc_type, __value_type>;
       using __value_alloc_traits = std::allocator_traits<__value_alloc_type>;
 
       using __node_base = __detail::_Hash_node_base;
       using __bucket_type = __node_base*;      
       using __bucket_alloc_type =
-	typename __alloctr_rebind<__node_alloc_type, __bucket_type>::__type;
+	__alloc_rebind<__node_alloc_type, __bucket_type>;
       using __bucket_alloc_traits = std::allocator_traits<__bucket_alloc_type>;
 
       _Hashtable_alloc(const _Hashtable_alloc&) = default;
diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h
index 14fbc43..abdb611 100644
--- a/libstdc++-v3/include/ext/alloc_traits.h
+++ b/libstdc++-v3/include/ext/alloc_traits.h
@@ -210,6 +210,6 @@ template<typename _Alloc>
   };
 
 _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
+} // namespace __gnu_cxx
 
 #endif

[-- Attachment #3: patch-2.txt --]
[-- Type: text/x-patch, Size: 21080 bytes --]

commit 6339d3559931228c0c3e4ce6e0cebcb0b0b0265d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 25 16:03:52 2014 +0100

    	* include/Makefile.am: Add new header.
    	* include/Makefile.in: Regenerate.
    	* include/bits/allocated_ptr.h (__allocated_ptr, __allocate_guarded):
    	New RAII utilities for working with allocators.
    	* include/bits/shared_ptr_base.h (_Sp_counted_deleter): Define
    	__allocator_type typedef and use new __allocated_ptr type.
    	(_Sp_counted_ptr_inplace): Likewise.
    	(__shared_count::__shared_count, __shared_ptr::__shared_ptr): Use
    	__allocate_guarded to to simplify exception handling.
    	* include/experimental/any (any::_Manager_alloc::_S_alloc): Likewise.
    	* include/std/future (_Result_alloc::_M_destroy): Likewise.
    	(_Result_alloc::_S_allocate_result): Likewise.
    	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line number.
    	* testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise.
    	* testsuite/20_util/shared_ptr/creation/no_rtti.cc: New.
    	* testsuite/20_util/shared_ptr/creation/alloc.cc: Test allocator
    	with fancy pointer.
    	* testsuite/30_threads/promise/cons/alloc.cc: Likewise.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 8fe82da..e469586 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -80,6 +80,7 @@ bits_builddir = ./bits
 bits_headers = \
 	${bits_srcdir}/algorithmfwd.h \
 	${bits_srcdir}/alloc_traits.h \
+	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
 	${bits_srcdir}/basic_ios.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 51fde97..34ae1d1 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -347,6 +347,7 @@ bits_builddir = ./bits
 bits_headers = \
 	${bits_srcdir}/algorithmfwd.h \
 	${bits_srcdir}/alloc_traits.h \
+	${bits_srcdir}/allocated_ptr.h \
 	${bits_srcdir}/allocator.h \
 	${bits_srcdir}/atomic_base.h \
 	${bits_srcdir}/basic_ios.h \
diff --git a/libstdc++-v3/include/bits/allocated_ptr.h b/libstdc++-v3/include/bits/allocated_ptr.h
new file mode 100644
index 0000000..5cdce20
--- /dev/null
+++ b/libstdc++-v3/include/bits/allocated_ptr.h
@@ -0,0 +1,104 @@
+// Guarded Allocation -*- C++ -*-
+
+// Copyright (C) 2014 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 bits/allocated_ptr.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{memory}
+ */
+
+#ifndef _ALLOCATED_PTR_H
+#define _ALLOCATED_PTR_H 1
+
+#if __cplusplus < 201103L
+# include <bits/c++0xwarning.h>
+#else
+# include <type_traits>
+# include <bits/ptr_traits.h>
+# include <bits/alloc_traits.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /// Non-standard RAII type for managing pointers obtained from allocators.
+  template<typename _Alloc>
+    struct __allocated_ptr
+    {
+      using pointer = typename allocator_traits<_Alloc>::pointer;
+      using value_type = typename allocator_traits<_Alloc>::value_type;
+
+      /// Take ownership of __ptr
+      __allocated_ptr(_Alloc& __a, pointer __ptr) noexcept
+      : _M_alloc(&__a), _M_ptr(__ptr)
+      { }
+
+      /// Convert __ptr to allocator's pointer type and take ownership of it
+      template<typename _Ptr,
+	       typename _Req = _Require<is_same<_Ptr, value_type*>>>
+      __allocated_ptr(_Alloc& __a, _Ptr __ptr)
+      : _M_alloc(&__a), _M_ptr(pointer_traits<pointer>::pointer_to(*__ptr))
+      { }
+
+      /// Transfer ownership of the owned pointer
+      __allocated_ptr(__allocated_ptr&& __gd) noexcept
+      : _M_alloc(__gd._M_alloc), _M_ptr(__gd._M_ptr)
+      { __gd._M_ptr = nullptr; }
+
+      /// Deallocate the owned pointer
+      ~__allocated_ptr()
+      {
+	if (_M_ptr != nullptr)
+	  std::allocator_traits<_Alloc>::deallocate(*_M_alloc, _M_ptr, 1);
+      }
+
+      /// Release ownership of the owned pointer
+      __allocated_ptr& operator=(std::nullptr_t) noexcept { _M_ptr = nullptr; }
+
+      /// Get the address that the owned pointer refers to.
+      value_type* get() { return _S_raw_ptr(_M_ptr); }
+
+    private:
+      value_type* _S_raw_ptr(value_type* __ptr) { return __ptr; }
+
+      template<typename _Ptr>
+	auto _S_raw_ptr(_Ptr __ptr) -> decltype(_S_raw_ptr(__ptr.operator->()))
+	{ return _S_raw_ptr(__ptr.operator->()); }
+
+      _Alloc* _M_alloc;
+      pointer _M_ptr;
+    };
+
+  /// Allocate space for a single object using __a
+  template<typename _Alloc>
+    __allocated_ptr<_Alloc>
+    __allocate_guarded(_Alloc& __a)
+    {
+      return { __a, std::allocator_traits<_Alloc>::allocate(__a, 1) };
+    }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif
+#endif
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index c25157f..590a8d3 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -49,6 +49,7 @@
 #ifndef _SHARED_PTR_BASE_H
 #define _SHARED_PTR_BASE_H 1
 
+#include <bits/allocated_ptr.h>
 #include <ext/aligned_buffer.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -448,6 +449,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       };
 
     public:
+      using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;
+
       // __d(__p) must not throw.
       _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
       : _M_impl(__p, __d, _Alloc()) { }
@@ -465,11 +468,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual void
       _M_destroy() noexcept
       {
-	typedef typename allocator_traits<_Alloc>::template
-	  rebind_traits<_Sp_counted_deleter> _Alloc_traits;
-	typename _Alloc_traits::allocator_type __a(_M_impl._M_alloc());
-	_Alloc_traits::destroy(__a, this);
-	_Alloc_traits::deallocate(__a, this, 1);
+	__allocator_type __a(_M_impl._M_alloc());
+	__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
+	this->~_Sp_counted_deleter();
       }
 
       virtual void*
@@ -506,6 +507,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       };
 
     public:
+      using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;
+
       template<typename... _Args>
 	_Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
 	: _M_impl(__a)
@@ -528,11 +531,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual void
       _M_destroy() noexcept
       {
-	typedef typename allocator_traits<_Alloc>::template
-	  rebind_traits<_Sp_counted_ptr_inplace> _Alloc_traits;
-	typename _Alloc_traits::allocator_type __a(_M_impl._M_alloc());
-	_Alloc_traits::destroy(__a, this);
-	_Alloc_traits::deallocate(__a, this, 1);
+	__allocator_type __a(_M_impl._M_alloc());
+	__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
+	this->~_Sp_counted_ptr_inplace();
       }
 
       // Sneaky trick so __shared_ptr can get the managed pointer
@@ -584,22 +585,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
 	{
 	  typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
-	  typedef typename allocator_traits<_Alloc>::template
-	    rebind_traits<_Sp_cd_type> _Alloc_traits;
-	  typename _Alloc_traits::allocator_type __a2(__a);
-	  _Sp_cd_type* __mem = 0;
 	  __try
 	    {
-	      __mem = _Alloc_traits::allocate(__a2, 1);
-	      _Alloc_traits::construct(__a2, __mem,
-		  __p, std::move(__d), std::move(__a));
+	      typename _Sp_cd_type::__allocator_type __a2(__a);
+	      auto __guard = std::__allocate_guarded(__a2);
+	      _Sp_cd_type* __mem = __guard.get();
+	      ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
 	      _M_pi = __mem;
+	      __guard = nullptr;
 	    }
 	  __catch(...)
 	    {
 	      __d(__p); // Call _Deleter on __p.
-	      if (__mem)
-	        _Alloc_traits::deallocate(__a2, __mem, 1);
 	      __throw_exception_again;
 	    }
 	}
@@ -610,21 +607,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _M_pi(0)
 	{
 	  typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
-	  typedef typename allocator_traits<_Alloc>::template
-	    rebind_traits<_Sp_cp_type> _Alloc_traits;
-	  typename _Alloc_traits::allocator_type __a2(__a);
-	  _Sp_cp_type* __mem = _Alloc_traits::allocate(__a2, 1);
-	  __try
-	    {
-	      _Alloc_traits::construct(__a2, __mem, std::move(__a),
-		    std::forward<_Args>(__args)...);
-	      _M_pi = __mem;
-	    }
-	  __catch(...)
-	    {
-	      _Alloc_traits::deallocate(__a2, __mem, 1);
-	      __throw_exception_again;
-	    }
+	  typename _Sp_cp_type::__allocator_type __a2(__a);
+	  auto __guard = std::__allocate_guarded(__a2);
+	  _Sp_cp_type* __mem = __guard.get();
+	  ::new (__mem) _Sp_cp_type(std::move(__a),
+				    std::forward<_Args>(__args)...);
+	  _M_pi = __mem;
+	  __guard = nullptr;
 	}
 
 #if _GLIBCXX_USE_DEPRECATED
@@ -1096,11 +1085,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Alloc>
         struct _Deleter
         {
-          void operator()(_Tp* __ptr)
+          void operator()(typename _Alloc::pointer __ptr)
           {
-	    typedef allocator_traits<_Alloc> _Alloc_traits;
-	    _Alloc_traits::destroy(_M_alloc, __ptr);
-	    _Alloc_traits::deallocate(_M_alloc, __ptr, 1);
+	    __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
+	    allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());
           }
           _Alloc _M_alloc;
         };
@@ -1109,27 +1097,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
 		     _Args&&... __args)
 	: _M_ptr(), _M_refcount()
-        {
-	  typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;
-          _Deleter<_Alloc2> __del = { _Alloc2(__a) };
-	  typedef allocator_traits<_Alloc2> __traits;
-          _M_ptr = __traits::allocate(__del._M_alloc, 1);
-	  __try
-	    {
-	      // _GLIBCXX_RESOLVE_LIB_DEFECTS
-	      // 2070. allocate_shared should use allocator_traits<A>::construct
-	      __traits::construct(__del._M_alloc, _M_ptr,
-		                  std::forward<_Args>(__args)...);
-	    }
-	  __catch(...)
-	    {
-	      __traits::deallocate(__del._M_alloc, _M_ptr, 1);
-	      __throw_exception_again;
-	    }
-          __shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
-          _M_refcount._M_swap(__count);
+	{
+	  typedef typename allocator_traits<_Alloc>::template
+	    rebind_traits<_Tp> __traits;
+	  _Deleter<typename __traits::allocator_type> __del = { __a };
+	  auto __guard = std::__allocate_guarded(__del._M_alloc);
+	  _M_ptr = __guard.get();
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 2070. allocate_shared should use allocator_traits<A>::construct
+	  __traits::construct(__del._M_alloc, _M_ptr,
+			      std::forward<_Args>(__args)...);
+	  __guard = nullptr;
+	  __shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
+	  _M_refcount._M_swap(__count);
 	  __enable_shared_from_this_helper(_M_refcount, _M_ptr, _M_ptr);
-        }
+	}
 #endif
 
       template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index 643fc23..8f6e372 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -116,8 +116,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Tp, typename _Alloc>
       struct _Manager_alloc; // creates contained object using an allocator
 
-    template<typename _Tp, typename _Alloc, typename _TpAlloc
-	     = typename allocator_traits<_Alloc>::template rebind_alloc<_Tp>>
+    template<typename _Tp, typename _Alloc,
+	     typename _TpAlloc = __alloc_rebind<_Alloc, _Tp>>
       using _ManagerAlloc = conditional_t<_Internal<_Tp>::value,
 					  _Manager_internal<_Tp>,
 					  _Manager_alloc<_Tp, _TpAlloc>>;
@@ -501,19 +501,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     _S_alloc(const _Alloc& __a, _Up&& __value)
     {
       typename _Traits::allocator_type __a2(__a);
-      auto __ptr = _Traits::allocate(__a2, 1);
-      __try
-	{
-	  any::_Storage __storage;
-	  __storage._M_ptr = std::__addressof(*__ptr);
-	  ::new(__storage._M_ptr) _Data{__a, std::forward<_Up>(__value)};
-	  return __storage;
-	}
-      __catch(...)
-	{
-	  _Traits::deallocate(__a2, __ptr, 1);
-	  __throw_exception_again;
-	}
+      auto __guard = std::__allocate_guarded(__a2);
+      any::_Storage __storage;
+      __storage._M_ptr = __guard.get();
+      ::new(__storage._M_ptr) _Data{__a, std::forward<_Up>(__value)};
+      __guard = nullptr;
+      return __storage;
     }
 #endif
 
@@ -591,11 +584,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	break;
       case _Op_destroy:
 	{
-	  using _PtrTr = pointer_traits<typename _Traits::pointer>;
-	  typename _Traits::allocator_type __a(__ptr->_M_alloc());
-	  auto __alloc_ptr = _PtrTr::pointer_to(*const_cast<_Data*>(__ptr));
+	  using _Alloc2 = typename _Traits::allocator_type;
+	  _Alloc2 __a(__ptr->_M_alloc());
+	  __allocated_ptr<_Alloc2> __guard{__a, const_cast<_Data*>(__ptr)};
 	  __ptr->~_Data();
-	  _Traits::deallocate(__a, __alloc_ptr, 1);
 	}
 	break;
       }
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index 0949144..be2ed96 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -45,7 +45,7 @@
 #include <bits/unique_ptr.h>
 #include <bits/shared_ptr.h>
 #include <bits/uses_allocator.h>
-#include <bits/alloc_traits.h>
+#include <bits/allocated_ptr.h>
 #include <ext/aligned_buffer.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -251,42 +251,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Res, typename _Alloc>
       struct _Result_alloc final : _Result<_Res>, _Alloc
       {
-        typedef typename allocator_traits<_Alloc>::template
-          rebind_alloc<_Result_alloc> __allocator_type;
+	using __allocator_type = __alloc_rebind<_Alloc, _Result_alloc>;
 
         explicit
 	_Result_alloc(const _Alloc& __a) : _Result<_Res>(), _Alloc(__a)
-        { }
+	{ }
 	
       private:
 	void _M_destroy()
-        {
-	  typedef allocator_traits<__allocator_type> __traits;
-          __allocator_type __a(*this);
-	  __traits::destroy(__a, this);
-	  __traits::deallocate(__a, this, 1);
-        }
+	{
+	  __allocator_type __a(*this);
+	  __allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
+	  this->~_Result_alloc();
+	}
       };
 
     template<typename _Res, typename _Allocator>
       static _Ptr<_Result_alloc<_Res, _Allocator>>
       _S_allocate_result(const _Allocator& __a)
       {
-        typedef _Result_alloc<_Res, _Allocator>	__result_type;
-	typedef allocator_traits<typename __result_type::__allocator_type>
-	  __traits;
-        typename __traits::allocator_type __a2(__a);
-        __result_type* __p = __traits::allocate(__a2, 1);
-        __try
-	  {
-	    __traits::construct(__a2, __p, __a);
-	  }
-        __catch(...)
-	  {
-	    __traits::deallocate(__a2, __p, 1);
-	    __throw_exception_again;
-	  }
-        return _Ptr<__result_type>(__p);
+	using __result_type = _Result_alloc<_Res, _Allocator>;
+	typename __result_type::__allocator_type __a2(__a);
+	auto __guard = std::__allocate_guarded(__a2);
+	__result_type* __p = ::new((void*)__guard.get()) __result_type{__a};
+	__guard = nullptr;
+	return _Ptr<__result_type>(__p);
       }
 
     template<typename _Res, typename _Tp>
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
index fbd8ccd..dff0402 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
@@ -32,7 +32,7 @@ void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 875 }
+  // { dg-error "incomplete" "" { target *-*-* } 864 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
   // { dg-error "incomplete" "" { target *-*-* } 307 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc
index 3f93a5e..1ea114c 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc
@@ -25,5 +25,5 @@
 void test01()
 {
   std::shared_ptr<void> p((void*)nullptr);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 874 }
+  // { dg-error "incomplete" "" { target *-*-* } 863 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
index cd2712a..402c612 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
@@ -101,10 +101,25 @@ test02()
 	  == tracker_allocator_counter::get_deallocation_count() );
 }
 
+template<typename T>
+  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
+  {
+    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
+  };
+
+void
+test03()
+{
+  __gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
+  auto p = std::allocate_shared<int>(alloc, 1);
+  VERIFY( *p == 1 );
+}
+
 int
 main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc
new file mode 100644
index 0000000..127bafb
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc
@@ -0,0 +1,41 @@
+// { dg-options "-std=gnu++11 -fno-rtti" }
+// { dg-do compile }
+
+// Copyright (C) 2014 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/>.
+
+// 20.8.2.2 Class template shared_ptr [util.smartptr.shared]
+
+#include <memory>
+#include <testsuite_allocator.h>
+
+struct X { };
+
+// 20.8.2.2.6 shared_ptr creation [util.smartptr.shared.create]
+
+// test allocate_shared with no RTTI
+
+template<typename T>
+  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
+  {
+    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
+  };
+
+__gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
+
+auto p = std::allocate_shared<X>(alloc);
+
diff --git a/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc b/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
index ac8fb13..c45e646 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
@@ -27,14 +27,27 @@
 #include <testsuite_hooks.h>
 #include <testsuite_allocator.h>
 
+using std::promise;
+using std::allocator_arg;
+
 void test01()
 {
-  using std::promise;
-  using std::allocator_arg;
-  using __gnu_test::uneq_allocator;
+  __gnu_test::uneq_allocator<char> alloc(99);
+  promise<int> p1(allocator_arg, alloc);
+  p1.set_value(5);
+  VERIFY( p1.get_future().get() == 5 );
+}
 
-  uneq_allocator<char> alloc(99);
+template<typename T>
+  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
+  {
+    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
+  };
 
+void
+test02()
+{
+  __gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
   promise<int> p1(allocator_arg, alloc);
   p1.set_value(5);
   VERIFY( p1.get_future().get() == 5 );
@@ -43,5 +56,6 @@ void test01()
 int main()
 {
   test01();
+  test02();
   return 0;
 }

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

* Re: [patch] Simplify allocator use
  2014-06-25 20:56 [patch] Simplify allocator use Jonathan Wakely
@ 2014-06-25 23:06 ` Jonathan Wakely
  2014-06-26 12:44   ` Jonathan Wakely
  2014-06-26 11:31 ` Jonathan Wakely
  1 sibling, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2014-06-25 23:06 UTC (permalink / raw)
  To: libstdc++, gcc-patches

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

This simplifies some of the test changes in my last patch, I was
misusing the CustomPointerAlloc due to confusion with some uncommitted
changes.

Tested x86_64-linux, committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 2533 bytes --]

commit d1a05535e99bfecb427829d3e03ef82e0977e60c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 25 23:39:20 2014 +0100

    	* testsuite/20_util/shared_ptr/creation/alloc.cc: Fix use of test
    	allocator.
    	* testsuite/20_util/shared_ptr/creation/no_rtti.cc: Likewise.
    	* testsuite/30_threads/promise/cons/alloc.cc: Likewise.

diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
index 402c612..0628807 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/alloc.cc
@@ -101,16 +101,10 @@ test02()
 	  == tracker_allocator_counter::get_deallocation_count() );
 }
 
-template<typename T>
-  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
-  {
-    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
-  };
-
 void
 test03()
 {
-  __gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
+  __gnu_test::CustomPointerAlloc<int> alloc;
   auto p = std::allocate_shared<int>(alloc, 1);
   VERIFY( *p == 1 );
 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc
index 127bafb..d1fab6c 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/creation/no_rtti.cc
@@ -29,13 +29,7 @@ struct X { };
 
 // test allocate_shared with no RTTI
 
-template<typename T>
-  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
-  {
-    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
-  };
-
-__gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
+__gnu_test::CustomPointerAlloc<int> alloc;
 
 auto p = std::allocate_shared<X>(alloc);
 
diff --git a/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc b/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
index c45e646..ea9bb1a 100644
--- a/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
+++ b/libstdc++-v3/testsuite/30_threads/promise/cons/alloc.cc
@@ -38,16 +38,9 @@ void test01()
   VERIFY( p1.get_future().get() == 5 );
 }
 
-template<typename T>
-  struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
-  {
-    using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
-  };
-
-void
-test02()
+void test02()
 {
-  __gnu_test::CustomPointerAlloc<Pointer<int>> alloc;
+  __gnu_test::CustomPointerAlloc<int> alloc;
   promise<int> p1(allocator_arg, alloc);
   p1.set_value(5);
   VERIFY( p1.get_future().get() == 5 );

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

* Re: [patch] Simplify allocator use
  2014-06-25 20:56 [patch] Simplify allocator use Jonathan Wakely
  2014-06-25 23:06 ` Jonathan Wakely
@ 2014-06-26 11:31 ` Jonathan Wakely
  2014-06-26 11:35   ` Jonathan Wakely
  2014-06-27 21:29   ` François Dumont
  1 sibling, 2 replies; 6+ messages in thread
From: Jonathan Wakely @ 2014-06-26 11:31 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: François Dumont

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

On 25/06/14 21:56 +0100, Jonathan Wakely wrote:
>The other adds an RAII type to help manage pointers obtained from
>allocators. The new type means I can remove several ugly try-catch
>blocks that are all very similar in structure and have been bothering
>me for some time. The new type also makes it trivial to support
>allocators with fancy pointers, fixing long-standing (but not very
>important) bugs in std::promise and std::shared_ptr.

This patch applies the __allocated_ptr type to hashtable_policy.h to
remove most explicit deallocation (yay!)  The buckets are still
allocated and deallocated manually, because __allocated_ptr only works
for allocations of single objects, not arrays.

As well as __allocated_ptr this change relies on two things:

1) the node type has a trivial destructor, so we don't actually need
   to call it, we can just reuse or release its storage.
   (See 3.8 [basic.life] p1)

2) allocator_traits::construct and allocator_traits::destroy can be
   used with an allocator that has a different value_type, so we don't
   need to create a rebound copy to destroy every element, we can just
   use the node-allocator.
   (See http://cplusplus.github.io/LWG/lwg-active.html#2218 which is
   Open, but I've discussed the issue with Howard, Pablo and others,
   and I think libc++ already relies on this assumption).

François, could you check it, and let me know if you see anything
wrong or have any comments?


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3534 bytes --]

commit d2fd02daab715c79c766bc0a476d1d01da1fc305
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jun 26 12:28:56 2014 +0100

    	* include/bits/hashtable_policy.h (_ReuseOrAllocNode::operator()): Use
    	__allocated_ptr.
    	(_Hashtable_alloc::_M_allocate_node): Likewise.
    	(_Hashtable_alloc::_M_deallocate_node): Likewise.

diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 606fbab..ed6b2d7 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -31,6 +31,8 @@
 #ifndef _HASHTABLE_POLICY_H
 #define _HASHTABLE_POLICY_H 1
 
+#include <bits/allocated_ptr.h>
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -137,20 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      __node_type* __node = _M_nodes;
 	      _M_nodes = _M_nodes->_M_next();
 	      __node->_M_nxt = nullptr;
-	      __value_alloc_type __a(_M_h._M_node_allocator());
-	      __value_alloc_traits::destroy(__a, __node->_M_valptr());
-	      __try
-		{
-		  __value_alloc_traits::construct(__a, __node->_M_valptr(),
-						  std::forward<_Arg>(__arg));
-		}
-	      __catch(...)
-		{
-		  __node->~__node_type();
-		  __node_alloc_traits::deallocate(_M_h._M_node_allocator(),
-						  __node, 1);
-		  __throw_exception_again;
-		}
+	      auto& __a = _M_h._M_node_allocator();
+	      __node_alloc_traits::destroy(__a, __node->_M_valptr());
+	      __allocated_ptr<_NodeAlloc> __guard{__a, __node};
+	      __node_alloc_traits::construct(__a, __node->_M_valptr(),
+					     std::forward<_Arg>(__arg));
+	      __guard = nullptr;
 	      return __node;
 	    }
 	  return _M_h._M_allocate_node(std::forward<_Arg>(__arg));
@@ -1947,33 +1941,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typename _Hashtable_alloc<_NodeAlloc>::__node_type*
       _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&... __args)
       {
-	auto __nptr = __node_alloc_traits::allocate(_M_node_allocator(), 1);
-	__node_type* __n = std::__addressof(*__nptr);
-	__try
-	  {
-	    __value_alloc_type __a(_M_node_allocator());
-	    ::new ((void*)__n) __node_type;
-	    __value_alloc_traits::construct(__a, __n->_M_valptr(),
-					    std::forward<_Args>(__args)...);
-	    return __n;
-	  }
-	__catch(...)
-	  {
-	    __node_alloc_traits::deallocate(_M_node_allocator(), __nptr, 1);
-	    __throw_exception_again;
-	  }
+	auto& __a = _M_node_allocator();
+	auto __guard = std::__allocate_guarded(__a);
+	__node_type* __n = __guard.get();
+	::new ((void*)__n) __node_type;
+	__node_alloc_traits::construct(__a, __n->_M_valptr(),
+				       std::forward<_Args>(__args)...);
+	__guard = nullptr;
+	return __n;
       }
 
   template<typename _NodeAlloc>
     void
     _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node(__node_type* __n)
     {
-      typedef typename __node_alloc_traits::pointer _Ptr;
-      auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__n);
-      __value_alloc_type __a(_M_node_allocator());
-      __value_alloc_traits::destroy(__a, __n->_M_valptr());
-      __n->~__node_type();
-      __node_alloc_traits::deallocate(_M_node_allocator(), __ptr, 1);
+      static_assert(std::is_trivially_destructible<__node_type>::value,
+		    "Nodes must not require non-trivial destruction");
+      auto& __alloc = _M_node_allocator();
+      __allocated_ptr<__node_alloc_type> __guard{__alloc, __n};
+      __node_alloc_traits::destroy(__alloc, __n->_M_valptr());
     }
 
   template<typename _NodeAlloc>

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

* Re: [patch] Simplify allocator use
  2014-06-26 11:31 ` Jonathan Wakely
@ 2014-06-26 11:35   ` Jonathan Wakely
  2014-06-27 21:29   ` François Dumont
  1 sibling, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2014-06-26 11:35 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: François Dumont

On 26/06/14 12:31 +0100, Jonathan Wakely wrote:
>@@ -137,20 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> 	      __node_type* __node = _M_nodes;
> 	      _M_nodes = _M_nodes->_M_next();
> 	      __node->_M_nxt = nullptr;
>-	      __value_alloc_type __a(_M_h._M_node_allocator());
>-	      __value_alloc_traits::destroy(__a, __node->_M_valptr());
>-	      __try
>-		{
>-		  __value_alloc_traits::construct(__a, __node->_M_valptr(),
>-						  std::forward<_Arg>(__arg));
>-		}
>-	      __catch(...)
>-		{
>-		  __node->~__node_type();
>-		  __node_alloc_traits::deallocate(_M_h._M_node_allocator(),
>-						  __node, 1);

I forgot to mention the change also fixes a bug in the line above:
__node should be converted to the allocator's pointer type before
passing it to deallocate. Using __allocated_ptr takes care of that.

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

* Re: [patch] Simplify allocator use
  2014-06-25 23:06 ` Jonathan Wakely
@ 2014-06-26 12:44   ` Jonathan Wakely
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2014-06-26 12:44 UTC (permalink / raw)
  To: libstdc++, gcc-patches

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

On 26/06/14 00:06 +0100, Jonathan Wakely wrote:
>This simplifies some of the test changes in my last patch, I was
>misusing the CustomPointerAlloc due to confusion with some uncommitted
>changes.

And this fixes the -fno-rtti version of make_shared, I shouldn't have
changed the deleter's parameter to the allocator's pointer. That
worked with the current test, but only because our CustomPointerAlloc
uses a custom pointer that is implicitly-convertible from value_type*.

I have a completely rewritten custom pointer for the testsuite which
doesn't support implicit conversions (only the minimum requirements)
and that caught this bug.  The new custom pointer type is proving very
useful while I'm making some std::list changes but isn't ready for
prime-time yet.

Tested x86_64-linux, committed to trunk.

[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 815 bytes --]

commit e69d8134edde691db7ea2567032229b210dd263d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jun 26 13:27:30 2014 +0100

    	* include/bits/shared_ptr_base.h (__shared_ptr::_Deleter): Fix
    	parameter type.

diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index 590a8d3..6f85ffa 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -1085,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Alloc>
         struct _Deleter
         {
-          void operator()(typename _Alloc::pointer __ptr)
+          void operator()(_Tp* __ptr)
           {
 	    __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
 	    allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());

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

* Re: [patch] Simplify allocator use
  2014-06-26 11:31 ` Jonathan Wakely
  2014-06-26 11:35   ` Jonathan Wakely
@ 2014-06-27 21:29   ` François Dumont
  1 sibling, 0 replies; 6+ messages in thread
From: François Dumont @ 2014-06-27 21:29 UTC (permalink / raw)
  To: Jonathan Wakely, libstdc++, gcc-patches

On 26/06/2014 13:31, Jonathan Wakely wrote:
> On 25/06/14 21:56 +0100, Jonathan Wakely wrote:
>> The other adds an RAII type to help manage pointers obtained from
>> allocators. The new type means I can remove several ugly try-catch
>> blocks that are all very similar in structure and have been bothering
>> me for some time. The new type also makes it trivial to support
>> allocators with fancy pointers, fixing long-standing (but not very
>> important) bugs in std::promise and std::shared_ptr.
>
> This patch applies the __allocated_ptr type to hashtable_policy.h to
> remove most explicit deallocation (yay!)  The buckets are still
> allocated and deallocated manually, because __allocated_ptr only works
> for allocations of single objects, not arrays.
>
> As well as __allocated_ptr this change relies on two things:
>
> 1) the node type has a trivial destructor, so we don't actually need
>   to call it, we can just reuse or release its storage.
>   (See 3.8 [basic.life] p1)
>
> 2) allocator_traits::construct and allocator_traits::destroy can be
>   used with an allocator that has a different value_type, so we don't
>   need to create a rebound copy to destroy every element, we can just
>   use the node-allocator.
>   (See http://cplusplus.github.io/LWG/lwg-active.html#2218 which is
>   Open, but I've discussed the issue with Howard, Pablo and others,
>   and I think libc++ already relies on this assumption).
>
> François, could you check it, and let me know if you see anything
> wrong or have any comments?
>
That looks fine to me, nice simplification.

François

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

end of thread, other threads:[~2014-06-27 21:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-25 20:56 [patch] Simplify allocator use Jonathan Wakely
2014-06-25 23:06 ` Jonathan Wakely
2014-06-26 12:44   ` Jonathan Wakely
2014-06-26 11:31 ` Jonathan Wakely
2014-06-26 11:35   ` Jonathan Wakely
2014-06-27 21:29   ` François Dumont

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).