public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* testsuite allocators patch
@ 2014-06-20 20:37 François Dumont
  2014-06-25 19:48 ` François Dumont
  0 siblings, 1 reply; 17+ messages in thread
From: François Dumont @ 2014-06-20 20:37 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Hi

     I would like to finally propose this patch before the one on 
_Rb_tree, as a separate one.

     I have adopted the same evolution on the tracker_allocator with 
even a perfect forwarding constructor to allow its usage on top of the 
uneq_allocator  which take a personality parameter. Doing so I realized 
that move_assign_neg.cc tests were not accurate enough as they needed a 
non move propagating allocator and the uneq_allocator were not 
explicitly non propagating.

2014-06-21  François Dumont  <fdumont@gcc.gnu.org>

     * testsuite/util/testsuite_allocator.h
     (tracker_allocator_counter::allocate): Remove new invocation, only
     collect information.
     (tracker_allocator_counter::deallocate): Remove delete invocation, only
     collect information.
     (check_inconsistent_alloc_value_type): New.
     (tracker_allocator): Transform as a facade for any allocator type.
     (uneq_allocator): Likewise.
     (propagating_allocator): Likewise.
     * testsuite/23_containers/forward_list/debug/move_assign_neg.cc: Use an
     explicitly non propagating allocator.
     * testsuite/23_containers/map/debug/move_assign_neg.cc: Likewise.
     * testsuite/23_containers/multimap/debug/move_assign_neg.cc: likewise.
     * testsuite/23_containers/multiset/debug/move_assign_neg.cc: Likewise.
     * testsuite/23_containers/set/debug/move_assign_neg.cc: Likewise.
     * testsuite/23_containers/unordered_map/debug/move_assign_neg.cc:
     Likewise.
     * testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc:
     Likewise.
     * testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc:
     Likewise.
     * testsuite/23_containers/unordered_set/debug/move_assign_neg.cc:
     Likewise.
     * testsuite/23_containers/vector/debug/move_assign_neg.cc: Likewise.

Tested under Linux x86_64.

Ok to commit ?

François

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

* Re: testsuite allocators patch
  2014-06-20 20:37 testsuite allocators patch François Dumont
@ 2014-06-25 19:48 ` François Dumont
  2014-06-26 10:33   ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: François Dumont @ 2014-06-25 19:48 UTC (permalink / raw)
  To: libstdc++, gcc-patches

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

Hi

     With the patch this time.

>
>     I would like to finally propose this patch before the one on 
> _Rb_tree, as a separate one.
>
>     I have adopted the same evolution on the tracker_allocator with 
> even a perfect forwarding constructor to allow its usage on top of the 
> uneq_allocator  which take a personality parameter. Doing so I 
> realized that move_assign_neg.cc tests were not accurate enough as 
> they needed a non move propagating allocator and the uneq_allocator 
> were not explicitly non propagating.
>
> 2014-06-21  François Dumont  <fdumont@gcc.gnu.org>
>
>     * testsuite/util/testsuite_allocator.h
>     (tracker_allocator_counter::allocate): Remove new invocation, only
>     collect information.
>     (tracker_allocator_counter::deallocate): Remove delete invocation, 
> only
>     collect information.
>     (check_inconsistent_alloc_value_type): New.
>     (tracker_allocator): Transform as a facade for any allocator type.
>     (uneq_allocator): Likewise.
>     (propagating_allocator): Likewise.
>     * testsuite/23_containers/forward_list/debug/move_assign_neg.cc: 
> Use an
>     explicitly non propagating allocator.
>     * testsuite/23_containers/map/debug/move_assign_neg.cc: Likewise.
>     * testsuite/23_containers/multimap/debug/move_assign_neg.cc: 
> likewise.
>     * testsuite/23_containers/multiset/debug/move_assign_neg.cc: 
> Likewise.
>     * testsuite/23_containers/set/debug/move_assign_neg.cc: Likewise.
>     * testsuite/23_containers/unordered_map/debug/move_assign_neg.cc:
>     Likewise.
>     * 
> testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc:
>     Likewise.
>     * 
> testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc:
>     Likewise.
>     * testsuite/23_containers/unordered_set/debug/move_assign_neg.cc:
>     Likewise.
>     * testsuite/23_containers/vector/debug/move_assign_neg.cc: Likewise.
>
> Tested under Linux x86_64.
>
> Ok to commit ?
>
> François
>


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

Index: testsuite/util/testsuite_allocator.h
===================================================================
--- testsuite/util/testsuite_allocator.h	(revision 211713)
+++ testsuite/util/testsuite_allocator.h	(working copy)
@@ -29,6 +29,7 @@
 #include <tr1/unordered_map>
 #include <bits/move.h>
 #include <ext/pointer.h>
+#include <ext/alloc_traits.h>
 #include <testsuite_hooks.h>
 
 namespace __gnu_test
@@ -38,26 +39,19 @@
   public:
     typedef std::size_t    size_type; 
 
-    static void*
+    static void
     allocate(size_type blocksize)
-    {
-      void* p = ::operator new(blocksize);
-      allocationCount_ += blocksize;
-      return p;
-    }
+    { allocationCount_ += blocksize; }
 
     static void
-    construct() { constructCount_++; }
+    construct() { ++constructCount_; }
 
     static void
-    destroy() { destructCount_++; }
+    destroy() { ++destructCount_; }
 
     static void
-    deallocate(void* p, size_type blocksize)
-    {
-      ::operator delete(p);
-      deallocationCount_ += blocksize;
-    }
+    deallocate(size_type blocksize)
+    { deallocationCount_ += blocksize; }
 
     static size_type
     get_allocation_count() { return allocationCount_; }
@@ -87,103 +81,142 @@
     static int        destructCount_;
   };
 
-  // A simple basic allocator that just forwards to the
+  // Helper to detect inconsistency between type used to instantiate an
+  // allocator and the underlying allocator value_type.
+  template<typename T, typename Alloc,
+	   typename = typename Alloc::value_type>
+    struct check_consistent_alloc_value_type;
+
+  template<typename T, typename Alloc>
+    struct check_consistent_alloc_value_type<T, Alloc, T>
+    { typedef T value_type; };
+
+  // An allocator facade that just intercepts some calls and forward them to the
   // tracker_allocator_counter to fulfill memory requests.  This class
   // is templated on the target object type, but tracker isn't.
-  template<class T>
-  class tracker_allocator
-  {
-  private:
-    typedef tracker_allocator_counter counter_type;
+  template<typename T, typename Alloc = std::allocator<T> >
+    class tracker_allocator : public Alloc
+    {
+    private:
+      typedef tracker_allocator_counter counter_type;
 
-  public:
-    typedef T              value_type;
-    typedef T*             pointer;
-    typedef const T*       const_pointer;
-    typedef T&             reference;
-    typedef const T&       const_reference;
-    typedef std::size_t    size_type; 
-    typedef std::ptrdiff_t difference_type; 
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
+
+    public:
+      typedef typename
+      check_consistent_alloc_value_type<T, Alloc>::value_type value_type;
+      typedef typename AllocTraits::pointer pointer;
+      typedef typename AllocTraits::size_type size_type;
     
-    template<class U> struct rebind { typedef tracker_allocator<U> other; };
+      template<class U>
+	struct rebind
+	{
+	  typedef tracker_allocator<U,
+		typename AllocTraits::template rebind<U>::other> other;
+	};
     
-    pointer
-    address(reference value) const _GLIBCXX_NOEXCEPT
-    { return std::__addressof(value); }
+#if __cplusplus >= 201103L
+      tracker_allocator() = default;
+      tracker_allocator(const tracker_allocator&) = default;
+      tracker_allocator(tracker_allocator&&) = default;
 
-    const_pointer
-    address(const_reference value) const _GLIBCXX_NOEXCEPT
-    { return std::__addressof(value); }
+      // Perfect forwarding constructor.
+      template<typename... _Args>
+	tracker_allocator(_Args&&... __args)
+	  : Alloc(std::forward<_Args>(__args)...)
+	{ }
+#else
+      tracker_allocator() _GLIBCXX_USE_NOEXCEPT
+      { }
 
-    tracker_allocator() _GLIBCXX_USE_NOEXCEPT
-    { }
+      tracker_allocator(const tracker_allocator&) _GLIBCXX_USE_NOEXCEPT
+      { }
 
-    tracker_allocator(const tracker_allocator&) _GLIBCXX_USE_NOEXCEPT
-    { }
-
-    template<class U>
-      tracker_allocator(const tracker_allocator<U>&) _GLIBCXX_USE_NOEXCEPT
+      ~tracker_allocator() _GLIBCXX_USE_NOEXCEPT
       { }
+#endif
 
-    ~tracker_allocator() _GLIBCXX_USE_NOEXCEPT
-    { }
+      template<class U>
+	tracker_allocator(const tracker_allocator<U,
+	  typename AllocTraits::template rebind<U>::other>& alloc)
+	    _GLIBCXX_USE_NOEXCEPT
+	  : Alloc(alloc)
+	{ }
 
-    size_type
-    max_size() const _GLIBCXX_USE_NOEXCEPT
-    { return size_type(-1) / sizeof(T); }
+      pointer
+      allocate(size_type n, const void* = 0)
+      {
+	pointer p = AllocTraits::allocate(*this, n);
+	counter_type::allocate(n * sizeof(T));
+	return p;
+      }
 
-    pointer
-    allocate(size_type n, const void* = 0)
-    { return static_cast<pointer>(counter_type::allocate(n * sizeof(T))); }
+#if __cplusplus >= 201103L
+      template<typename U, typename... Args>
+	void
+	construct(U* p, Args&&... args) 
+	{
+	  AllocTraits::construct(*this, p, std::forward<Args>(args)...);
+	  counter_type::construct();
+	}
 
-#if __cplusplus >= 201103L
-    template<typename U, typename... Args>
+      template<typename U>
+	void
+	destroy(U* p)
+	{
+	  AllocTraits::destroy(*this, p);
+	  counter_type::destroy();
+	}
+#else
       void
-      construct(U* p, Args&&... args) 
+      construct(pointer p, const T& value)
       {
-	::new((void *)p) U(std::forward<Args>(args)...);
+	AllocTraits::construct(*this, p, value);
 	counter_type::construct();
       }
 
-    template<typename U>
       void
-      destroy(U* p)
+      destroy(pointer p)
       {
-	p->~U();
+	AllocTraits::destroy(*this, p);
 	counter_type::destroy();
       }
-#else
-    void
-    construct(pointer p, const T& value)
-    {
-      ::new ((void *)p) T(value);
-      counter_type::construct();
-    }
-
-    void
-    destroy(pointer p)
-    {
-      p->~T();
-      counter_type::destroy();
-    }
 #endif
 
-    void
-    deallocate(pointer p, size_type num)
-    { counter_type::deallocate(p, num * sizeof(T)); }
-  };
+      void
+      deallocate(pointer p, size_type num)
+      {
+	counter_type::deallocate(num * sizeof(T));
+	AllocTraits::deallocate(*this, p, num);
+      }
 
-  template<class T1, class T2>
+      // Implement swap for underlying allocators that might need it.
+      friend inline void
+      swap(tracker_allocator& a, tracker_allocator& b)
+      {
+	using std::swap;
+
+	Alloc& aa = a;
+	Alloc& ab = b;
+	swap(aa, ab);
+      } 
+    };
+
+  template<class T1, class Alloc1, class T2, class Alloc2>
     bool
-    operator==(const tracker_allocator<T1>&, 
-	       const tracker_allocator<T2>&) throw()
-    { return true; }
+    operator==(const tracker_allocator<T1, Alloc1>& lhs, 
+	       const tracker_allocator<T2, Alloc2>& rhs) throw()
+    {
+      const Alloc1& alloc1 = lhs;
+      const Alloc2& alloc2 = rhs;
+      return lhs == rhs;
+    }
 
-  template<class T1, class T2>
+  template<class T1, class Alloc1, class T2, class Alloc2>
     bool
-    operator!=(const tracker_allocator<T1>&, 
-	       const tracker_allocator<T2>&) throw()
-    { return false; }
+    operator!=(const tracker_allocator<T1, Alloc1>& lhs, 
+	       const tracker_allocator<T2, Alloc2>& rhs) throw()
+    { return !(lhs == rhs); }
 
   bool
   check_construct_destroy(const char* tag, int expected_c, int expected_d);
@@ -219,7 +252,6 @@
       throw;
     }
 
-
   // A simple allocator which can be constructed endowed of a given
   // "personality" (an integer), queried in operator== to simulate the
   // behavior of realworld "unequal" allocators (i.e., not exploiting
@@ -227,7 +259,7 @@
   // filled at allocation time with (pointer, personality) pairs, is
   // then consulted to enforce the requirements in Table 32 about
   // deallocation vs allocator equality.  Note that this allocator is
-  // swappable, not assignable, consistently with Option 3 of DR 431
+  // swappable, not copy assignable, consistently with Option 3 of DR 431
   // (see N1599).
   struct uneq_allocator_base
   {
@@ -244,26 +276,33 @@
     }
   };
 
-  template<typename Tp>
+  template<typename Tp, typename Alloc = std::allocator<Tp> >
     class uneq_allocator
-    : private uneq_allocator_base
+    : private uneq_allocator_base,
+      public Alloc
     {
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
+
+      Alloc& base() { return *this; }
+      const Alloc& base() const  { return *this; }
+      void swap_base(Alloc& b) { swap(b, this->base()); }
+
     public:
-      typedef std::size_t                         size_type;
-      typedef std::ptrdiff_t                      difference_type;
-      typedef Tp*                                 pointer;
-      typedef const Tp*                           const_pointer;
-      typedef Tp&                                 reference;
-      typedef const Tp&                           const_reference;
-      typedef Tp                                  value_type;
+      typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
+	value_type;
+      typedef typename AllocTraits::size_type	size_type;
+      typedef typename AllocTraits::pointer	pointer;
 
 #if __cplusplus >= 201103L
-      typedef std::true_type                      propagate_on_container_swap;
+      typedef std::true_type			propagate_on_container_swap;
 #endif
 
       template<typename Tp1>
-        struct rebind
-	{ typedef uneq_allocator<Tp1> other; };
+	struct rebind
+	{
+	  typedef uneq_allocator<Tp1,
+		typename AllocTraits::template rebind<Tp1>::other> other;
+	};
 
       uneq_allocator() _GLIBCXX_USE_NOEXCEPT
       : personality(0) { }
@@ -272,7 +311,9 @@
       : personality(person) { }
       
       template<typename Tp1>
-        uneq_allocator(const uneq_allocator<Tp1>& b) _GLIBCXX_USE_NOEXCEPT
+	uneq_allocator(const uneq_allocator<Tp1,
+		       typename AllocTraits::template rebind<Tp1>::other>& b)
+	_GLIBCXX_USE_NOEXCEPT
 	: personality(b.get_personality()) { }
 
       ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
@@ -281,20 +322,9 @@
       int get_personality() const { return personality; }
       
       pointer
-      address(reference x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(x); }
-    
-      const_pointer
-      address(const_reference x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(x); }
-
-      pointer
-      allocate(size_type n, const void* = 0)
+      allocate(size_type n, const void* hint = 0)
       { 
-	if (__builtin_expect(n > this->max_size(), false))
-	  std::__throw_bad_alloc();
-	
-	pointer p = static_cast<Tp*>(::operator new(n * sizeof(Tp)));
+	pointer p = AllocTraits::allocate(*this, n);
 	try
 	  {
 	    get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
@@ -302,7 +332,7 @@
 	  }
 	catch(...)
 	  {
-	    ::operator delete(p);
+	    AllocTraits::deallocate(*this, p, n);
 	    __throw_exception_again;
 	  }
 	return p;
@@ -309,7 +339,7 @@
       }
 
       void
-      deallocate(pointer p, size_type)
+      deallocate(pointer p, size_type n)
       {
 	bool test __attribute__((unused)) = true;
 
@@ -323,34 +353,18 @@
 	VERIFY( it->second == personality );
 
 	get_map().erase(it);
-	::operator delete(p);
+	AllocTraits::deallocate(*this, p, n);
       }
 
-      size_type
-      max_size() const _GLIBCXX_USE_NOEXCEPT 
-      { return size_type(-1) / sizeof(Tp); }
-
 #if __cplusplus >= 201103L
-      template<typename U, typename... Args>
-        void
-        construct(U* p, Args&&... args) 
-	{ ::new((void *)p) U(std::forward<Args>(args)...); }
-
-      template<typename U>
-	void 
-	destroy(U* p) { p->~U(); }
-
       // Not copy assignable...
       uneq_allocator&
       operator=(const uneq_allocator&) = delete;
+
+      // ... but still moveable if base allocator is.
+      uneq_allocator&
+      operator=(uneq_allocator&&) = default;
 #else
-      void 
-      construct(pointer p, const Tp& val) 
-      { ::new((void *)p) Tp(val); }
-
-      void 
-      destroy(pointer p) { p->~Tp(); }
-
     private:
       // Not assignable...
       uneq_allocator&
@@ -358,21 +372,27 @@
 #endif
 
     private:
-
       // ... yet swappable!
       friend inline void
       swap(uneq_allocator& a, uneq_allocator& b)
-      { std::swap(a.personality, b.personality); } 
-      
+      {
+	std::swap(a.personality, b.personality);
+	a.swap_base(b);
+      } 
+
       template<typename Tp1>
-        friend inline bool
-        operator==(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
-        { return a.personality == b.personality; }
+	friend inline bool
+	operator==(const uneq_allocator& a,
+		   const uneq_allocator<Tp1,
+		   typename AllocTraits::template rebind<Tp1>::other>& b)
+	{ return a.personality == b.personality; }
 
       template<typename Tp1>
-        friend inline bool
-        operator!=(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
-        { return !(a == b); }
+	friend inline bool
+	operator!=(const uneq_allocator& a,
+		   const uneq_allocator<Tp1,
+		   typename AllocTraits::template rebind<Tp1>::other>& b)
+	{ return !(a == b); }
       
       int personality;
     };
@@ -379,10 +399,12 @@
 
 #if __cplusplus >= 201103L
   // An uneq_allocator which can be used to test allocator propagation.
-  template<typename Tp, bool Propagate>
-    class propagating_allocator : public uneq_allocator<Tp>
+  template<typename Tp, bool Propagate, typename Alloc = std::allocator<Tp>>
+    class propagating_allocator : public uneq_allocator<Tp, Alloc>
     {
-      typedef uneq_allocator<Tp> base_alloc;
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
+
+      typedef uneq_allocator<Tp, Alloc> base_alloc;
       base_alloc& base() { return *this; }
       const base_alloc& base() const  { return *this; }
       void swap_base(base_alloc& b) { swap(b, this->base()); }
@@ -393,7 +415,11 @@
       // default allocator_traits::rebind_alloc would select
       // uneq_allocator::rebind so we must define rebind here
       template<typename Up>
-	struct rebind { typedef propagating_allocator<Up, Propagate> other; };
+	struct rebind
+	{
+	  typedef propagating_allocator<Up, Propagate,
+		typename AllocTraits::template rebind<Up>::other> other;
+	};
 
       propagating_allocator(int i) noexcept
       : base_alloc(i)
@@ -400,8 +426,9 @@
       { }
 
       template<typename Up>
-	propagating_allocator(const propagating_allocator<Up, Propagate>& a)
-       	noexcept
+	propagating_allocator(const propagating_allocator<Up, Propagate,
+			      typename AllocTraits::template rebind<Up>::other>& a)
+	noexcept
 	: base_alloc(a)
 	{ }
 
@@ -418,8 +445,8 @@
       }
 
       template<bool P2>
-  	propagating_allocator&
-  	operator=(const propagating_allocator<Tp, P2>& a) noexcept
+	propagating_allocator&
+	operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
   	{
 	  static_assert(P2, "assigning propagating_allocator<T, true>");
 	  propagating_allocator(a).swap_base(*this);
Index: testsuite/23_containers/forward_list/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/forward_list/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/forward_list/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::forward_list<int, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/map/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/map/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/map/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::map<int, int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/multimap/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/multimap/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/multimap/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::multimap<int, int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/multiset/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/multiset/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/multiset/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::multiset<int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/set/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/set/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/set/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::set<int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/unordered_map/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_map/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/unordered_map/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::unordered_map<int, int,
 				     std::hash<int>, std::equal_to<int>,
 				     alloc_type> test_type;
Index: testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int>> alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::unordered_multimap<int, int, std::hash<int>,
 					  std::equal_to<int>,
 					  alloc_type> test_type;
Index: testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::unordered_multiset<int, std::hash<int>,
 					  std::equal_to<int>,
 					  alloc_type> test_type;
Index: testsuite/23_containers/unordered_set/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_set/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/unordered_set/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::unordered_set<int, std::hash<int>,
 				     std::equal_to<int>,
 				     alloc_type> test_type;
Index: testsuite/23_containers/vector/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/vector/debug/move_assign_neg.cc	(revision 211713)
+++ testsuite/23_containers/vector/debug/move_assign_neg.cc	(working copy)
@@ -27,7 +27,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::vector<int, alloc_type> test_type;
 
   test_type v1(alloc_type(1));

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

* Re: testsuite allocators patch
  2014-06-25 19:48 ` François Dumont
@ 2014-06-26 10:33   ` Jonathan Wakely
  2014-06-26 20:45     ` François Dumont
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-06-26 10:33 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 25/06/14 21:47 +0200, François Dumont wrote:
>>    I would like to finally propose this patch before the one on 
>>_Rb_tree, as a separate one.
>>
>>    I have adopted the same evolution on the tracker_allocator with 
>>even a perfect forwarding constructor to allow its usage on top of 
>>the uneq_allocator  which take a personality parameter. Doing so I 
>>realized that move_assign_neg.cc tests were not accurate enough as 
>>they needed a non move propagating allocator and the uneq_allocator 
>>were not explicitly non propagating.

Ah, that's good to improve them then.

>Index: testsuite/util/testsuite_allocator.h
>===================================================================
>--- testsuite/util/testsuite_allocator.h	(revision 211713)
>+++ testsuite/util/testsuite_allocator.h	(working copy)
>@@ -87,103 +81,142 @@
>     static int        destructCount_;
>   };
> 
>-  // A simple basic allocator that just forwards to the
>+  // Helper to detect inconsistency between type used to instantiate an
>+  // allocator and the underlying allocator value_type.
>+  template<typename T, typename Alloc,
>+	   typename = typename Alloc::value_type>
>+    struct check_consistent_alloc_value_type;
>+
>+  template<typename T, typename Alloc>
>+    struct check_consistent_alloc_value_type<T, Alloc, T>
>+    { typedef T value_type; };
>+
>+  // An allocator facade that just intercepts some calls and forward them to the
>   // tracker_allocator_counter to fulfill memory requests.  This class

This comment is no longer true, tracker_allocator_counter does not
fulfil the memory requests.

>   // is templated on the target object type, but tracker isn't.
>-  template<class T>
>-  class tracker_allocator
>-  {
>-  private:
>-    typedef tracker_allocator_counter counter_type;
>+  template<typename T, typename Alloc = std::allocator<T> >
>+    class tracker_allocator : public Alloc
>+    {
>+    private:
>+      typedef tracker_allocator_counter counter_type;
> 
>-  public:
>-    typedef T              value_type;
>-    typedef T*             pointer;
>-    typedef const T*       const_pointer;
>-    typedef T&             reference;
>-    typedef const T&       const_reference;
>-    typedef std::size_t    size_type; 
>-    typedef std::ptrdiff_t difference_type; 
>+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
>+
>+    public:
>+      typedef typename
>+      check_consistent_alloc_value_type<T, Alloc>::value_type value_type;
>+      typedef typename AllocTraits::pointer pointer;
>+      typedef typename AllocTraits::size_type size_type;

Thanks for doing this - I think it makes the facade more useful if it
uses allocator_traits and so can be combined with SimpleAllocator and
CustomPointerAlloc.

>-    template<class U> struct rebind { typedef tracker_allocator<U> other; };
>+      template<class U>
>+	struct rebind
>+	{
>+	  typedef tracker_allocator<U,
>+		typename AllocTraits::template rebind<U>::other> other;
>+	};
>     
>-    pointer
>-    address(reference value) const _GLIBCXX_NOEXCEPT
>-    { return std::__addressof(value); }
>+#if __cplusplus >= 201103L
>+      tracker_allocator() = default;
>+      tracker_allocator(const tracker_allocator&) = default;
>+      tracker_allocator(tracker_allocator&&) = default;
> 
>-    const_pointer
>-    address(const_reference value) const _GLIBCXX_NOEXCEPT
>-    { return std::__addressof(value); }
>+      // Perfect forwarding constructor.
>+      template<typename... _Args>
>+	tracker_allocator(_Args&&... __args)
>+	  : Alloc(std::forward<_Args>(__args)...)
>+	{ }
>+#else
>+      tracker_allocator() _GLIBCXX_USE_NOEXCEPT

The _GLIBCXX_USE_NOEXCEPT macro expands to nothing in C++03 mode, so
you might as well omit it in the #else branch.

OK for trunk if you make the tracker_allocator comment correct.

Thanks!

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

* Re: testsuite allocators patch
  2014-06-26 10:33   ` Jonathan Wakely
@ 2014-06-26 20:45     ` François Dumont
  2014-06-26 21:24       ` Paolo Carlini
  0 siblings, 1 reply; 17+ messages in thread
From: François Dumont @ 2014-06-26 20:45 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

On 26/06/2014 12:33, Jonathan Wakely wrote:
>
> The _GLIBCXX_USE_NOEXCEPT macro expands to nothing in C++03 mode, so
> you might as well omit it in the #else branch.
>
> OK for trunk if you make the tracker_allocator comment correct.
>
> Thanks!
>
>
Committed with:

   // An allocator facade that intercepts 
allocate/deallocate/construct/destroy
   // calls and track them through the tracker_allocator_counter class. This
   // class is templated on the target object type, but tracker isn't.
   template<typename T, typename Alloc = std::allocator<T> >
     class tracker_allocator : public Alloc

Thanks for feedback.

François

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

* Re: testsuite allocators patch
  2014-06-26 20:45     ` François Dumont
@ 2014-06-26 21:24       ` Paolo Carlini
  2014-06-26 22:39         ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2014-06-26 21:24 UTC (permalink / raw)
  To: François Dumont, Jonathan Wakely; +Cc: libstdc++, gcc-patches

Hi,

I'm afraid something went badly wrong with this commit, I'm seeing tens 
of fails. See eg:

     https://gcc.gnu.org/ml/gcc-testresults/2014-06/msg02439.html

Paolo.

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

* Re: testsuite allocators patch
  2014-06-26 21:24       ` Paolo Carlini
@ 2014-06-26 22:39         ` Jonathan Wakely
  2014-06-27  7:30           ` Paolo Carlini
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-06-26 22:39 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: François Dumont, libstdc++, gcc-patches

On 26/06/14 23:21 +0200, Paolo Carlini wrote:
>Hi,
>
>I'm afraid something went badly wrong with this commit, I'm seeing 
>tens of fails. See eg:
>
>    https://gcc.gnu.org/ml/gcc-testresults/2014-06/msg02439.html

It seems that uneq_allocator is no longer copy constructible.


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

* Re: testsuite allocators patch
  2014-06-26 22:39         ` Jonathan Wakely
@ 2014-06-27  7:30           ` Paolo Carlini
  2014-06-27 17:33             ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2014-06-27  7:30 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: François Dumont, libstdc++, gcc-patches

Hi,

On 06/27/2014 12:38 AM, Jonathan Wakely wrote:
> On 26/06/14 23:21 +0200, Paolo Carlini wrote:
>> Hi,
>>
>> I'm afraid something went badly wrong with this commit, I'm seeing 
>> tens of fails. See eg:
>>
>>    https://gcc.gnu.org/ml/gcc-testresults/2014-06/msg02439.html
>
> It seems that uneq_allocator is no longer copy constructible.
Can you spot a quick fix, like a thinko, or do you think Francois has to 
look into it? I'm inclined to revert it for now, the noise is quite 
annoying...

Thanks,
Paolo.

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

* Re: testsuite allocators patch
  2014-06-27  7:30           ` Paolo Carlini
@ 2014-06-27 17:33             ` Jonathan Wakely
  2014-06-27 19:51               ` Paolo Carlini
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-06-27 17:33 UTC (permalink / raw)
  To: Paolo Carlini
  Cc: Jonathan Wakely, François Dumont, libstdc++, gcc-patches

I didn't see an obvious fix (I'm not sure if the templated constructor
can deduce its argument since the change) but have been out all day
and not had a chance to look into it.

On 27 June 2014 08:27, Paolo Carlini <paolo.carlini@oracle.com> wrote:
> Hi,
>
>
> On 06/27/2014 12:38 AM, Jonathan Wakely wrote:
>>
>> On 26/06/14 23:21 +0200, Paolo Carlini wrote:
>>>
>>> Hi,
>>>
>>> I'm afraid something went badly wrong with this commit, I'm seeing tens
>>> of fails. See eg:
>>>
>>>    https://gcc.gnu.org/ml/gcc-testresults/2014-06/msg02439.html
>>
>>
>> It seems that uneq_allocator is no longer copy constructible.
>
> Can you spot a quick fix, like a thinko, or do you think Francois has to
> look into it? I'm inclined to revert it for now, the noise is quite
> annoying...
>
> Thanks,
> Paolo.

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

* Re: testsuite allocators patch
  2014-06-27 17:33             ` Jonathan Wakely
@ 2014-06-27 19:51               ` Paolo Carlini
  2014-06-27 21:29                 ` François Dumont
  2014-07-23 20:46                 ` François Dumont
  0 siblings, 2 replies; 17+ messages in thread
From: Paolo Carlini @ 2014-06-27 19:51 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: Jonathan Wakely, François Dumont, libstdc++, gcc-patches

Hi,

On 06/27/2014 07:33 PM, Jonathan Wakely wrote:
> I didn't see an obvious fix (I'm not sure if the templated constructor
> can deduce its argument since the change) but have been out all day
> and not had a chance to look into it.
Ok, thanks. I'm reverting the last two libstdc++-v3 commits.

Paolo.

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

* Re: testsuite allocators patch
  2014-06-27 19:51               ` Paolo Carlini
@ 2014-06-27 21:29                 ` François Dumont
  2014-07-23 20:46                 ` François Dumont
  1 sibling, 0 replies; 17+ messages in thread
From: François Dumont @ 2014-06-27 21:29 UTC (permalink / raw)
  To: Paolo Carlini, Jonathan Wakely; +Cc: Jonathan Wakely, libstdc++, gcc-patches

On 27/06/2014 21:48, Paolo Carlini wrote:
> Hi,
>
> On 06/27/2014 07:33 PM, Jonathan Wakely wrote:
>> I didn't see an obvious fix (I'm not sure if the templated constructor
>> can deduce its argument since the change) but have been out all day
>> and not had a chance to look into it.
> Ok, thanks. I'm reverting the last two libstdc++-v3 commits.
>
> Paolo.
>
It run fine on my side but maybe because of other modifications I have. 
I will revert those and reapply the patch to see what is wrong.

Sorry

François

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

* Re: testsuite allocators patch
  2014-06-27 19:51               ` Paolo Carlini
  2014-06-27 21:29                 ` François Dumont
@ 2014-07-23 20:46                 ` François Dumont
  2014-07-24  8:58                   ` Jonathan Wakely
  2014-07-29 19:42                   ` Jonathan Wakely
  1 sibling, 2 replies; 17+ messages in thread
From: François Dumont @ 2014-07-23 20:46 UTC (permalink / raw)
  To: Paolo Carlini, Jonathan Wakely; +Cc: Jonathan Wakely, libstdc++, gcc-patches

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

On 27/06/2014 21:48, Paolo Carlini wrote:
> Hi,
>
> On 06/27/2014 07:33 PM, Jonathan Wakely wrote:
>> I didn't see an obvious fix (I'm not sure if the templated constructor
>> can deduce its argument since the change) but have been out all day
>> and not had a chance to look into it.
> Ok, thanks. I'm reverting the last two libstdc++-v3 commits.
>
> Paolo.
>

Hi

     Back from vacation, ready to have this patch committed eventually.

     Here is the new version with the missing default and copy constructor.

     I have a small question regarding some code next to the one I am 
modifying in this patch. I can see lines like:

       propagating_allocator() noexcept = default;

     When using a default implementation shouldn't we let the compiler 
decide if it should be noexcept or not depending on the member fields or 
base class default constructors ?

     Tested under Linux x86_64.

     Ok to commit ?

François


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

Index: testsuite/util/testsuite_allocator.h
===================================================================
--- testsuite/util/testsuite_allocator.h	(revision 212959)
+++ testsuite/util/testsuite_allocator.h	(working copy)
@@ -29,6 +29,7 @@
 #include <tr1/unordered_map>
 #include <bits/move.h>
 #include <ext/pointer.h>
+#include <ext/alloc_traits.h>
 #include <testsuite_hooks.h>
 
 namespace __gnu_test
@@ -38,26 +39,19 @@
   public:
     typedef std::size_t    size_type; 
 
-    static void*
+    static void
     allocate(size_type blocksize)
-    {
-      void* p = ::operator new(blocksize);
-      allocationCount_ += blocksize;
-      return p;
-    }
+    { allocationCount_ += blocksize; }
 
     static void
-    construct() { constructCount_++; }
+    construct() { ++constructCount_; }
 
     static void
-    destroy() { destructCount_++; }
+    destroy() { ++destructCount_; }
 
     static void
-    deallocate(void* p, size_type blocksize)
-    {
-      ::operator delete(p);
-      deallocationCount_ += blocksize;
-    }
+    deallocate(size_type blocksize)
+    { deallocationCount_ += blocksize; }
 
     static size_type
     get_allocation_count() { return allocationCount_; }
@@ -87,103 +81,142 @@
     static int        destructCount_;
   };
 
-  // A simple basic allocator that just forwards to the
-  // tracker_allocator_counter to fulfill memory requests.  This class
-  // is templated on the target object type, but tracker isn't.
-  template<class T>
-  class tracker_allocator
-  {
-  private:
-    typedef tracker_allocator_counter counter_type;
+  // Helper to detect inconsistency between type used to instantiate an
+  // allocator and the underlying allocator value_type.
+  template<typename T, typename Alloc,
+	   typename = typename Alloc::value_type>
+    struct check_consistent_alloc_value_type;
 
-  public:
-    typedef T              value_type;
-    typedef T*             pointer;
-    typedef const T*       const_pointer;
-    typedef T&             reference;
-    typedef const T&       const_reference;
-    typedef std::size_t    size_type; 
-    typedef std::ptrdiff_t difference_type; 
-    
-    template<class U> struct rebind { typedef tracker_allocator<U> other; };
-    
-    pointer
-    address(reference value) const _GLIBCXX_NOEXCEPT
-    { return std::__addressof(value); }
+  template<typename T, typename Alloc>
+    struct check_consistent_alloc_value_type<T, Alloc, T>
+    { typedef T value_type; };
 
-    const_pointer
-    address(const_reference value) const _GLIBCXX_NOEXCEPT
-    { return std::__addressof(value); }
+  // An allocator facade that intercepts allocate/deallocate/construct/destroy
+  // calls and track them through the tracker_allocator_counter class. This
+  // class is templated on the target object type, but tracker isn't.
+  template<typename T, typename Alloc = std::allocator<T> >
+    class tracker_allocator : public Alloc
+    {
+    private:
+      typedef tracker_allocator_counter counter_type;
 
-    tracker_allocator() _GLIBCXX_USE_NOEXCEPT
-    { }
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
 
-    tracker_allocator(const tracker_allocator&) _GLIBCXX_USE_NOEXCEPT
-    { }
+    public:
+      typedef typename
+      check_consistent_alloc_value_type<T, Alloc>::value_type value_type;
+      typedef typename AllocTraits::pointer pointer;
+      typedef typename AllocTraits::size_type size_type;
 
-    template<class U>
-      tracker_allocator(const tracker_allocator<U>&) _GLIBCXX_USE_NOEXCEPT
+      template<class U>
+	struct rebind
+	{
+	  typedef tracker_allocator<U,
+		typename AllocTraits::template rebind<U>::other> other;
+	};
+    
+#if __cplusplus >= 201103L
+      tracker_allocator() = default;
+      tracker_allocator(const tracker_allocator&) = default;
+      tracker_allocator(tracker_allocator&&) = default;
+
+      // Perfect forwarding constructor.
+      template<typename... _Args>
+	tracker_allocator(_Args&&... __args)
+	  : Alloc(std::forward<_Args>(__args)...)
+	{ }
+#else
+      tracker_allocator()
       { }
 
-    ~tracker_allocator() _GLIBCXX_USE_NOEXCEPT
-    { }
+      tracker_allocator(const tracker_allocator&)
+      { }
 
-    size_type
-    max_size() const _GLIBCXX_USE_NOEXCEPT
-    { return size_type(-1) / sizeof(T); }
+      ~tracker_allocator()
+      { }
+#endif
 
-    pointer
-    allocate(size_type n, const void* = 0)
-    { return static_cast<pointer>(counter_type::allocate(n * sizeof(T))); }
+      template<class U>
+	tracker_allocator(const tracker_allocator<U,
+	  typename AllocTraits::template rebind<U>::other>& alloc)
+	    _GLIBCXX_USE_NOEXCEPT
+	  : Alloc(alloc)
+	{ }
 
+      pointer
+      allocate(size_type n, const void* = 0)
+      {
+	pointer p = AllocTraits::allocate(*this, n);
+	counter_type::allocate(n * sizeof(T));
+	return p;
+      }
+
 #if __cplusplus >= 201103L
-    template<typename U, typename... Args>
+      template<typename U, typename... Args>
+	void
+	construct(U* p, Args&&... args) 
+	{
+	  AllocTraits::construct(*this, p, std::forward<Args>(args)...);
+	  counter_type::construct();
+	}
+
+      template<typename U>
+	void
+	destroy(U* p)
+	{
+	  AllocTraits::destroy(*this, p);
+	  counter_type::destroy();
+	}
+#else
       void
-      construct(U* p, Args&&... args) 
+      construct(pointer p, const T& value)
       {
-	::new((void *)p) U(std::forward<Args>(args)...);
+	AllocTraits::construct(*this, p, value);
 	counter_type::construct();
       }
 
-    template<typename U>
       void
-      destroy(U* p)
+      destroy(pointer p)
       {
-	p->~U();
+	AllocTraits::destroy(*this, p);
 	counter_type::destroy();
       }
-#else
-    void
-    construct(pointer p, const T& value)
-    {
-      ::new ((void *)p) T(value);
-      counter_type::construct();
-    }
-
-    void
-    destroy(pointer p)
-    {
-      p->~T();
-      counter_type::destroy();
-    }
 #endif
 
-    void
-    deallocate(pointer p, size_type num)
-    { counter_type::deallocate(p, num * sizeof(T)); }
-  };
+      void
+      deallocate(pointer p, size_type num)
+      {
+	counter_type::deallocate(num * sizeof(T));
+	AllocTraits::deallocate(*this, p, num);
+      }
 
-  template<class T1, class T2>
+      // Implement swap for underlying allocators that might need it.
+      friend inline void
+      swap(tracker_allocator& a, tracker_allocator& b)
+      {
+	using std::swap;
+
+	Alloc& aa = a;
+	Alloc& ab = b;
+	swap(aa, ab);
+      } 
+    };
+
+  template<class T1, class Alloc1, class T2, class Alloc2>
     bool
-    operator==(const tracker_allocator<T1>&, 
-	       const tracker_allocator<T2>&) throw()
-    { return true; }
+    operator==(const tracker_allocator<T1, Alloc1>& lhs, 
+	       const tracker_allocator<T2, Alloc2>& rhs) throw()
+    {
+      const Alloc1& alloc1 = lhs;
+      const Alloc2& alloc2 = rhs;
+      return lhs == rhs;
+    }
 
-  template<class T1, class T2>
+  template<class T1, class Alloc1, class T2, class Alloc2>
     bool
-    operator!=(const tracker_allocator<T1>&, 
-	       const tracker_allocator<T2>&) throw()
-    { return false; }
+    operator!=(const tracker_allocator<T1, Alloc1>& lhs, 
+	       const tracker_allocator<T2, Alloc2>& rhs) throw()
+    { return !(lhs == rhs); }
 
   bool
   check_construct_destroy(const char* tag, int expected_c, int expected_d);
@@ -193,7 +226,7 @@
     check_deallocate_null()
     {
       // Let's not core here...
-      Alloc  a;
+      Alloc a;
       a.deallocate(0, 1);
       a.deallocate(0, 10);
       return true;
@@ -219,7 +252,6 @@
       throw;
     }
 
-
   // A simple allocator which can be constructed endowed of a given
   // "personality" (an integer), queried in operator== to simulate the
   // behavior of realworld "unequal" allocators (i.e., not exploiting
@@ -227,7 +259,7 @@
   // filled at allocation time with (pointer, personality) pairs, is
   // then consulted to enforce the requirements in Table 32 about
   // deallocation vs allocator equality.  Note that this allocator is
-  // swappable, not assignable, consistently with Option 3 of DR 431
+  // swappable, not copy assignable, consistently with Option 3 of DR 431
   // (see N1599).
   struct uneq_allocator_base
   {
@@ -244,26 +276,33 @@
     }
   };
 
-  template<typename Tp>
+  template<typename Tp, typename Alloc = std::allocator<Tp> >
     class uneq_allocator
-    : private uneq_allocator_base
+    : private uneq_allocator_base,
+      public Alloc
     {
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
+
+      Alloc& base() { return *this; }
+      const Alloc& base() const  { return *this; }
+      void swap_base(Alloc& b) { swap(b, this->base()); }
+
     public:
-      typedef std::size_t                         size_type;
-      typedef std::ptrdiff_t                      difference_type;
-      typedef Tp*                                 pointer;
-      typedef const Tp*                           const_pointer;
-      typedef Tp&                                 reference;
-      typedef const Tp&                           const_reference;
-      typedef Tp                                  value_type;
+      typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
+	value_type;
+      typedef typename AllocTraits::size_type	size_type;
+      typedef typename AllocTraits::pointer	pointer;
 
 #if __cplusplus >= 201103L
-      typedef std::true_type                      propagate_on_container_swap;
+      typedef std::true_type			propagate_on_container_swap;
 #endif
 
       template<typename Tp1>
-        struct rebind
-	{ typedef uneq_allocator<Tp1> other; };
+	struct rebind
+	{
+	  typedef uneq_allocator<Tp1,
+		typename AllocTraits::template rebind<Tp1>::other> other;
+	};
 
       uneq_allocator() _GLIBCXX_USE_NOEXCEPT
       : personality(0) { }
@@ -270,9 +309,16 @@
 
       uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
       : personality(person) { }
+
+#if __cplusplus >= 201103L
+      uneq_allocator(const uneq_allocator&) = default;
+      uneq_allocator(uneq_allocator&&) = default;
+#endif
       
       template<typename Tp1>
-        uneq_allocator(const uneq_allocator<Tp1>& b) _GLIBCXX_USE_NOEXCEPT
+	uneq_allocator(const uneq_allocator<Tp1,
+		       typename AllocTraits::template rebind<Tp1>::other>& b)
+	_GLIBCXX_USE_NOEXCEPT
 	: personality(b.get_personality()) { }
 
       ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
@@ -281,20 +327,10 @@
       int get_personality() const { return personality; }
       
       pointer
-      address(reference x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(x); }
-    
-      const_pointer
-      address(const_reference x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(x); }
+      allocate(size_type n, const void* hint = 0)
+      { 
+	pointer p = AllocTraits::allocate(*this, n);
 
-      pointer
-      allocate(size_type n, const void* = 0)
-      { 
-	if (__builtin_expect(n > this->max_size(), false))
-	  std::__throw_bad_alloc();
-	
-	pointer p = static_cast<Tp*>(::operator new(n * sizeof(Tp)));
 	try
 	  {
 	    get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
@@ -302,14 +338,15 @@
 	  }
 	catch(...)
 	  {
-	    ::operator delete(p);
+	    AllocTraits::deallocate(*this, p, n);
 	    __throw_exception_again;
 	  }
+
 	return p;
       }
 
       void
-      deallocate(pointer p, size_type)
+      deallocate(pointer p, size_type n)
       {
 	bool test __attribute__((unused)) = true;
 
@@ -323,34 +360,18 @@
 	VERIFY( it->second == personality );
 
 	get_map().erase(it);
-	::operator delete(p);
+	AllocTraits::deallocate(*this, p, n);
       }
 
-      size_type
-      max_size() const _GLIBCXX_USE_NOEXCEPT 
-      { return size_type(-1) / sizeof(Tp); }
-
 #if __cplusplus >= 201103L
-      template<typename U, typename... Args>
-        void
-        construct(U* p, Args&&... args) 
-	{ ::new((void *)p) U(std::forward<Args>(args)...); }
-
-      template<typename U>
-	void 
-	destroy(U* p) { p->~U(); }
-
       // Not copy assignable...
       uneq_allocator&
       operator=(const uneq_allocator&) = delete;
+
+      // ... but still moveable if base allocator is.
+      uneq_allocator&
+      operator=(uneq_allocator&&) = default;
 #else
-      void 
-      construct(pointer p, const Tp& val) 
-      { ::new((void *)p) Tp(val); }
-
-      void 
-      destroy(pointer p) { p->~Tp(); }
-
     private:
       // Not assignable...
       uneq_allocator&
@@ -358,21 +379,27 @@
 #endif
 
     private:
-
       // ... yet swappable!
       friend inline void
       swap(uneq_allocator& a, uneq_allocator& b)
-      { std::swap(a.personality, b.personality); } 
-      
+      {
+	std::swap(a.personality, b.personality);
+	a.swap_base(b);
+      } 
+
       template<typename Tp1>
-        friend inline bool
-        operator==(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
-        { return a.personality == b.personality; }
+	friend inline bool
+	operator==(const uneq_allocator& a,
+		   const uneq_allocator<Tp1,
+		   typename AllocTraits::template rebind<Tp1>::other>& b)
+	{ return a.personality == b.personality; }
 
       template<typename Tp1>
-        friend inline bool
-        operator!=(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
-        { return !(a == b); }
+	friend inline bool
+	operator!=(const uneq_allocator& a,
+		   const uneq_allocator<Tp1,
+		   typename AllocTraits::template rebind<Tp1>::other>& b)
+	{ return !(a == b); }
       
       int personality;
     };
@@ -379,10 +406,12 @@
 
 #if __cplusplus >= 201103L
   // An uneq_allocator which can be used to test allocator propagation.
-  template<typename Tp, bool Propagate>
-    class propagating_allocator : public uneq_allocator<Tp>
+  template<typename Tp, bool Propagate, typename Alloc = std::allocator<Tp>>
+    class propagating_allocator : public uneq_allocator<Tp, Alloc>
     {
-      typedef uneq_allocator<Tp> base_alloc;
+      typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
+
+      typedef uneq_allocator<Tp, Alloc> base_alloc;
       base_alloc& base() { return *this; }
       const base_alloc& base() const  { return *this; }
       void swap_base(base_alloc& b) { swap(b, this->base()); }
@@ -393,7 +422,11 @@
       // default allocator_traits::rebind_alloc would select
       // uneq_allocator::rebind so we must define rebind here
       template<typename Up>
-	struct rebind { typedef propagating_allocator<Up, Propagate> other; };
+	struct rebind
+	{
+	  typedef propagating_allocator<Up, Propagate,
+		typename AllocTraits::template rebind<Up>::other> other;
+	};
 
       propagating_allocator(int i) noexcept
       : base_alloc(i)
@@ -400,8 +433,9 @@
       { }
 
       template<typename Up>
-	propagating_allocator(const propagating_allocator<Up, Propagate>& a)
-       	noexcept
+	propagating_allocator(const propagating_allocator<Up, Propagate,
+			      typename AllocTraits::template rebind<Up>::other>& a)
+	noexcept
 	: base_alloc(a)
 	{ }
 
@@ -418,8 +452,8 @@
       }
 
       template<bool P2>
-  	propagating_allocator&
-  	operator=(const propagating_allocator<Tp, P2>& a) noexcept
+	propagating_allocator&
+	operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
   	{
 	  static_assert(P2, "assigning propagating_allocator<T, true>");
 	  propagating_allocator(a).swap_base(*this);
Index: testsuite/23_containers/forward_list/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/forward_list/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/forward_list/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::forward_list<int, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/map/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/map/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/map/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::map<int, int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/multimap/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/multimap/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/multimap/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::multimap<int, int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/multiset/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/multiset/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/multiset/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::multiset<int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/set/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/set/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/set/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::set<int, std::less<int>, alloc_type> test_type;
 
   test_type v1(alloc_type(1));
Index: testsuite/23_containers/unordered_map/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_map/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/unordered_map/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int> > alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::unordered_map<int, int,
 				     std::hash<int>, std::equal_to<int>,
 				     alloc_type> test_type;
Index: testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/unordered_multimap/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,8 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<std::pair<const int, int>> alloc_type;
+  typedef __gnu_test::propagating_allocator<std::pair<const int, int>,
+					    false> alloc_type;
   typedef __gnu_debug::unordered_multimap<int, int, std::hash<int>,
 					  std::equal_to<int>,
 					  alloc_type> test_type;
Index: testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/unordered_multiset/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::unordered_multiset<int, std::hash<int>,
 					  std::equal_to<int>,
 					  alloc_type> test_type;
Index: testsuite/23_containers/unordered_set/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/unordered_set/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/unordered_set/debug/move_assign_neg.cc	(working copy)
@@ -25,7 +25,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::unordered_set<int, std::hash<int>,
 				     std::equal_to<int>,
 				     alloc_type> test_type;
Index: testsuite/23_containers/vector/debug/move_assign_neg.cc
===================================================================
--- testsuite/23_containers/vector/debug/move_assign_neg.cc	(revision 212959)
+++ testsuite/23_containers/vector/debug/move_assign_neg.cc	(working copy)
@@ -27,7 +27,7 @@
 {
   bool test __attribute__((unused)) = true;
 
-  typedef __gnu_test::uneq_allocator<int> alloc_type;
+  typedef __gnu_test::propagating_allocator<int, false> alloc_type;
   typedef __gnu_debug::vector<int, alloc_type> test_type;
 
   test_type v1(alloc_type(1));

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

* Re: testsuite allocators patch
  2014-07-23 20:46                 ` François Dumont
@ 2014-07-24  8:58                   ` Jonathan Wakely
  2014-07-24 20:30                     ` François Dumont
  2014-07-29 19:42                   ` Jonathan Wakely
  1 sibling, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-07-24  8:58 UTC (permalink / raw)
  To: François Dumont
  Cc: Paolo Carlini, Jonathan Wakely, libstdc++, gcc-patches

On 23/07/14 22:33 +0200, François Dumont wrote:
>    I have a small question regarding some code next to the one I am 
>modifying in this patch. I can see lines like:
>
>      propagating_allocator() noexcept = default;
>
>    When using a default implementation shouldn't we let the compiler 
>decide if it should be noexcept or not depending on the member fields 
>or base class default constructors ?

Stating it explicitly means you get an error if the default
implementation is not noexcept. That can be useful, to ensure you
don't silently start getting a throwing constructor by mistake because
of a change to a base class.

I'm not sure if I added the noexcept above, but if I did that might
have been what I was intending it to do. I don't remember.

I'll review the rest of the patch ASAP. Did you test it with no other
changes in your tree, and run the entire testsuite?

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

* Re: testsuite allocators patch
  2014-07-24  8:58                   ` Jonathan Wakely
@ 2014-07-24 20:30                     ` François Dumont
  2014-07-24 23:36                       ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: François Dumont @ 2014-07-24 20:30 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Paolo Carlini, Jonathan Wakely, libstdc++, gcc-patches

On 24/07/2014 10:55, Jonathan Wakely wrote:
> On 23/07/14 22:33 +0200, François Dumont wrote:
>>    I have a small question regarding some code next to the one I am 
>> modifying in this patch. I can see lines like:
>>
>>      propagating_allocator() noexcept = default;
>>
>>    When using a default implementation shouldn't we let the compiler 
>> decide if it should be noexcept or not depending on the member fields 
>> or base class default constructors ?
>
> Stating it explicitly means you get an error if the default
> implementation is not noexcept. That can be useful, to ensure you
> don't silently start getting a throwing constructor by mistake because
> of a change to a base class.
>
> I'm not sure if I added the noexcept above, but if I did that might
> have been what I was intending it to do. I don't remember.
>
> I'll review the rest of the patch ASAP. Did you test it with no other
> changes in your tree, and run the entire testsuite?
>
Ok, thanks for the explanation, it is clear now.

Yes I have tested with no other changes in my tree and got only those 
pretty printers errors which are unrelated I think:

Python Exception <class 'TypeError'> iter() returned non-iterator of 
type '_contained':
$2 = std::experimental::optional<int> [no contained value]
skipping: Python Exception <class 'TypeError'> iter() returned 
non-iterator of type '_contained':
got: $2 = std::experimental::optional<int> [no contained value]
PASS: libstdc++-prettyprinters/libfundts.cc print o
Python Exception <class 'TypeError'> iter() returned non-iterator of 
type '_contained':
$3 = std::experimental::optional<bool>
skipping: Python Exception <class 'TypeError'> iter() returned 
non-iterator of type '_contained':
got: $3 = std::experimental::optional<bool>
FAIL: libstdc++-prettyprinters/libfundts.cc print ob
Python Exception <class 'TypeError'> iter() returned non-iterator of 
type '_contained':
$4 = std::experimental::optional<int>
skipping: Python Exception <class 'TypeError'> iter() returned 
non-iterator of type '_contained':
got: $4 = std::experimental::optional<int>
FAIL: libstdc++-prettyprinters/libfundts.cc print oi

François

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

* Re: testsuite allocators patch
  2014-07-24 20:30                     ` François Dumont
@ 2014-07-24 23:36                       ` Jonathan Wakely
  2014-07-29 21:34                         ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-07-24 23:36 UTC (permalink / raw)
  To: François Dumont
  Cc: Jonathan Wakely, Paolo Carlini, libstdc++, gcc-patches

On 24 July 2014 21:11, François Dumont wrote:
>
> Yes I have tested with no other changes in my tree and got only those pretty
> printers errors which are unrelated I think:
>
> Python Exception <class 'TypeError'> iter() returned non-iterator of type
> '_contained':
> $2 = std::experimental::optional<int> [no contained value]

I haven't seen these, I'll fix them on Monday, thanks.

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

* Re: testsuite allocators patch
  2014-07-23 20:46                 ` François Dumont
  2014-07-24  8:58                   ` Jonathan Wakely
@ 2014-07-29 19:42                   ` Jonathan Wakely
  1 sibling, 0 replies; 17+ messages in thread
From: Jonathan Wakely @ 2014-07-29 19:42 UTC (permalink / raw)
  To: François Dumont
  Cc: Paolo Carlini, Jonathan Wakely, libstdc++, gcc-patches

On 23/07/14 22:33 +0200, François Dumont wrote:
>On 27/06/2014 21:48, Paolo Carlini wrote:
>>Hi,
>>
>>On 06/27/2014 07:33 PM, Jonathan Wakely wrote:
>>>I didn't see an obvious fix (I'm not sure if the templated constructor
>>>can deduce its argument since the change) but have been out all day
>>>and not had a chance to look into it.
>>Ok, thanks. I'm reverting the last two libstdc++-v3 commits.
>>
>>Paolo.
>>
>
>Hi
>
>    Back from vacation, ready to have this patch committed eventually.
>
>    Here is the new version with the missing default and copy constructor.
>
>    I have a small question regarding some code next to the one I am 
>modifying in this patch. I can see lines like:
>
>      propagating_allocator() noexcept = default;
>
>    When using a default implementation shouldn't we let the compiler 
>decide if it should be noexcept or not depending on the member fields 
>or base class default constructors ?
>
>    Tested under Linux x86_64.
>
>    Ok to commit ?

OK, thanks.

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

* Re: testsuite allocators patch
  2014-07-24 23:36                       ` Jonathan Wakely
@ 2014-07-29 21:34                         ` Jonathan Wakely
  2014-07-29 21:44                           ` Jonathan Wakely
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Wakely @ 2014-07-29 21:34 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: François Dumont, Paolo Carlini

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

On 25/07/14 00:19 +0100, Jonathan Wakely wrote:
>On 24 July 2014 21:11, François Dumont wrote:
>>
>> Yes I have tested with no other changes in my tree and got only those pretty
>> printers errors which are unrelated I think:
>>
>> Python Exception <class 'TypeError'> iter() returned non-iterator of type
>> '_contained':
>> $2 = std::experimental::optional<int> [no contained value]
>
>I haven't seen these, I'll fix them on Monday, thanks.

Fixed by the attached patch.

Tested x86_64-linux (thanks to Samual Bronson for testing with
Python3) and committed to trunk.


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

commit 7de83299c42041611360a1426f5164270ac6c6b6
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jul 29 20:08:31 2014 +0100

    	* python/libstdcxx/v6/printers.py
    	(SingleObjContainerPrinter._contained): Use compatibility mixin.

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 15d7a88..2e5cd6c 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -851,14 +851,14 @@ class SingleObjContainerPrinter(object):
         return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
                                                 type) or str(type)
 
-    class _contained:
+    class _contained(Iterator):
         def __init__ (self, val):
             self.val = val
 
         def __iter__ (self):
             return self
 
-        def next (self):
+        def __next__(self):
             if self.val is None:
                 raise StopIteration
             retval = self.val

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

* Re: testsuite allocators patch
  2014-07-29 21:34                         ` Jonathan Wakely
@ 2014-07-29 21:44                           ` Jonathan Wakely
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Wakely @ 2014-07-29 21:44 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: François Dumont, Paolo Carlini

On 29/07/14 22:33 +0100, Jonathan Wakely wrote:
>Tested x86_64-linux (thanks to Samual Bronson for testing with
>Python3) and committed to trunk.

Oops, Samuel not Samual ... no idea why my fingers typed that wrong!

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

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

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-20 20:37 testsuite allocators patch François Dumont
2014-06-25 19:48 ` François Dumont
2014-06-26 10:33   ` Jonathan Wakely
2014-06-26 20:45     ` François Dumont
2014-06-26 21:24       ` Paolo Carlini
2014-06-26 22:39         ` Jonathan Wakely
2014-06-27  7:30           ` Paolo Carlini
2014-06-27 17:33             ` Jonathan Wakely
2014-06-27 19:51               ` Paolo Carlini
2014-06-27 21:29                 ` François Dumont
2014-07-23 20:46                 ` François Dumont
2014-07-24  8:58                   ` Jonathan Wakely
2014-07-24 20:30                     ` François Dumont
2014-07-24 23:36                       ` Jonathan Wakely
2014-07-29 21:34                         ` Jonathan Wakely
2014-07-29 21:44                           ` Jonathan Wakely
2014-07-29 19:42                   ` Jonathan Wakely

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