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_BEGIN_NAMESPACE_LFTS_PMR 86 87 // Round __s up to next multiple of __a. 88 inline _LIBCPP_INLINE_VISIBILITY 89 size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT 90 { 91 _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows"); 92 return (__s + __a - 1) & ~(__a - 1); 93 } 94 95 // 8.5, memory.resource 96 class _LIBCPP_TEMPLATE_VIS memory_resource 97 { 98 static const size_t __max_align = alignof(max_align_t); 99 100 // 8.5.2, memory.resource.public 101 public: 102 virtual ~memory_resource() = default; 103 104 _LIBCPP_INLINE_VISIBILITY 105 void* allocate(size_t __bytes, size_t __align = __max_align) 106 { return do_allocate(__bytes, __align); } 107 108 _LIBCPP_INLINE_VISIBILITY 109 void deallocate(void * __p, size_t __bytes, size_t __align = __max_align) 110 { do_deallocate(__p, __bytes, __align); } 111 112 _LIBCPP_INLINE_VISIBILITY 113 bool is_equal(memory_resource const & __other) const _NOEXCEPT 114 { return do_is_equal(__other); } 115 116 // 8.5.3, memory.resource.priv 117 protected: 118 virtual void* do_allocate(size_t, size_t) = 0; 119 virtual void do_deallocate(void*, size_t, size_t) = 0; 120 virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0; 121 }; 122 123 // 8.5.4, memory.resource.eq 124 inline _LIBCPP_INLINE_VISIBILITY 125 bool operator==(memory_resource const & __lhs, 126 memory_resource const & __rhs) _NOEXCEPT 127 { 128 return &__lhs == &__rhs || __lhs.is_equal(__rhs); 129 } 130 131 inline _LIBCPP_INLINE_VISIBILITY 132 bool operator!=(memory_resource const & __lhs, 133 memory_resource const & __rhs) _NOEXCEPT 134 { 135 return !(__lhs == __rhs); 136 } 137 138 _LIBCPP_FUNC_VIS 139 memory_resource * new_delete_resource() _NOEXCEPT; 140 141 _LIBCPP_FUNC_VIS 142 memory_resource * null_memory_resource() _NOEXCEPT; 143 144 _LIBCPP_FUNC_VIS 145 memory_resource * get_default_resource() _NOEXCEPT; 146 147 _LIBCPP_FUNC_VIS 148 memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT; 149 150 // 8.6, memory.polymorphic.allocator.class 151 152 // 8.6.1, memory.polymorphic.allocator.overview 153 template <class _ValueType> 154 class _LIBCPP_TEMPLATE_VIS polymorphic_allocator 155 { 156 public: 157 typedef _ValueType value_type; 158 159 // 8.6.2, memory.polymorphic.allocator.ctor 160 _LIBCPP_INLINE_VISIBILITY 161 polymorphic_allocator() _NOEXCEPT 162 : __res_(_VSTD_LFTS_PMR::get_default_resource()) 163 {} 164 165 _LIBCPP_INLINE_VISIBILITY 166 polymorphic_allocator(memory_resource * __r) _NOEXCEPT 167 : __res_(__r) 168 {} 169 170 polymorphic_allocator(polymorphic_allocator const &) = default; 171 172 template <class _Tp> 173 _LIBCPP_INLINE_VISIBILITY 174 polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT 175 : __res_(__other.resource()) 176 {} 177 178 polymorphic_allocator & 179 operator=(polymorphic_allocator const &) = delete; 180 181 // 8.6.3, memory.polymorphic.allocator.mem 182 _LIBCPP_INLINE_VISIBILITY 183 _ValueType* allocate(size_t __n) { 184 if (__n > __max_size()) { 185 __throw_length_error( 186 "std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)" 187 " 'n' exceeds maximum supported size"); 188 } 189 return static_cast<_ValueType*>( 190 __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType)) 191 ); 192 } 193 194 _LIBCPP_INLINE_VISIBILITY 195 void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT { 196 _LIBCPP_ASSERT(__n <= __max_size(), 197 "deallocate called for size which exceeds max_size()"); 198 __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType)); 199 } 200 201 template <class _Tp, class ..._Ts> 202 _LIBCPP_INLINE_VISIBILITY 203 void construct(_Tp* __p, _Ts &&... __args) 204 { 205 _VSTD_LFTS::__lfts_user_alloc_construct( 206 __p, resource(), _VSTD::forward<_Ts>(__args)... 207 ); 208 } 209 210 template <class _T1, class _T2, class ..._Args1, class ..._Args2> 211 _LIBCPP_INLINE_VISIBILITY 212 void construct(pair<_T1, _T2>* __p, piecewise_construct_t, 213 tuple<_Args1...> __x, tuple<_Args2...> __y) 214 { 215 ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct 216 , __transform_tuple( 217 typename __lfts_uses_alloc_ctor< 218 _T1, memory_resource*, _Args1... 219 >::type() 220 , _VSTD::move(__x) 221 , typename __make_tuple_indices<sizeof...(_Args1)>::type{} 222 ) 223 , __transform_tuple( 224 typename __lfts_uses_alloc_ctor< 225 _T2, memory_resource*, _Args2... 226 >::type() 227 , _VSTD::move(__y) 228 , typename __make_tuple_indices<sizeof...(_Args2)>::type{} 229 ) 230 ); 231 } 232 233 template <class _T1, class _T2> 234 _LIBCPP_INLINE_VISIBILITY 235 void construct(pair<_T1, _T2>* __p) { 236 construct(__p, piecewise_construct, tuple<>(), tuple<>()); 237 } 238 239 template <class _T1, class _T2, class _Up, class _Vp> 240 _LIBCPP_INLINE_VISIBILITY 241 void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) { 242 construct(__p, piecewise_construct 243 , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u)) 244 , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v))); 245 } 246 247 template <class _T1, class _T2, class _U1, class _U2> 248 _LIBCPP_INLINE_VISIBILITY 249 void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) { 250 construct(__p, piecewise_construct 251 , _VSTD::forward_as_tuple(__pr.first) 252 , _VSTD::forward_as_tuple(__pr.second)); 253 } 254 255 template <class _T1, class _T2, class _U1, class _U2> 256 _LIBCPP_INLINE_VISIBILITY 257 void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){ 258 construct(__p, piecewise_construct 259 , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first)) 260 , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second))); 261 } 262 263 template <class _Tp> 264 _LIBCPP_INLINE_VISIBILITY 265 void destroy(_Tp * __p) _NOEXCEPT 266 { __p->~_Tp(); } 267 268 _LIBCPP_INLINE_VISIBILITY 269 polymorphic_allocator 270 select_on_container_copy_construction() const _NOEXCEPT 271 { return polymorphic_allocator(); } 272 273 _LIBCPP_INLINE_VISIBILITY 274 memory_resource * resource() const _NOEXCEPT 275 { return __res_; } 276 277 private: 278 template <class ..._Args, size_t ..._Idx> 279 _LIBCPP_INLINE_VISIBILITY 280 tuple<_Args&&...> 281 __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t, 282 __tuple_indices<_Idx...>) const 283 { 284 return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...); 285 } 286 287 template <class ..._Args, size_t ..._Idx> 288 _LIBCPP_INLINE_VISIBILITY 289 tuple<allocator_arg_t const&, memory_resource*, _Args&&...> 290 __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t, 291 __tuple_indices<_Idx...>) const 292 { 293 using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>; 294 return _Tup(allocator_arg, resource(), 295 _VSTD::get<_Idx>(_VSTD::move(__t))...); 296 } 297 298 template <class ..._Args, size_t ..._Idx> 299 _LIBCPP_INLINE_VISIBILITY 300 tuple<_Args&&..., memory_resource*> 301 __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t, 302 __tuple_indices<_Idx...>) const 303 { 304 using _Tup = tuple<_Args&&..., memory_resource*>; 305 return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource()); 306 } 307 308 _LIBCPP_INLINE_VISIBILITY 309 size_t __max_size() const _NOEXCEPT 310 { return numeric_limits<size_t>::max() / sizeof(value_type); } 311 312 memory_resource * __res_; 313 }; 314 315 // 8.6.4, memory.polymorphic.allocator.eq 316 317 template <class _Tp, class _Up> 318 inline _LIBCPP_INLINE_VISIBILITY 319 bool operator==(polymorphic_allocator<_Tp> const & __lhs, 320 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT 321 { 322 return *__lhs.resource() == *__rhs.resource(); 323 } 324 325 template <class _Tp, class _Up> 326 inline _LIBCPP_INLINE_VISIBILITY 327 bool operator!=(polymorphic_allocator<_Tp> const & __lhs, 328 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT 329 { 330 return !(__lhs == __rhs); 331 } 332 333 // 8.7, memory.resource.adaptor 334 335 // 8.7.1, memory.resource.adaptor.overview 336 template <class _CharAlloc> 337 class _LIBCPP_TEMPLATE_VIS __resource_adaptor_imp 338 : public memory_resource 339 { 340 using _CTraits = allocator_traits<_CharAlloc>; 341 static_assert(is_same<typename _CTraits::value_type, char>::value 342 && is_same<typename _CTraits::pointer, char*>::value 343 && is_same<typename _CTraits::void_pointer, void*>::value, ""); 344 345 static const size_t _MaxAlign = alignof(max_align_t); 346 347 using _Alloc = typename _CTraits::template rebind_alloc< 348 typename aligned_storage<_MaxAlign, _MaxAlign>::type 349 >; 350 351 using _ValueType = typename _Alloc::value_type; 352 353 _Alloc __alloc_; 354 355 public: 356 typedef _CharAlloc allocator_type; 357 358 __resource_adaptor_imp() = default; 359 __resource_adaptor_imp(__resource_adaptor_imp const &) = default; 360 __resource_adaptor_imp(__resource_adaptor_imp &&) = default; 361 362 // 8.7.2, memory.resource.adaptor.ctor 363 364 _LIBCPP_INLINE_VISIBILITY 365 explicit __resource_adaptor_imp(allocator_type const & __a) 366 : __alloc_(__a) 367 {} 368 369 _LIBCPP_INLINE_VISIBILITY 370 explicit __resource_adaptor_imp(allocator_type && __a) 371 : __alloc_(_VSTD::move(__a)) 372 {} 373 374 __resource_adaptor_imp & 375 operator=(__resource_adaptor_imp const &) = default; 376 377 _LIBCPP_INLINE_VISIBILITY 378 allocator_type get_allocator() const 379 { return __alloc_; } 380 381 // 8.7.3, memory.resource.adaptor.mem 382 protected: 383 virtual void * do_allocate(size_t __bytes, size_t) 384 { 385 if (__bytes > __max_size()) { 386 __throw_length_error( 387 "std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)" 388 " 'bytes' exceeds maximum supported size"); 389 } 390 size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; 391 return __alloc_.allocate(__s); 392 } 393 394 virtual void do_deallocate(void * __p, size_t __bytes, size_t) 395 { 396 _LIBCPP_ASSERT(__bytes <= __max_size(), 397 "do_deallocate called for size which exceeds the maximum allocation size"); 398 size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; 399 __alloc_.deallocate((_ValueType*)__p, __s); 400 } 401 402 virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT { 403 __resource_adaptor_imp const * __p 404 = dynamic_cast<__resource_adaptor_imp const *>(&__other); 405 return __p ? __alloc_ == __p->__alloc_ : false; 406 } 407 408 private: 409 _LIBCPP_INLINE_VISIBILITY 410 size_t __max_size() const _NOEXCEPT { 411 return numeric_limits<size_t>::max() - _MaxAlign; 412 } 413 }; 414 415 template <class _Alloc> 416 using resource_adaptor = __resource_adaptor_imp< 417 typename allocator_traits<_Alloc>::template rebind_alloc<char> 418 >; 419 420 _LIBCPP_END_NAMESPACE_LFTS_PMR 421 422 #endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */ 423