* 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.
Another piece of C++20, tested powerpc64le-linux, committed to trunk.
commit 3b59880300e00772f3d18c26544e0422332efd92 Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Mar 4 11:42:44 2019 +0000 Implement polymorphic_allocator<byte> 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. 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 <limits> // numeric_limits #include <memory> // align, allocator_arg_t, __uses_alloc #include <utility> // pair, index_sequence #include <vector> // vector -#include <cstddef> // size_t, max_align_t +#include <cstddef> // size_t, max_align_t, byte #include <shared_mutex> // shared_mutex +#include <bits/functexcept.h> #include <debug/assertions.h> namespace std _GLIBCXX_VISIBILITY(default) @@ -55,8 +57,13 @@ namespace pmr class memory_resource; +#if __cplusplus == 201703L template<typename _Tp> class polymorphic_allocator; +#else // C++20 + template<typename _Tp = std::byte> + 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<typename _Up> + _Up* + allocate_object(size_t __n = 1) + { + if ((std::numeric_limits<size_t>::max() / sizeof(_Up)) < __n) + __throw_length_error("polymorphic_allocator::allocate_object"); + return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), + alignof(_Up))); + } + + template<typename _Up> + void + deallocate_object(_Up* __p, size_t __n = 1) + { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } + + template<typename _Up, typename... _CtorArgs> + _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<typename _Up> + void + delete_object(_Up* __p) + { + destroy(__p); + deallocate_object(__p); + } +#endif // C++2a + +#if __cplusplus == 201703L template<typename _Tp1, typename... _Args> __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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <memory_resource> +#include <cstring> +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +void +test01() +{ + __gnu_test::memory_resource res; + std::pmr::polymorphic_allocator<> alloc(&res); + static_assert( std::is_same_v<decltype(alloc)::value_type, std::byte> ); + + 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>(); + int* p2 = alloc.allocate_object<int>(2); + struct X { double d[10]; }; + X* px = alloc.allocate_object<X>(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<Y>(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(); +}