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,60 @@ 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) { + size_t __sz = sizeof(_Tp); + + if (SIZE_MAX / __sz < __n) + _VSTD::__throw_length_error("polymorphic_allocator"); + 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(static_cast(__p), __n); + } + + 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/libcxx/memory/poly_alloc.cpp =================================================================== --- /dev/null +++ test/libcxx/memory/poly_alloc.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); + +#include +#include +#include "test_macros.h" + +#define SIZE 8 + +using alloc_t = std::pmr::polymorphic_allocator<>; + +template +void fill_obj(T* p, T v, std::size_t size = SIZE) +{ + for (unsigned i = 0; i < size; ++i) + p[i] = v; +} + +template +void cmp_obj(T* a, T* b, std::size_t size = SIZE) +{ + for (unsigned i = 0; i < size; ++i) + assert(a[i] == b[i]); +} + +template +void test_polymorphic_alloc (T fill_val) +{ + alloc_t alloc = { }; + + T* a = static_cast(alloc.allocate_bytes(sizeof(T) * SIZE)); + T* b = alloc.allocate_object(SIZE); + + fill_obj(a, fill_val); + fill_obj(b, fill_val); + + cmp_obj(a, b); + + ASSERT_SAME_TYPE(decltype(a), decltype(b)); +} + +struct Foo +{ }; + +struct Bar +{ int a; double b; bool c; }; + +bool destructor_called = false; +class Baz +{ + Baz(int a, double b, bool c) { + assert(a == 1); + assert(b == 2.0); + assert(c == false); + } + + ~Baz() { + destructor_called = true; + } +} + +int main(int, char**) +{ + test_polymorphic_alloc(1); + test_polymorphic_alloc(Foo { }); + test_polymorphic_alloc(Bar { .a=3, .b=2.0 .c=true }); + + alloc_t alloc = { }; + Baz* baz = alloc.new_object(1, 2.0, false); + alloc.delete_object(baz); + assert(destructor_called == true); + + return 0; +}