From 0e31827300f1ce12857070c5f27a10ebcca4933e Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 4 Mar 2019 12:21:06 +0000 Subject: [PATCH] Implement polymorphic_allocator for C++20 (P0339R6) * include/std/memory_resource (polymorphic_allocator): Add default template argument for C++20. (polymorphic_allocator::allocate_bytes) (polymorphic_allocator::deallocate_bytes) (polymorphic_allocator::allocate_object) (polymorphic_allocator::deallocate_object) (polymorphic_allocator::new_object) (polymorphic_allocator::delete_object): New member functions for C++20. * testsuite/20_util/polymorphic_allocator/allocate_object.cc: New test. From-SVN: r269362 --- libstdc++-v3/ChangeLog | 14 ++++ libstdc++-v3/include/std/memory_resource | 63 ++++++++++++++- .../polymorphic_allocator/allocate_object.cc | 80 +++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/polymorphic_allocator/allocate_object.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 70cfef0cb97..334cd1f8432 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2019-03-04 Jonathan Wakely + + * include/std/memory_resource (polymorphic_allocator): Add default + template argument for C++20. + (polymorphic_allocator::allocate_bytes) + (polymorphic_allocator::deallocate_bytes) + (polymorphic_allocator::allocate_object) + (polymorphic_allocator::deallocate_object) + (polymorphic_allocator::new_object) + (polymorphic_allocator::delete_object): New member functions for + C++20. + * testsuite/20_util/polymorphic_allocator/allocate_object.cc: New + test. + 2019-03-03 Jonathan Wakely PR libstdc++/89562 diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index a212bccc9b1..7f1f0ca5e91 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -33,11 +33,13 @@ #if __cplusplus >= 201703L +#include // numeric_limits #include // align, allocator_arg_t, __uses_alloc #include // pair, index_sequence #include // vector -#include // size_t, max_align_t +#include // size_t, max_align_t, byte #include // shared_mutex +#include #include namespace std _GLIBCXX_VISIBILITY(default) @@ -55,8 +57,13 @@ namespace pmr class memory_resource; +#if __cplusplus == 201703L template class polymorphic_allocator; +#else // C++20 + template + class polymorphic_allocator; +#endif // Global memory resources memory_resource* new_delete_resource() noexcept; @@ -170,7 +177,59 @@ namespace pmr __attribute__((__nonnull__)) { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } -#if __cplusplus <= 201703L +#if __cplusplus > 201703L + void* + allocate_bytes(size_t __nbytes, + size_t __alignment = alignof(max_align_t)) + { return _M_resource->allocate(__nbytes, __alignment); } + + void + deallocate_bytes(void* __p, size_t __nbytes, + size_t __alignment = alignof(max_align_t)) + { _M_resource->deallocate(__p, __nbytes, __alignment); } + + template + _Up* + allocate_object(size_t __n = 1) + { + if ((std::numeric_limits::max() / sizeof(_Up)) < __n) + __throw_length_error("polymorphic_allocator::allocate_object"); + return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), + alignof(_Up))); + } + + template + void + deallocate_object(_Up* __p, size_t __n = 1) + { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } + + template + _Up* + new_object(_CtorArgs&&... __ctor_args) + { + _Up* __p = allocate_object<_Up>(); + __try + { + construct(__p, std::forward<_CtorArgs>(__ctor_args)...); + } + __catch (...) + { + deallocate_object(__p); + __throw_exception_again; + } + return __p; + } + + template + void + delete_object(_Up* __p) + { + destroy(__p); + deallocate_object(__p); + } +#endif // C++2a + +#if __cplusplus == 201703L template __attribute__((__nonnull__)) typename __not_pair<_Tp1>::type diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/allocate_object.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/allocate_object.cc new file mode 100644 index 00000000000..cbaccf6f5b0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/allocate_object.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2019 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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include +#include + +void +test01() +{ + __gnu_test::memory_resource res; + std::pmr::polymorphic_allocator<> alloc(&res); + static_assert( std::is_same_v ); + + void* p = alloc.allocate_bytes(100); + VERIFY( res.number_of_active_allocations() == 1 ); + alloc.deallocate_bytes(p, 100); + VERIFY( res.number_of_active_allocations() == 0 ); + p = alloc.allocate_bytes(100, 64); + VERIFY( res.number_of_active_allocations() == 1 ); + alloc.deallocate_bytes(p, 100, 64); + VERIFY( res.number_of_active_allocations() == 0 ); + + int* p1 = alloc.allocate_object(); + int* p2 = alloc.allocate_object(2); + struct X { double d[10]; }; + X* px = alloc.allocate_object(20); + VERIFY( res.number_of_active_allocations() == 3 ); + + alloc.deallocate_object(p1); + alloc.deallocate_object(p2, 2); + alloc.deallocate_object(px, 20); + VERIFY( res.number_of_active_allocations() == 0 ); + + struct Y { + Y(int i, const char* s, bool* alive) + : i(i), s(s), alive(alive) + { *alive = true; } + + ~Y() { *alive = false; } + + int i; + const char* s; + bool* alive; + }; + + bool alive = false; + Y* py = alloc.new_object(1, "two", &alive); + VERIFY( alive ); + VERIFY( py->i == 1 ); + VERIFY( std::strcmp(py->s, "two") == 0 ); + VERIFY( res.number_of_active_allocations() == 1 ); + + alloc.delete_object(py); + VERIFY( alive == false ); +} + +int +main() +{ + test01(); +} -- 2.30.2