Index: include/experimental/memory_resource =================================================================== --- include/experimental/memory_resource +++ include/experimental/memory_resource @@ -152,7 +152,12 @@ // 8.6, memory.polymorphic.allocator.class // 8.6.1, memory.polymorphic.allocator.overview + +#if _LIBCPP_STD_VER > 17 +template // std::byte is not available until C++17 +#else template +#endif // _LIBCPP_STD_VER > 17 class _LIBCPP_TEMPLATE_VIS polymorphic_allocator { public: @@ -267,6 +272,58 @@ void destroy(_Tp * __p) _NOEXCEPT { __p->~_Tp(); } +#if _LIBCPP_STD_VER > 17 + _LIBCPP_INLINE_VISIBILITY + void* allocate_bytes(size_t __n, + size_t __alignment = alignof(max_align_t)) { + return __res_->allocate(__n, __alignment); + } + + _LIBCPP_INLINE_VISIBILITY + void deallocate_bytes(void* __p, size_t __n, + size_t __alignment = alignof(max_align_t)) { + __res_->deallocate(__p, __n, __alignment); + } + + template + _LIBCPP_INLINE_VISIBILITY + _Tp* allocate_object(size_t __n = 1) { + const size_t __sz = sizeof(_Tp); + + if (SIZE_MAX / __sz < __n) + _VSTD::__throw_length_error("Specified amount of storage exceeds SIZE_MAX"); + else + return static_cast<_Tp*>(allocate_bytes(__n * __sz, alignof(_Tp))); + } + + template + _LIBCPP_INLINE_VISIBILITY + void deallocate_object(_Tp* __p, size_t __n = 1) { + deallocate_bytes(__p, __n * sizeof(_Tp), alignof(_Tp)); + } + + template + _LIBCPP_INLINE_VISIBILITY + _Tp* new_object(_Args&&... __args) { + _Tp* __p = allocate_object<_Tp>(); + try { + construct(__p, _VSTD::forward<_Args>(__args)...); + } catch (...) { + deallocate_object(__p); + throw; + } + + return __p; + } + + template + _LIBCPP_INLINE_VISIBILITY + void delete_object(_Tp* __p) { + destroy(__p); + deallocate_object(__p); + } +#endif // _LIBCPP_STD_VER > 17 + _LIBCPP_INLINE_VISIBILITY polymorphic_allocator select_on_container_copy_construction() const _NOEXCEPT Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/object_allocation.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/object_allocation.pass.cpp @@ -0,0 +1,125 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); +// void deallocate_bytes(void* p, size_t nbytes, +// size_t alignment = alignof(max_align_t)); +// template +// T* allocate_object(size_t n = 1); +// template +// void deallocate_object(T* p, size_t n = 1); +// template +// T* new_object(CtorArgs&&... ctor_args); +// template +// void delete_object(T* p); + +#include +#include + +#include "test_macros.h" +#include "test_memory_resource.hpp" + +template +void test_alloc_bytes(std::size_t size) +{ + using allocator_type = typename std::conditional::value, + std::experimental::pmr::polymorphic_allocator<>, + std::experimental::pmr::polymorphic_allocator>::type; + + TestResource R; + allocator_type alloc(&R); + + void* ptr = alloc.allocate_bytes(size, alignof(T)); + assert(R.checkAlloc(ptr, size, alignof(T))); + + alloc.deallocate_bytes(ptr, size, alignof(T)); + assert(R.checkDealloc(ptr, size, alignof(T))); +} + +template +void test_alloc_obj(std::size_t size) +{ + using allocator_type = typename std::conditional::value, + std::experimental::pmr::polymorphic_allocator<>, + std::experimental::pmr::polymorphic_allocator>::type; + + TestResource R; + allocator_type alloc(&R); + + auto* ptr = alloc. template allocate_object(size); + ASSERT_SAME_TYPE(decltype(ptr), T*); + assert(R.checkAlloc(ptr, size * sizeof(T), alignof(T))); + + alloc.deallocate_object(ptr, size); + assert(R.checkDealloc(ptr, size * sizeof(T), alignof(T))); + + try { + alloc. template allocate_object(SIZE_MAX * sizeof(T) + 1); + assert(false); + } catch (...) { } +} + +template +void test_new_obj(Args&&... args) +{ + using allocator_type = typename std::conditional::value, + std::experimental::pmr::polymorphic_allocator<>, + std::experimental::pmr::polymorphic_allocator>::type; + + TestResource R; + allocator_type alloc(&R); + + auto* ptr = alloc. template new_object(std::forward(args)...); + ASSERT_SAME_TYPE(decltype(ptr), T*); + assert(R.checkAlloc(ptr, sizeof(T), alignof(T))); + + alloc.delete_object(ptr); + assert(R.checkDealloc(ptr, sizeof(T), alignof(T))); +} + +template +void test() +{ + test_alloc_bytes(1); + test_alloc_bytes(8); + test_alloc_obj(1); + test_alloc_obj(8); + test_new_obj(); +} + +struct Foo +{ + int a, b; + + Foo() : a(0), b(0) { } + Foo(int a, int b) : a(a), b(b) { } + + static void test() + { + TestResource R; + std::experimental::pmr::polymorphic_allocator alloc(&R); + auto* ptr = alloc. template new_object(42, 101); + assert(ptr->a == 42 && ptr->b == 101); + alloc.delete_object(ptr); + } +}; + +int main(int, char**) +{ + test(); + test(); + test(); + test(); + + Foo::test(); + + return 0; +} Index: www/cxx2a_status.html =================================================================== --- www/cxx2a_status.html +++ www/cxx2a_status.html @@ -138,7 +138,7 @@ P1353R0CWGMissing feature test macrosSan Diego - P0339R6LWGpolymorphic_allocator<> as a vocabulary typeKona + P0339R6LWGpolymorphic_allocator<> as a vocabulary typeKonaComplete P0340R3LWGMaking std::underlying_type SFINAE-friendlyKona P0738R2LWGI Stream, You Stream, We All Stream for istream_iteratorKona P0811R3LWGWell-behaved interpolation for numbers and pointersKonaComplete9.0