250 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H10#define _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H11 12#include <__assert>13#include <__config>14#include <__cstddef/byte.h>15#include <__cstddef/max_align_t.h>16#include <__fwd/pair.h>17#include <__memory_resource/memory_resource.h>18#include <__new/exceptions.h>19#include <__new/placement_new_delete.h>20#include <__utility/exception_guard.h>21#include <__utility/piecewise_construct.h>22#include <limits>23#include <tuple>24 25#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)26# pragma GCC system_header27#endif28 29_LIBCPP_PUSH_MACROS30#include <__undef_macros>31 32#if _LIBCPP_STD_VER >= 1733 34_LIBCPP_BEGIN_NAMESPACE_STD35 36namespace pmr {37 38// [mem.poly.allocator.class]39 40template <class _ValueType41# if _LIBCPP_STD_VER >= 2042 = byte43# endif44 >45class _LIBCPP_AVAILABILITY_PMR polymorphic_allocator {46 47public:48 using value_type = _ValueType;49 50 // [mem.poly.allocator.ctor]51 52 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {}53 54 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* _LIBCPP_DIAGNOSE_NULLPTR __r) noexcept : __res_(__r) {55 _LIBCPP_ASSERT_NON_NULL(__r, "Attempted to pass a nullptr resource to polymorphic_alloator");56 }57 58 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator&) = default;59 60 template <class _Tp>61 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator<_Tp>& __other) noexcept62 : __res_(__other.resource()) {}63 64 polymorphic_allocator& operator=(const polymorphic_allocator&) = delete;65 66 // [mem.poly.allocator.mem]67 68 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ValueType* allocate(size_t __n) {69 if (__n > __max_size()) {70 std::__throw_bad_array_new_length();71 }72 return static_cast<_ValueType*>(__res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType)));73 }74 75 _LIBCPP_HIDE_FROM_ABI void deallocate(_ValueType* __p, size_t __n) {76 _LIBCPP_ASSERT_VALID_DEALLOCATION(77 __n <= __max_size(),78 "deallocate() called for a size which exceeds max_size(), leading to a memory leak "79 "(the argument will overflow and result in too few objects being deleted)");80 __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));81 }82 83# if _LIBCPP_STD_VER >= 2084 85 [[nodiscard]] [[using __gnu__: __alloc_size__(2), __alloc_align__(3)]] _LIBCPP_HIDE_FROM_ABI void*86 allocate_bytes(size_t __nbytes, size_t __alignment = alignof(max_align_t)) {87 return __res_->allocate(__nbytes, __alignment);88 }89 90 _LIBCPP_HIDE_FROM_ABI void deallocate_bytes(void* __ptr, size_t __nbytes, size_t __alignment = alignof(max_align_t)) {91 __res_->deallocate(__ptr, __nbytes, __alignment);92 }93 94 template <class _Type>95 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* allocate_object(size_t __n = 1) {96 if (numeric_limits<size_t>::max() / sizeof(_Type) < __n)97 std::__throw_bad_array_new_length();98 return static_cast<_Type*>(allocate_bytes(__n * sizeof(_Type), alignof(_Type)));99 }100 101 template <class _Type>102 _LIBCPP_HIDE_FROM_ABI void deallocate_object(_Type* __ptr, size_t __n = 1) {103 deallocate_bytes(__ptr, __n * sizeof(_Type), alignof(_Type));104 }105 106 template <class _Type, class... _CtorArgs>107 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Type* new_object(_CtorArgs&&... __ctor_args) {108 _Type* __ptr = allocate_object<_Type>();109 auto __guard = std::__make_exception_guard([&] { deallocate_object(__ptr); });110 construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...);111 __guard.__complete();112 return __ptr;113 }114 115 template <class _Type>116 _LIBCPP_HIDE_FROM_ABI void delete_object(_Type* __ptr) {117 destroy(__ptr);118 deallocate_object(__ptr);119 }120 121# endif // _LIBCPP_STD_VER >= 20122 123 template <class _Tp, class... _Ts>124 _LIBCPP_HIDE_FROM_ABI void construct(_Tp* __p, _Ts&&... __args) {125 std::__user_alloc_construct_impl(126 typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(),127 __p,128 *this,129 std::forward<_Ts>(__args)...);130 }131 132 template <class _T1, class _T2, class... _Args1, class... _Args2>133 _LIBCPP_HIDE_FROM_ABI void134 construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) {135 ::new ((void*)__p) pair<_T1, _T2>(136 piecewise_construct,137 __transform_tuple(typename __uses_alloc_ctor< _T1, polymorphic_allocator&, _Args1... >::type(),138 std::move(__x),139 make_index_sequence<sizeof...(_Args1)>()),140 __transform_tuple(typename __uses_alloc_ctor< _T2, polymorphic_allocator&, _Args2... >::type(),141 std::move(__y),142 make_index_sequence<sizeof...(_Args2)>()));143 }144 145 template <class _T1, class _T2>146 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p) {147 construct(__p, piecewise_construct, tuple<>(), tuple<>());148 }149 150 template <class _T1, class _T2, class _Up, class _Vp>151 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v) {152 construct(__p,153 piecewise_construct,154 std::forward_as_tuple(std::forward<_Up>(__u)),155 std::forward_as_tuple(std::forward<_Vp>(__v)));156 }157 158 template <class _T1, class _T2, class _U1, class _U2>159 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, const pair<_U1, _U2>& __pr) {160 construct(__p, piecewise_construct, std::forward_as_tuple(__pr.first), std::forward_as_tuple(__pr.second));161 }162 163 template <class _T1, class _T2, class _U1, class _U2>164 _LIBCPP_HIDE_FROM_ABI void construct(pair<_T1, _T2>* __p, pair<_U1, _U2>&& __pr) {165 construct(__p,166 piecewise_construct,167 std::forward_as_tuple(std::forward<_U1>(__pr.first)),168 std::forward_as_tuple(std::forward<_U2>(__pr.second)));169 }170 171 template <class _Tp>172 _LIBCPP_HIDE_FROM_ABI void destroy(_Tp* __p) {173 __p->~_Tp();174 }175 176 _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept {177 return polymorphic_allocator();178 }179 180 [[__gnu__::__returns_nonnull__]] _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; }181 182 _LIBCPP_HIDE_FROM_ABI friend bool183 operator==(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept {184 return *__lhs.resource() == *__rhs.resource();185 }186 187# if _LIBCPP_STD_VER <= 17188 // This overload is not specified, it was added due to LWG3683.189 _LIBCPP_HIDE_FROM_ABI friend bool190 operator!=(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept {191 return *__lhs.resource() != *__rhs.resource();192 }193# endif194 195private:196 template <class... _Args, size_t... _Is>197 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&...>198 __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, index_sequence<_Is...>) {199 return std::forward_as_tuple(std::get<_Is>(std::move(__t))...);200 }201 202 template <class... _Args, size_t... _Is>203 _LIBCPP_HIDE_FROM_ABI tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>204 __transform_tuple(integral_constant<int, 1>, tuple<_Args...>&& __t, index_sequence<_Is...>) {205 using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>;206 return _Tup(allocator_arg, *this, std::get<_Is>(std::move(__t))...);207 }208 209 template <class... _Args, size_t... _Is>210 _LIBCPP_HIDE_FROM_ABI tuple<_Args&&..., polymorphic_allocator&>211 __transform_tuple(integral_constant<int, 2>, tuple<_Args...>&& __t, index_sequence<_Is...>) {212 using _Tup = tuple<_Args&&..., polymorphic_allocator&>;213 return _Tup(std::get<_Is>(std::move(__t))..., *this);214 }215 216 _LIBCPP_HIDE_FROM_ABI size_t __max_size() const noexcept {217 return numeric_limits<size_t>::max() / sizeof(value_type);218 }219 220 memory_resource* __res_;221};222 223// [mem.poly.allocator.eq]224 225template <class _Tp, class _Up>226inline _LIBCPP_HIDE_FROM_ABI bool227operator==(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept {228 return *__lhs.resource() == *__rhs.resource();229}230 231# if _LIBCPP_STD_VER <= 17232 233template <class _Tp, class _Up>234inline _LIBCPP_HIDE_FROM_ABI bool235operator!=(const polymorphic_allocator<_Tp>& __lhs, const polymorphic_allocator<_Up>& __rhs) noexcept {236 return !(__lhs == __rhs);237}238 239# endif240 241} // namespace pmr242 243_LIBCPP_END_NAMESPACE_STD244 245#endif // _LIBCPP_STD_VER >= 17246 247_LIBCPP_POP_MACROS248 249#endif // _LIBCPP___MEMORY_RESOURCE_POLYMORPHIC_ALLOCATOR_H250