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