1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 3// 4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5// See https://llvm.org/LICENSE.txt for license information. 6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE 11#define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE 12 13/** 14 experimental/memory_resource synopsis 15 16// C++1y 17 18namespace std { 19namespace experimental { 20inline namespace fundamentals_v1 { 21namespace pmr { 22 23 class memory_resource; 24 25 bool operator==(const memory_resource& a, 26 const memory_resource& b) noexcept; 27 bool operator!=(const memory_resource& a, 28 const memory_resource& b) noexcept; 29 30 template <class Tp> class polymorphic_allocator; 31 32 template <class T1, class T2> 33 bool operator==(const polymorphic_allocator<T1>& a, 34 const polymorphic_allocator<T2>& b) noexcept; 35 template <class T1, class T2> 36 bool operator!=(const polymorphic_allocator<T1>& a, 37 const polymorphic_allocator<T2>& b) noexcept; 38 39 // The name resource_adaptor_imp is for exposition only. 40 template <class Allocator> class resource_adaptor_imp; 41 42 template <class Allocator> 43 using resource_adaptor = resource_adaptor_imp< 44 allocator_traits<Allocator>::rebind_alloc<char>>; 45 46 // Global memory resources 47 memory_resource* new_delete_resource() noexcept; 48 memory_resource* null_memory_resource() noexcept; 49 50 // The default memory resource 51 memory_resource* set_default_resource(memory_resource* r) noexcept; 52 memory_resource* get_default_resource() noexcept; 53 54 // Standard memory resources 55 struct pool_options; 56 class synchronized_pool_resource; 57 class unsynchronized_pool_resource; 58 class monotonic_buffer_resource; 59 60} // namespace pmr 61} // namespace fundamentals_v1 62} // namespace experimental 63} // namespace std 64 65 */ 66 67#include <__assert> 68#include <__tuple> 69#include <__utility/move.h> 70#include <cstddef> 71#include <cstdlib> 72#include <experimental/__config> 73#include <experimental/__memory> 74#include <limits> 75#include <memory> 76#include <new> 77#include <stdexcept> 78#include <type_traits> 79 80#include <utility> // TODO: Remove this 81 82#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 83# pragma GCC system_header 84#endif 85 86_LIBCPP_PUSH_MACROS 87#include <__undef_macros> 88 89_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR 90 91// Round __s up to next multiple of __a. 92inline _LIBCPP_INLINE_VISIBILITY 93size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT 94{ 95 _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows"); 96 return (__s + __a - 1) & ~(__a - 1); 97} 98 99// 8.5, memory.resource 100class _LIBCPP_TYPE_VIS memory_resource 101{ 102 static const size_t __max_align = _LIBCPP_ALIGNOF(max_align_t); 103 104// 8.5.2, memory.resource.public 105public: 106 virtual ~memory_resource() = default; 107 108 _LIBCPP_INLINE_VISIBILITY 109 void* allocate(size_t __bytes, size_t __align = __max_align) 110 { return do_allocate(__bytes, __align); } 111 112 _LIBCPP_INLINE_VISIBILITY 113 void deallocate(void * __p, size_t __bytes, size_t __align = __max_align) 114 { do_deallocate(__p, __bytes, __align); } 115 116 _LIBCPP_INLINE_VISIBILITY 117 bool is_equal(memory_resource const & __other) const _NOEXCEPT 118 { return do_is_equal(__other); } 119 120// 8.5.3, memory.resource.priv 121private: 122 virtual void* do_allocate(size_t, size_t) = 0; 123 virtual void do_deallocate(void*, size_t, size_t) = 0; 124 virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0; 125}; 126 127// 8.5.4, memory.resource.eq 128inline _LIBCPP_INLINE_VISIBILITY 129bool operator==(memory_resource const & __lhs, 130 memory_resource const & __rhs) _NOEXCEPT 131{ 132 return &__lhs == &__rhs || __lhs.is_equal(__rhs); 133} 134 135inline _LIBCPP_INLINE_VISIBILITY 136bool operator!=(memory_resource const & __lhs, 137 memory_resource const & __rhs) _NOEXCEPT 138{ 139 return !(__lhs == __rhs); 140} 141 142_LIBCPP_FUNC_VIS 143memory_resource * new_delete_resource() _NOEXCEPT; 144 145_LIBCPP_FUNC_VIS 146memory_resource * null_memory_resource() _NOEXCEPT; 147 148_LIBCPP_FUNC_VIS 149memory_resource * get_default_resource() _NOEXCEPT; 150 151_LIBCPP_FUNC_VIS 152memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT; 153 154// 8.6, memory.polymorphic.allocator.class 155 156// 8.6.1, memory.polymorphic.allocator.overview 157template <class _ValueType> 158class _LIBCPP_TEMPLATE_VIS polymorphic_allocator 159{ 160public: 161 typedef _ValueType value_type; 162 163 // 8.6.2, memory.polymorphic.allocator.ctor 164 _LIBCPP_INLINE_VISIBILITY 165 polymorphic_allocator() _NOEXCEPT 166 : __res_(_VSTD_LFTS_PMR::get_default_resource()) 167 {} 168 169 _LIBCPP_INLINE_VISIBILITY 170 polymorphic_allocator(memory_resource * __r) _NOEXCEPT 171 : __res_(__r) 172 {} 173 174 polymorphic_allocator(polymorphic_allocator const &) = default; 175 176 template <class _Tp> 177 _LIBCPP_INLINE_VISIBILITY 178 polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT 179 : __res_(__other.resource()) 180 {} 181 182 polymorphic_allocator & 183 operator=(polymorphic_allocator const &) = delete; 184 185 // 8.6.3, memory.polymorphic.allocator.mem 186 _LIBCPP_INLINE_VISIBILITY 187 _ValueType* allocate(size_t __n) { 188 if (__n > __max_size()) 189 __throw_bad_array_new_length(); 190 return static_cast<_ValueType*>( 191 __res_->allocate(__n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType)) 192 ); 193 } 194 195 _LIBCPP_INLINE_VISIBILITY 196 void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT { 197 _LIBCPP_ASSERT(__n <= __max_size(), 198 "deallocate called for size which exceeds max_size()"); 199 __res_->deallocate(__p, __n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType)); 200 } 201 202 template <class _Tp, class ..._Ts> 203 _LIBCPP_INLINE_VISIBILITY 204 void construct(_Tp* __p, _Ts &&... __args) 205 { 206 _VSTD_LFTS::__lfts_user_alloc_construct( 207 __p, *this, _VSTD::forward<_Ts>(__args)... 208 ); 209 } 210 211 template <class _T1, class _T2, class ..._Args1, class ..._Args2> 212 _LIBCPP_INLINE_VISIBILITY 213 void construct(pair<_T1, _T2>* __p, piecewise_construct_t, 214 tuple<_Args1...> __x, tuple<_Args2...> __y) 215 { 216 ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct 217 , __transform_tuple( 218 typename __lfts_uses_alloc_ctor< 219 _T1, polymorphic_allocator&, _Args1... 220 >::type() 221 , _VSTD::move(__x) 222 , typename __make_tuple_indices<sizeof...(_Args1)>::type{} 223 ) 224 , __transform_tuple( 225 typename __lfts_uses_alloc_ctor< 226 _T2, polymorphic_allocator&, _Args2... 227 >::type() 228 , _VSTD::move(__y) 229 , typename __make_tuple_indices<sizeof...(_Args2)>::type{} 230 ) 231 ); 232 } 233 234 template <class _T1, class _T2> 235 _LIBCPP_INLINE_VISIBILITY 236 void construct(pair<_T1, _T2>* __p) { 237 construct(__p, piecewise_construct, tuple<>(), tuple<>()); 238 } 239 240 template <class _T1, class _T2, class _Up, class _Vp> 241 _LIBCPP_INLINE_VISIBILITY 242 void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) { 243 construct(__p, piecewise_construct 244 , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u)) 245 , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v))); 246 } 247 248 template <class _T1, class _T2, class _U1, class _U2> 249 _LIBCPP_INLINE_VISIBILITY 250 void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) { 251 construct(__p, piecewise_construct 252 , _VSTD::forward_as_tuple(__pr.first) 253 , _VSTD::forward_as_tuple(__pr.second)); 254 } 255 256 template <class _T1, class _T2, class _U1, class _U2> 257 _LIBCPP_INLINE_VISIBILITY 258 void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){ 259 construct(__p, piecewise_construct 260 , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first)) 261 , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second))); 262 } 263 264 template <class _Tp> 265 _LIBCPP_INLINE_VISIBILITY 266 void destroy(_Tp * __p) _NOEXCEPT 267 { __p->~_Tp(); } 268 269 _LIBCPP_INLINE_VISIBILITY 270 polymorphic_allocator 271 select_on_container_copy_construction() const _NOEXCEPT 272 { return polymorphic_allocator(); } 273 274 _LIBCPP_INLINE_VISIBILITY 275 memory_resource * resource() const _NOEXCEPT 276 { return __res_; } 277 278private: 279 template <class ..._Args, size_t ..._Idx> 280 _LIBCPP_INLINE_VISIBILITY 281 tuple<_Args&&...> 282 __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, 283 __tuple_indices<_Idx...>) const 284 { 285 return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...); 286 } 287 288 template <class ..._Args, size_t ..._Idx> 289 _LIBCPP_INLINE_VISIBILITY 290 tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...> 291 __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t, 292 __tuple_indices<_Idx...>) 293 { 294 using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>; 295 return _Tup(allocator_arg, *this, 296 _VSTD::get<_Idx>(_VSTD::move(__t))...); 297 } 298 299 template <class ..._Args, size_t ..._Idx> 300 _LIBCPP_INLINE_VISIBILITY 301 tuple<_Args&&..., polymorphic_allocator&> 302 __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t, 303 __tuple_indices<_Idx...>) 304 { 305 using _Tup = tuple<_Args&&..., polymorphic_allocator&>; 306 return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., *this); 307 } 308 309 _LIBCPP_INLINE_VISIBILITY 310 size_t __max_size() const _NOEXCEPT 311 { return numeric_limits<size_t>::max() / sizeof(value_type); } 312 313 memory_resource * __res_; 314}; 315 316// 8.6.4, memory.polymorphic.allocator.eq 317 318template <class _Tp, class _Up> 319inline _LIBCPP_INLINE_VISIBILITY 320bool operator==(polymorphic_allocator<_Tp> const & __lhs, 321 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT 322{ 323 return *__lhs.resource() == *__rhs.resource(); 324} 325 326template <class _Tp, class _Up> 327inline _LIBCPP_INLINE_VISIBILITY 328bool operator!=(polymorphic_allocator<_Tp> const & __lhs, 329 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT 330{ 331 return !(__lhs == __rhs); 332} 333 334// 8.7, memory.resource.adaptor 335 336// 8.7.1, memory.resource.adaptor.overview 337template <class _CharAlloc> 338class _LIBCPP_TEMPLATE_VIS __resource_adaptor_imp 339 : public memory_resource 340{ 341 using _CTraits = allocator_traits<_CharAlloc>; 342 static_assert(is_same<typename _CTraits::value_type, char>::value 343 && is_same<typename _CTraits::pointer, char*>::value 344 && is_same<typename _CTraits::void_pointer, void*>::value, ""); 345 346 static const size_t _MaxAlign = _LIBCPP_ALIGNOF(max_align_t); 347 348 using _Alloc = typename _CTraits::template rebind_alloc< 349 typename aligned_storage<_MaxAlign, _MaxAlign>::type 350 >; 351 352 using _ValueType = typename _Alloc::value_type; 353 354 _Alloc __alloc_; 355 356public: 357 typedef _CharAlloc allocator_type; 358 359 __resource_adaptor_imp() = default; 360 __resource_adaptor_imp(__resource_adaptor_imp const &) = default; 361 __resource_adaptor_imp(__resource_adaptor_imp &&) = default; 362 363 // 8.7.2, memory.resource.adaptor.ctor 364 365 _LIBCPP_INLINE_VISIBILITY 366 explicit __resource_adaptor_imp(allocator_type const & __a) 367 : __alloc_(__a) 368 {} 369 370 _LIBCPP_INLINE_VISIBILITY 371 explicit __resource_adaptor_imp(allocator_type && __a) 372 : __alloc_(_VSTD::move(__a)) 373 {} 374 375 __resource_adaptor_imp & 376 operator=(__resource_adaptor_imp const &) = default; 377 378 _LIBCPP_INLINE_VISIBILITY 379 allocator_type get_allocator() const 380 { return __alloc_; } 381 382// 8.7.3, memory.resource.adaptor.mem 383private: 384 virtual void * do_allocate(size_t __bytes, size_t) 385 { 386 if (__bytes > __max_size()) 387 __throw_bad_array_new_length(); 388 size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; 389 return __alloc_.allocate(__s); 390 } 391 392 virtual void do_deallocate(void * __p, size_t __bytes, size_t) 393 { 394 _LIBCPP_ASSERT(__bytes <= __max_size(), 395 "do_deallocate called for size which exceeds the maximum allocation size"); 396 size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; 397 __alloc_.deallocate((_ValueType*)__p, __s); 398 } 399 400 virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT { 401 __resource_adaptor_imp const * __p 402 = dynamic_cast<__resource_adaptor_imp const *>(&__other); 403 return __p ? __alloc_ == __p->__alloc_ : false; 404 } 405 406 _LIBCPP_INLINE_VISIBILITY 407 size_t __max_size() const _NOEXCEPT { 408 return numeric_limits<size_t>::max() - _MaxAlign; 409 } 410}; 411 412template <class _Alloc> 413using resource_adaptor = __resource_adaptor_imp< 414 typename allocator_traits<_Alloc>::template rebind_alloc<char> 415 >; 416 417_LIBCPP_END_NAMESPACE_LFTS_PMR 418 419_LIBCPP_POP_MACROS 420 421#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */ 422