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 <__memory_resource/memory_resource.h> 15 #include <__utility/exception_guard.h> 16 #include <cstddef> 17 #include <limits> 18 #include <new> 19 #include <stdexcept> 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_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 _LIBCPP_NODISCARD_AFTER_CXX17 _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(__n <= __max_size(), "deallocate called for size which exceeds max_size()"); 72 __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType)); 73 } 74 75 # if _LIBCPP_STD_VER >= 20 76 77 [[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI void* 78 allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) { 79 return __res_->allocate(__nbytes, __alignment); 80 } 81 82 _LIBCPP_HIDE_FROM_ABI void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) { 83 __res_->deallocate(__ptr, __nbytes, __alignment); 84 } 85 86 template <class _Type> 87 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* allocate_object(size_t __n = 1) { 88 if (numeric_limits<size_t>::max() / sizeof(_Type) < __n) 89 std::__throw_bad_array_new_length(); 90 return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type))); 91 } 92 93 template <class _Type> 94 _LIBCPP_HIDE_FROM_ABI void deallocate_object(_Type* __ptr, size_t __n = 1) { 95 deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type)); 96 } 97 98 template <class _Type, class... _CtorArgs> new_object(_CtorArgs &&...__ctor_args)99 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* new_object(_CtorArgs&&... __ctor_args) { 100 _Type* __ptr = allocate_object<_Type>(); 101 auto __guard = std::__make_exception_guard([&] { deallocate_object(__ptr); }); 102 construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...); 103 __guard.__complete(); 104 return __ptr; 105 } 106 107 template <class _Type> delete_object(_Type * __ptr)108 _LIBCPP_HIDE_FROM_ABI void delete_object(_Type* __ptr) { 109 destroy(__ptr); 110 deallocate_object(__ptr); 111 } 112 113 # endif // _LIBCPP_STD_VER >= 20 114 115 template <class _Tp, class... _Ts> construct(_Tp * __p,_Ts &&...__args)116 _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) { 117 std::__user_alloc_construct_impl( 118 typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(), 119 __p, 120 *this, 121 std::forward<_Ts>(__args)...); 122 } 123 124 template <class _T1, class _T2, class... _Args1, class... _Args2> 125 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1,_T2> * __p,piecewise_construct_t,tuple<_Args1...> __x,tuple<_Args2...> __y)126 construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { 127 ::new ((void*)__p) pair<_T1, _T2>( 128 piecewise_construct, 129 __transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(), 130 std::move(__x), 131 typename __make_tuple_indices<sizeof...(_Args1)>::type{}), 132 __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(), 133 std::move(__y), 134 typename __make_tuple_indices<sizeof...(_Args2)>::type{})); 135 } 136 137 template <class _T1, class _T2> construct(pair<_T1,_T2> * __p)138 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p) { 139 construct(__p, piecewise_construct, tuple<>(), tuple<>()); 140 } 141 142 template <class _T1, class _T2, class _Up, class _Vp> construct(pair<_T1,_T2> * __p,_Up && __u,_Vp && __v)143 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v) { 144 construct(__p, 145 piecewise_construct, 146 std::forward_as_tuple(std::forward<_Up>(__u)), 147 std::forward_as_tuple(std::forward<_Vp>(__v))); 148 } 149 150 template <class _T1, class _T2, class _U1, class _U2> construct(pair<_T1,_T2> * __p,const pair<_U1,_U2> & __pr)151 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, const pair<_U1, _U2>& __pr) { 152 construct(__p, piecewise_construct, std::forward_as_tuple(__pr.first), std::forward_as_tuple(__pr.second)); 153 } 154 155 template <class _T1, class _T2, class _U1, class _U2> construct(pair<_T1,_T2> * __p,pair<_U1,_U2> && __pr)156 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, pair<_U1, _U2>&& __pr) { 157 construct(__p, 158 piecewise_construct, 159 std::forward_as_tuple(std::forward<_U1>(__pr.first)), 160 std::forward_as_tuple(std::forward<_U2>(__pr.second))); 161 } 162 163 template <class _Tp> destroy(_Tp * __p)164 _LIBCPP_HIDE_FROM_ABI void destroy(_Tp* __p) { 165 __p->~_Tp(); 166 } 167 select_on_container_copy_construction()168 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept { 169 return polymorphic_allocator(); 170 } 171 resource()172 _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } 173 174 private: 175 template <class... _Args, size_t... _Is> 176 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...> __transform_tuple(integral_constant<int,0>,tuple<_Args...> && __t,__tuple_indices<_Is...>)177 __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 178 return std::forward_as_tuple(std::get<_Is>(std::move(__t))...); 179 } 180 181 template <class... _Args, size_t... _Is> 182 _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...> __transform_tuple(integral_constant<int,1>,tuple<_Args...> && __t,__tuple_indices<_Is...>)183 __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 184 using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>; 185 return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...); 186 } 187 188 template <class... _Args, size_t... _Is> 189 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&> __transform_tuple(integral_constant<int,2>,tuple<_Args...> && __t,__tuple_indices<_Is...>)190 __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, __tuple_indices<_Is...>) { 191 using _Tup = tuple<_Args&&..., polymorphic_allocator&>; 192 return _Tup(std::get<_Is>(std::move(__t))..., *this); 193 } 194 __max_size()195 _LIBCPP_HIDE_FROM_ABI size_t __max_size() const noexcept { 196 return numeric_limits<size_t>::max() / sizeof(value_type); 197 } 198 199 memory_resource* __res_; 200 }; 201 202 // [mem.poly.allocator.eq] 203 204 template <class _Tp, class _Up> 205 inline _LIBCPP_HIDE_FROM_ABI bool 206 operator==(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { 207 return *__lhs.resource() == *__rhs.resource(); 208 } 209 210 template <class _Tp, class _Up> 211 inline _LIBCPP_HIDE_FROM_ABI bool 212 operator!=(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept { 213 return !(__lhs == __rhs); 214 } 215 216 } // namespace pmr 217 218 _LIBCPP_END_NAMESPACE_STD 219 220 #endif // _LIBCPP_STD_VER >= 17 221 222 _LIBCPP_POP_MACROS 223 224 #endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H 225