+2019-03-04 Jonathan Wakely <jwakely@redhat.com>
+
+ * 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 <jwakely@redhat.com>
PR libstdc++/89562
#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)
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;
__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
--- /dev/null
+// 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();
+}