Skip to content

Commit

Permalink
[libc++] Implement P0339R6 (polymorphic_allocator<> as a vocabulary t…
Browse files Browse the repository at this point in the history
…ype)

Reviewed By: ldionne, #libc

Spies: LRFLEW, libcxx-commits, arichardson, krytarowski, jdoerfert

Differential Revision: https://reviews.llvm.org/D137739
  • Loading branch information
philnik777 committed Dec 7, 2022
1 parent 0f6dbb5 commit 181cce6
Show file tree
Hide file tree
Showing 25 changed files with 397 additions and 53 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Expand Up @@ -260,7 +260,7 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_math_constants`` ``201907L``
------------------------------------------------- -----------------
``__cpp_lib_polymorphic_allocator`` *unimplemented*
``__cpp_lib_polymorphic_allocator`` ``201902L``
------------------------------------------------- -----------------
``__cpp_lib_ranges`` ``201811L``
------------------------------------------------- -----------------
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes.rst
Expand Up @@ -48,6 +48,7 @@ Implemented Papers
- P0482R6 - char8_t: A type for UTF-8 characters and strings
- P2438R2 - ``std::string::substr() &&``
- P0600R1 - ``nodiscard`` in the library
- P0339R6 - ``polymorphic_allocator<>`` as a vocabulary type

Improvements and New Features
-----------------------------
Expand Down
6 changes: 3 additions & 3 deletions libcxx/docs/Status/Cxx20Issues.csv
Expand Up @@ -201,7 +201,7 @@
"`3201 <https://wg21.link/LWG3201>`__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|",""
"`3226 <https://wg21.link/LWG3226>`__","``zoned_time``\ constructor from ``string_view``\ should accept ``zoned_time<Duration2, TimeZonePtr2>``\ ","Prague","","","|chrono|"
"`3233 <https://wg21.link/LWG3233>`__","Broken requirements for ``shared_ptr``\ converting constructors","Prague","",""
"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0"
"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","16.0"
"`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","",""
"`3242 <https://wg21.link/LWG3242>`__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","Clang 14","|format|"
"`3243 <https://wg21.link/LWG3243>`__","``std::format``\ and negative zeroes","Prague","|Complete|","14.0","|format|"
Expand Down Expand Up @@ -232,9 +232,9 @@
"`3301 <https://wg21.link/LWG3301>`__","``transform_view::iterator``\ has incorrect ``iterator_category``\ ","Prague","|Complete|","15.0","|ranges|"
"`3302 <https://wg21.link/LWG3302>`__","Range adaptor objects ``keys``\ and ``values``\ are unspecified","Prague","","","|ranges|"
"`3303 <https://wg21.link/LWG3303>`__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","Prague","",""
"`3304 <https://wg21.link/LWG3304>`__","Allocate functions of ``std::polymorphic_allocator``\ should require ``[[nodiscard]]``\ ","Prague","",""
"`3304 <https://wg21.link/LWG3304>`__","Allocate functions of ``std::polymorphic_allocator``\ should require ``[[nodiscard]]``\ ","Prague","|Complete|","16.0"
"`3307 <https://wg21.link/LWG3307>`__","``std::allocator<void>().allocate(n)``\ ","Prague","",""
"`3310 <https://wg21.link/LWG3310>`__","Replace ``SIZE_MAX``\ with ``numeric_limits<size_t>::max()``\ ","Prague","",""
"`3310 <https://wg21.link/LWG3310>`__","Replace ``SIZE_MAX``\ with ``numeric_limits<size_t>::max()``\ ","Prague","|Complete|","16.0"
"`3313 <https://wg21.link/LWG3313>`__","``join_view::iterator::operator--``\ is incorrectly constrained","Prague","|Complete|","14.0","|ranges|"
"`3314 <https://wg21.link/LWG3314>`__","Is stream insertion behavior locale dependent when ``Period::type``\ is ``micro``\ ?","Prague","|Complete|","16.0","|chrono|"
"`3315 <https://wg21.link/LWG3315>`__","Correct Allocator Default Behavior","Prague","",""
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Papers.csv
Expand Up @@ -80,7 +80,7 @@
"`P1285R0 <https://wg21.link/P1285R0>`__","LWG","Improving Completeness Requirements for Type Traits","San Diego","* *",""
"`P1353R0 <https://wg21.link/P1353R0>`__","CWG","Missing feature test macros","San Diego","* *",""
"","","","","",""
"`P0339R6 <https://wg21.link/P0339R6>`__","LWG","polymorphic_allocator<> as a vocabulary type","Kona","",""
"`P0339R6 <https://wg21.link/P0339R6>`__","LWG","polymorphic_allocator<> as a vocabulary type","Kona","|Complete|","16.0"
"`P0340R3 <https://wg21.link/P0340R3>`__","LWG","Making std::underlying_type SFINAE-friendly","Kona","|Complete|","9.0"
"`P0738R2 <https://wg21.link/P0738R2>`__","LWG","I Stream, You Stream, We All Stream for istream_iterator","Kona","",""
"`P0811R3 <https://wg21.link/P0811R3>`__","LWG","Well-behaved interpolation for numbers and pointers","Kona","|Complete|","9.0"
Expand Down
48 changes: 47 additions & 1 deletion libcxx/include/__memory_resource/polymorphic_allocator.h
Expand Up @@ -12,6 +12,7 @@
#include <__assert>
#include <__config>
#include <__memory_resource/memory_resource.h>
#include <__utility/transaction.h>
#include <cstddef>
#include <limits>
#include <new>
Expand All @@ -33,8 +34,13 @@ namespace pmr {

// [mem.poly.allocator.class]

template <class _ValueType>
template <class _ValueType
# if _LIBCPP_STD_VER >= 20
= byte
# endif
>
class _LIBCPP_TEMPLATE_VIS polymorphic_allocator {

public:
using value_type = _ValueType;

Expand Down Expand Up @@ -66,6 +72,46 @@ class _LIBCPP_TEMPLATE_VIS polymorphic_allocator {
__res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
}

# if _LIBCPP_STD_VER >= 20

[[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] void*
allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) {
return __res_->allocate(__nbytes, __alignment);
}

void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) {
__res_->deallocate(__ptr, __nbytes, __alignment);
}

template <class _Type>
[[nodiscard]] _Type* allocate_object(size_t __n = 1) {
if (numeric_limits<size_t>::max() / sizeof(_Type) < __n)
std::__throw_bad_array_new_length();
return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type)));
}

template <class _Type>
void deallocate_object(_Type* __ptr, size_t __n = 1) {
deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type));
}

template <class _Type, class... _CtorArgs>
[[nodiscard]] _Type* new_object(_CtorArgs&&... __ctor_args) {
_Type* __ptr = allocate_object<_Type>();
__transaction __guard([&] { deallocate_object(__ptr); });
construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...);
__guard.__complete();
return __ptr;
}

template <class _Type>
void delete_object(_Type* __ptr) {
destroy(__ptr);
deallocate_object(__ptr);
}

# endif // _LIBCPP_STD_VER >= 20

template <class _Tp, class... _Ts>
_LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) {
std::__user_alloc_construct_impl(
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/__type_traits/is_nothrow_constructible.h
Expand Up @@ -11,6 +11,9 @@

#include <__config>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_reference.h>
#include <__utility/declval.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__utility/transaction.h
Expand Up @@ -10,9 +10,9 @@
#define _LIBCPP___UTILITY_TRANSACTION_H

#include <__config>
#include <__type_traits/is_nothrow_move_constructible.h>
#include <__utility/exchange.h>
#include <__utility/move.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/experimental/iterator
Expand Up @@ -118,4 +118,8 @@ _LIBCPP_END_NAMESPACE_LFTS

#endif // _LIBCPP_STD_VER > 11

#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
# include <type_traits>
#endif

#endif // _LIBCPP_EXPERIMENTAL_ITERATOR
2 changes: 1 addition & 1 deletion libcxx/include/version
Expand Up @@ -354,7 +354,7 @@ __cpp_lib_void_t 201411L <type_traits>
# endif
# define __cpp_lib_list_remove_return_type 201806L
# define __cpp_lib_math_constants 201907L
// # define __cpp_lib_polymorphic_allocator 201902L
# define __cpp_lib_polymorphic_allocator 201902L
# define __cpp_lib_ranges 201811L
# define __cpp_lib_remove_cvref 201711L
# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore)
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx03.csv
Expand Up @@ -556,6 +556,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex concepts
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx11.csv
Expand Up @@ -556,6 +556,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex concepts
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx14.csv
Expand Up @@ -558,6 +558,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex concepts
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx17.csv
Expand Up @@ -558,6 +558,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex concepts
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx20.csv
Expand Up @@ -569,6 +569,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex concepts
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/transitive_includes/cxx2b.csv
Expand Up @@ -438,6 +438,7 @@ memory_resource mutex
memory_resource new
memory_resource stdexcept
memory_resource tuple
memory_resource type_traits
memory_resource version
mutex atomic
mutex cstddef
Expand Down
@@ -0,0 +1,19 @@
//===----------------------------------------------------------------------===//
//
// 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++03, c++11, c++14, c++17

// check that clang warns on non-power-of-two alignment

#include <memory_resource>

void func() {
std::pmr::polymorphic_allocator<> allocator;
(void)allocator.allocate_bytes(0, 3); // expected-warning {{requested alignment is not a power of 2}}

}
Expand Up @@ -65,17 +65,11 @@
# error "__cpp_lib_memory_resource should have the value 201603L in c++20"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++20"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++20"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
# endif

#elif TEST_STD_VER > 20
Expand All @@ -87,17 +81,11 @@
# error "__cpp_lib_memory_resource should have the value 201603L in c++2b"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
# endif

#endif // TEST_STD_VER > 20
Expand Down
Expand Up @@ -3208,17 +3208,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++20"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++20"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++20"
# endif

# ifndef __cpp_lib_quoted_string_io
Expand Down Expand Up @@ -4478,17 +4472,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_polymorphic_allocator
# error "__cpp_lib_polymorphic_allocator should be defined in c++2b"
# endif
# if __cpp_lib_polymorphic_allocator != 201902L
# error "__cpp_lib_polymorphic_allocator should have the value 201902L in c++2b"
# endif

# ifndef __cpp_lib_quoted_string_io
Expand Down
@@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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++03, c++11, c++14, c++17
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}}

// test_memory_resource requires RTTI for dynamic_cast
// UNSUPPORTED: no-rtti

// <memory_resource>

// polymorphic_allocator::allocate_bytes()
// polymorphic_allocator::deallocate_bytes()

#include <algorithm>
#include <cassert>
#include <concepts>
#include <memory_resource>

#include "tracking_mem_res.h"

template <class T>
void test() {
size_t last_size = 0;
size_t last_alignment = 0;
TrackingMemRes resource(&last_size, &last_alignment);

std::pmr::polymorphic_allocator<T> allocator(&resource);

{
std::same_as<void*> decltype(auto) allocation = allocator.allocate_bytes(13);
auto ptr = static_cast<char*>(allocation);
std::fill(ptr, ptr + 13, '0');
assert(last_size == 13);
assert(last_alignment == alignof(max_align_t));
allocator.deallocate_bytes(allocation, 13);
assert(last_size == 13);
assert(last_alignment == alignof(max_align_t));
}
{
void* allocation = allocator.allocate_bytes(13, 64);
auto ptr = static_cast<char*>(allocation);
std::fill(ptr, ptr + 13, '0');
assert(last_size == 13);
assert(last_alignment == 64);
allocator.deallocate_bytes(allocation, 13, 64);
assert(last_size == 13);
assert(last_alignment == 64);
}
}

struct S {};

int main(int, char**) {
test<std::byte>();
test<S>();

return 0;
}

0 comments on commit 181cce6

Please sign in to comment.