diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2021-08-03 14:00:47 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2021-08-03 15:30:36 +0100 |
commit | 13a1ac9f6f700f4e214fcc83b122a4a405c6b13d (patch) | |
tree | a09d223b37dea4182bfd8a16f7ec75a639c4553c /libstdc++-v3/include/std/memory_resource | |
parent | 9bd87e388724baab9597ef232ea7e855c99eb7d7 (diff) | |
download | gcc-13a1ac9f6f700f4e214fcc83b122a4a405c6b13d.tar.gz |
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.
Diffstat (limited to 'libstdc++-v3/include/std/memory_resource')
-rw-r--r-- | libstdc++-v3/include/std/memory_resource | 132 |
1 files changed, 131 insertions, 1 deletions
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 { |