1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H 10 #define _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H 11 12 #include <__assert> 13 #include <__availability> 14 #include <__config> 15 #include <__memory_resource/memory_resource.h> 16 #include <__utility/exception_guard.h> 17 #include <cstddef> 18 #include <limits> 19 #include <new> 20 #include <stdexcept> 21 #include <tuple> 22 23 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 24 # pragma GCC system_header 25 #endif 26 27 _LIBCPP_PUSH_MACROS 28 #include <__undef_macros> 29 30 #if _LIBCPP_STD_VER >= 17 31 32 _LIBCPP_BEGIN_NAMESPACE_STD 33 34 namespace pmr { 35 36 // [mem.poly.allocator.class] 37 38 template <class _ValueType 39 # if _LIBCPP_STD_VER >= 20 40 = byte 41 # endif 42 > 43 class _LIBCPP_AVAILABILITY_PMR _LIBCPP_TEMPLATE_VIS polymorphic_allocator { 44 45 public: 46 using value_type = _ValueType; 47 48 // [mem.poly.allocator.ctor] 49 50 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {} 51 52 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) {} 53 54 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator&) = default; 55 56 template <class _Tp> 57 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator<_Tp>& __other) noexcept 58 : __res_(__other.resource()) {} 59 60 polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; 61 62 // [mem.poly.allocator.mem] 63 64 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI _ValueType* allocate(size_t __n) { 65 if (__n > __max_size()) { 66 __throw_bad_array_new_length(); 67 } 68 return static_cast<_ValueType*>(__res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))); 69 } 70 71 _LIBCPP_HIDE_FROM_ABI void deallocate(_ValueType* __p, size_t __n) { 72 _LIBCPP_ASSERT_UNCATEGORIZED(__n <= __max_size(), "deallocate called for size which exceeds max_size()"); 73 __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType)); 74 } 75 76 # if _LIBCPP_STD_VER >= 20 77 78 [[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI void* 79 allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) { 80 return __res_->allocate(__nbytes, __alignment); 81 } 82 83 _LIBCPP_HIDE_FROM_ABI void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) { 84 __res_->deallocate(__ptr, __nbytes, __alignment); 85 } 86 87 template <class _Type> 88 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* allocate_object(size_t __n = 1) { 89 if (numeric_limits<size_t>::max() / sizeof(_Type) < __n) 90 std::__throw_bad_array_new_length(); 91 return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type))); 92 } 93 94 template <class _Type> 95 _LIBCPP_HIDE_FROM_ABI void deallocate_object(_Type* __ptr, size_t __n = 1) { 96 deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type)); 97 } 98 99 template <class _Type, class... _CtorArgs> 100 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* new_object(_CtorArgs&&... __ctor_args) { 101 _Type* __ptr = allocate_object<_Type>(); 102 auto __guard = std::__make_exception_guard([&] { deallocate_object(__ptr); }); 103 construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...); 104 __guard.__complete(); 105 return __ptr; 106 } 107 108 template <class _Type> 109 _LIBCPP_HIDE_FROM_ABI void delete_object(_Type* __ptr) { 110 destroy(__ptr); 111 deallocate_object(__ptr); 112 } 113 114 # endif // _LIBCPP_STD_VER >= 20 115 116 template <class _Tp, class... _Ts> 117 _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) { 118 std::__user_alloc_construct_impl( 119 typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(), 120 __p, 121 *this, 122 std::forward<_Ts>(__args)...); 123 } 124 125 template <class _T1, class _T2, class... _Args1, class... _Args2> 126 _LIBCPP_HIDE_FROM_ABI void 127 construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { 128 ::new ((void*)__p) pair<_T1, _T2>( 129 piecewise_construct, 130 __transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(), 131 std::move(__x), 132 typename __make_tuple_indices<sizeof...(_Args1)>::type{}), 133 __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(), 134 std::move(__y), 135 typename __make_tuple_indices<sizeof...(_Args2)>::type{})); 136 } 137 138 template <class _T1, class _T2> 139 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p) { 140 construct(__p, piecewise_construct, tuple<>(), tuple<>()); 141 } 142 143 template <class _T1, class _T2, class _Up, class _Vp> 144 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v) { 145 construct(__p, 146 piecewise_construct, 147 std::forward_as_tuple(std::forward<_Up>(__u)), 148 std::forward_as_tuple(std::forward<_Vp>(__v))); 149 } 150 151 template <class _T1, class _T2, class _U1, class _U2> 152 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, const pair<_U1, _U2>& __pr) { 153 construct(__p, piecewise_construct, std::forward_as_tuple(__pr.first), std::forward_as_tuple(__pr.second)); 154 } 155 156 template <class _T1, class _T2, class _U1, class _U2> 157 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, pair<_U1, _U2>&& __pr) { 158 construct(__p, 159 piecewise_construct, 160 std::forward_as_tuple(std::forward<_U1>(__pr.first)), 161 std::forward_as_tuple(std::forward<_U2>(__pr.second))); 162 } 163 164 template <class _Tp> 165 _LIBCPP_HIDE_FROM_ABI void destroy(_Tp* __p) { 166 __p->~_Tp(); 167 } 168 169 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept { 170 return polymorphic_allocator(); 171 } 172 173 _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } 174 175 private: 176 template <class... _Args, size_t... _Is> 177 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> 178 __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 179 return std::forward_as_tuple(std::get<_Is>(std::move(__t))...); 180 } 181 182 template <class... _Args, size_t... _Is> 183 _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...> 184 __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 185 using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>; 186 return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...); 187 } 188 189 template <class... _Args, size_t... _Is> 190 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&> 191 __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 192 using _Tup = tuple<_Args&&..., polymorphic_allocator&>; 193 return _Tup(std::get<_Is>(std::move(__t))..., *this); 194 } 195 196 _LIBCPP_HIDE_FROM_ABI size_t __max_size() const noexcept { 197 return numeric_limits<size_t>::max() / sizeof(value_type); 198 } 199 200 memory_resource* __res_; 201 }; 202 203 // [mem.poly.allocator.eq] 204 205 template <class _Tp, class _Up> 206 inline _LIBCPP_HIDE_FROM_ABI bool 207 operator==(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { 208 return *__lhs.resource() == *__rhs.resource(); 209 } 210 211 # if _LIBCPP_STD_VER <= 17 212 213 template <class _Tp, class _Up> 214 inline _LIBCPP_HIDE_FROM_ABI bool 215 operator!=(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { 216 return !(__lhs == __rhs); 217 } 218 219 # endif 220 221 } // namespace pmr 222 223 _LIBCPP_END_NAMESPACE_STD 224 225 #endif // _LIBCPP_STD_VER >= 17 226 227 _LIBCPP_POP_MACROS 228 229 #endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H 230