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