diff mbox series

[committed] libstdc++: Specialize allocator_traits<pmr::polymorphic_allocator<T>>

Message ID YQliAaGCB104lvdp@redhat.com
State New
Headers show
Series [committed] libstdc++: Specialize allocator_traits<pmr::polymorphic_allocator<T>> | expand

Commit Message

Jonathan Wakely Aug. 3, 2021, 3:34 p.m. UTC
This adds a partial specialization of allocator_traits, similar to what
was already done for std::allocator. This means that most uses of
polymorphic_allocator via the traits can avoid the metaprogramming
overhead needed to deduce the properties from polymorphic_allocator.

In addition, I'm changing polymorphic_allocator::delete_object to invoke
the destructor (or pseudo-destructor) directly, rather than calling
allocator_traits::destroy, which calls polymorphic_allocator::destroy
(which is deprecated). This is observable if a user has specialized
allocator_traits<polymorphic_allocator<Foo>> and expects to see its
destroy member function called. I consider explicit specializations of
allocator_traits to be wrong-headed, and this use case seems unnecessary
to support. So delete_object just invokes the destructor directly.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/std/memory_resource (polymorphic_allocator::delete_object):
	Call destructor directly instead of using destroy.
	(allocator_traits<polymorphic_allocator<T>>): Define partial
	specialization.

Tested powerpc64le-linux. Committed to trunk.
commit 13a1ac9f6f700f4e214fcc83b122a4a405c6b13d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Aug 3 14:00:47 2021

    libstdc++: Specialize allocator_traits<pmr::polymorphic_allocator<T>>
    
    This adds a partial specialization of allocator_traits, similar to what
    was already done for std::allocator. This means that most uses of
    polymorphic_allocator via the traits can avoid the metaprogramming
    overhead needed to deduce the properties from polymorphic_allocator.
    
    In addition, I'm changing polymorphic_allocator::delete_object to invoke
    the destructor (or pseudo-destructor) directly, rather than calling
    allocator_traits::destroy, which calls polymorphic_allocator::destroy
    (which is deprecated). This is observable if a user has specialized
    allocator_traits<polymorphic_allocator<Foo>> and expects to see its
    destroy member function called. I consider explicit specializations of
    allocator_traits to be wrong-headed, and this use case seems unnecessary
    to support. So delete_object just invokes the destructor directly.
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/std/memory_resource (polymorphic_allocator::delete_object):
            Call destructor directly instead of using destroy.
            (allocator_traits<polymorphic_allocator<T>>): Define partial
            specialization.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index cdc5e5d98b1..6bca0afa018 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -232,7 +232,7 @@  namespace pmr
 	void
 	delete_object(_Up* __p)
 	{
-	  destroy(__p);
+	  __p->~_Up();
 	  deallocate_object(__p);
 	}
 #endif // C++2a
@@ -381,6 +381,136 @@  namespace pmr
     { return !(__a == __b); }
 #endif
 
+} // namespace pmr
+
+  /// Partial specialization for std::pmr::polymorphic_allocator
+  template<typename _Tp>
+    struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
+    {
+      /// The allocator type
+      using allocator_type = pmr::polymorphic_allocator<_Tp>;
+
+      /// The allocated type
+      using value_type = _Tp;
+
+      /// The allocator's pointer type.
+      using pointer = _Tp*;
+
+      /// The allocator's const pointer type.
+      using const_pointer = const _Tp*;
+
+      /// The allocator's void pointer type.
+      using void_pointer = void*;
+
+      /// The allocator's const void pointer type.
+      using const_void_pointer = const void*;
+
+      /// The allocator's difference type
+      using difference_type = std::ptrdiff_t;
+
+      /// The allocator's size type
+      using size_type = std::size_t;
+
+      /** @{
+       * A `polymorphic_allocator` does not propagate when a
+       * container is copied, moved, or swapped.
+       */
+      using propagate_on_container_copy_assignment = false_type;
+      using propagate_on_container_move_assignment = false_type;
+      using propagate_on_container_swap = false_type;
+
+      static allocator_type
+      select_on_container_copy_construction(const allocator_type&) noexcept
+      { return allocator_type(); }
+      /// @}
+
+      /// Whether all instances of the allocator type compare equal.
+      using is_always_equal = false_type;
+
+      template<typename _Up>
+	using rebind_alloc = pmr::polymorphic_allocator<_Up>;
+
+      template<typename _Up>
+	using rebind_traits = allocator_traits<pmr::polymorphic_allocator<_Up>>;
+
+      /**
+       *  @brief  Allocate memory.
+       *  @param  __a  An allocator.
+       *  @param  __n  The number of objects to allocate space for.
+       *
+       *  Calls `a.allocate(n)`.
+      */
+      [[nodiscard]] static pointer
+      allocate(allocator_type& __a, size_type __n)
+      { return __a.allocate(__n); }
+
+      /**
+       *  @brief  Allocate memory.
+       *  @param  __a  An allocator.
+       *  @param  __n  The number of objects to allocate space for.
+       *  @return Memory of suitable size and alignment for `n` objects
+       *          of type `value_type`.
+       *
+       *  The third parameter is ignored..
+       *
+       *  Returns `a.allocate(n)`.
+      */
+      [[nodiscard]] static pointer
+      allocate(allocator_type& __a, size_type __n, const_void_pointer)
+      { return __a.allocate(__n); }
+
+      /**
+       *  @brief  Deallocate memory.
+       *  @param  __a  An allocator.
+       *  @param  __p  Pointer to the memory to deallocate.
+       *  @param  __n  The number of objects space was allocated for.
+       *
+       *  Calls `a.deallocate(p, n)`.
+      */
+      static void
+      deallocate(allocator_type& __a, pointer __p, size_type __n)
+      { __a.deallocate(__p, __n); }
+
+      /**
+       *  @brief  Construct an object of type `_Up`
+       *  @param  __a  An allocator.
+       *  @param  __p  Pointer to memory of suitable size and alignment for
+       *	       an object of type `_Up`.
+       *  @param  __args Constructor arguments.
+       *
+       *  Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
+       *  in C++11, C++14 and C++17. Changed in C++20 to call
+       *  `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
+      */
+      template<typename _Up, typename... _Args>
+	static void
+	construct(allocator_type& __a, _Up* __p, _Args&&... __args)
+	{ __a.construct(__p, std::forward<_Args>(__args)...); }
+
+      /**
+       *  @brief  Destroy an object of type `_Up`
+       *  @param  __a  An allocator.
+       *  @param  __p  Pointer to the object to destroy
+       *
+       *  Calls `p->_Up()`.
+      */
+      template<typename _Up>
+	static _GLIBCXX20_CONSTEXPR void
+	destroy(allocator_type&, _Up* __p)
+	noexcept(is_nothrow_destructible<_Up>::value)
+	{ __p->~_Up(); }
+
+      /**
+       *  @brief  The maximum supported allocation size
+       *  @return `numeric_limits<size_t>::max() / sizeof(value_type)`
+      */
+      static _GLIBCXX20_CONSTEXPR size_type
+      max_size(const allocator_type&) noexcept
+      { return size_t(-1) / sizeof(value_type); }
+    };
+
+namespace pmr
+{
   /// Parameters for tuning a pool resource's behaviour.
   struct pool_options
   {