1// <experimental/memory_resource> -*- C++ -*- 2 3// Copyright (C) 2015-2017 Free Software Foundation, Inc. 4// 5// This file is part of the GNU ISO C++ Library. This library is free 6// software; you can redistribute it and/or modify it under the 7// terms of the GNU General Public License as published by the 8// Free Software Foundation; either version 3, or (at your option) 9// any later version. 10 11// This library is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15 16// Under Section 7 of GPL version 3, you are granted additional 17// permissions described in the GCC Runtime Library Exception, version 18// 3.1, as published by the Free Software Foundation. 19 20// You should have received a copy of the GNU General Public License and 21// a copy of the GCC Runtime Library Exception along with this program; 22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23// <http://www.gnu.org/licenses/>. 24 25/** @file experimental/memory_resource 26 * This is a TS C++ Library header. 27 */ 28 29#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 30#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1 31 32#include <memory> 33#include <new> 34#include <atomic> 35#include <cstddef> 36#include <experimental/bits/lfts_config.h> 37 38namespace std { 39namespace experimental { 40inline namespace fundamentals_v2 { 41namespace pmr { 42_GLIBCXX_BEGIN_NAMESPACE_VERSION 43 44#define __cpp_lib_experimental_memory_resources 201402L 45 46 class memory_resource; 47 48 template <typename _Tp> 49 class polymorphic_allocator; 50 51 template <typename _Alloc> 52 class __resource_adaptor_imp; 53 54 template <typename _Alloc> 55 using resource_adaptor = __resource_adaptor_imp< 56 typename allocator_traits<_Alloc>::template rebind_alloc<char>>; 57 58 template <typename _Tp> 59 struct __uses_allocator_construction_helper; 60 61 // Global memory resources 62 memory_resource* new_delete_resource() noexcept; 63 memory_resource* null_memory_resource() noexcept; 64 65 // The default memory resource 66 memory_resource* get_default_resource() noexcept; 67 memory_resource* set_default_resource(memory_resource* __r) noexcept; 68 69 // Standard memory resources 70 71 // 8.5 Class memory_resource 72 class memory_resource 73 { 74 protected: 75 static constexpr size_t _S_max_align = alignof(max_align_t); 76 77 public: 78 virtual ~memory_resource() { } 79 80 void* 81 allocate(size_t __bytes, size_t __alignment = _S_max_align) 82 { return do_allocate(__bytes, __alignment); } 83 84 void 85 deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) 86 { return do_deallocate(__p, __bytes, __alignment); } 87 88 bool 89 is_equal(const memory_resource& __other) const noexcept 90 { return do_is_equal(__other); } 91 92 protected: 93 virtual void* 94 do_allocate(size_t __bytes, size_t __alignment) = 0; 95 96 virtual void 97 do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; 98 99 virtual bool 100 do_is_equal(const memory_resource& __other) const noexcept = 0; 101 }; 102 103 inline bool 104 operator==(const memory_resource& __a, 105 const memory_resource& __b) noexcept 106 { return &__a == &__b || __a.is_equal(__b); } 107 108 inline bool 109 operator!=(const memory_resource& __a, 110 const memory_resource& __b) noexcept 111 { return !(__a == __b); } 112 113 114 // 8.6 Class template polymorphic_allocator 115 template <class _Tp> 116 class polymorphic_allocator 117 { 118 using __uses_alloc1_ = __uses_alloc1<memory_resource*>; 119 using __uses_alloc2_ = __uses_alloc2<memory_resource*>; 120 121 template<typename _Tp1, typename... _Args> 122 void 123 _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) 124 { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } 125 126 template<typename _Tp1, typename... _Args> 127 void 128 _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) 129 { ::new(__p) _Tp1(allocator_arg, this->resource(), 130 std::forward<_Args>(__args)...); } 131 132 template<typename _Tp1, typename... _Args> 133 void 134 _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) 135 { ::new(__p) _Tp1(std::forward<_Args>(__args)..., 136 this->resource()); } 137 138 public: 139 using value_type = _Tp; 140 141 polymorphic_allocator() noexcept 142 : _M_resource(get_default_resource()) 143 { } 144 145 polymorphic_allocator(memory_resource* __r) 146 : _M_resource(__r) 147 { _GLIBCXX_DEBUG_ASSERT(__r); } 148 149 polymorphic_allocator(const polymorphic_allocator& __other) = default; 150 151 template <typename _Up> 152 polymorphic_allocator(const polymorphic_allocator<_Up>& 153 __other) noexcept 154 : _M_resource(__other.resource()) 155 { } 156 157 polymorphic_allocator& 158 operator=(const polymorphic_allocator& __rhs) = default; 159 160 _Tp* allocate(size_t __n) 161 { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), 162 alignof(_Tp))); } 163 164 void deallocate(_Tp* __p, size_t __n) 165 { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } 166 167 template <typename _Tp1, typename... _Args> //used here 168 void construct(_Tp1* __p, _Args&&... __args) 169 { 170 memory_resource* const __resource = this->resource(); 171 auto __use_tag 172 = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource); 173 _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); 174 } 175 176 // Specializations for pair using piecewise construction 177 template <typename _Tp1, typename _Tp2, 178 typename... _Args1, typename... _Args2> 179 void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 180 tuple<_Args1...> __x, 181 tuple<_Args2...> __y) 182 { 183 memory_resource* const __resource = this->resource(); 184 auto __x_use_tag = 185 __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); 186 auto __y_use_tag = 187 __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); 188 189 ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, 190 _M_construct_p(__x_use_tag, __x), 191 _M_construct_p(__y_use_tag, __y)); 192 } 193 194 template <typename _Tp1, typename _Tp2> 195 void construct(pair<_Tp1,_Tp2>* __p) 196 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 197 198 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 199 void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) 200 { this->construct(__p, piecewise_construct, 201 forward_as_tuple(std::forward<_Up>(__x)), 202 forward_as_tuple(std::forward<_Vp>(__y))); } 203 204 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 205 void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 206 { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), 207 forward_as_tuple(__pr.second)); } 208 209 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 210 void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) 211 { this->construct(__p, piecewise_construct, 212 forward_as_tuple(std::forward<_Up>(__pr.first)), 213 forward_as_tuple(std::forward<_Vp>(__pr.second))); } 214 215 template <typename _Up> 216 void destroy(_Up* __p) 217 { __p->~_Up(); } 218 219 // Return a default-constructed allocator (no allocator propagation) 220 polymorphic_allocator select_on_container_copy_construction() const 221 { return polymorphic_allocator(); } 222 223 memory_resource* resource() const 224 { return _M_resource; } 225 226 private: 227 template<typename _Tuple> 228 _Tuple&& 229 _M_construct_p(__uses_alloc0, _Tuple& __t) 230 { return std::move(__t); } 231 232 template<typename... _Args> 233 decltype(auto) 234 _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) 235 { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), 236 std::move(__t)); } 237 238 template<typename... _Args> 239 decltype(auto) 240 _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) 241 { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } 242 243 memory_resource* _M_resource; 244 }; 245 246 template <class _Tp1, class _Tp2> 247 bool operator==(const polymorphic_allocator<_Tp1>& __a, 248 const polymorphic_allocator<_Tp2>& __b) noexcept 249 { return *__a.resource() == *__b.resource(); } 250 251 template <class _Tp1, class _Tp2> 252 bool operator!=(const polymorphic_allocator<_Tp1>& __a, 253 const polymorphic_allocator<_Tp2>& __b) noexcept 254 { return !(__a == __b); } 255 256 // 8.7.1 __resource_adaptor_imp 257 template <typename _Alloc> 258 class __resource_adaptor_imp : public memory_resource 259 { 260 static_assert(is_same<char, 261 typename allocator_traits<_Alloc>::value_type>::value, 262 "Allocator's value_type is char"); 263 static_assert(is_same<char*, 264 typename allocator_traits<_Alloc>::pointer>::value, 265 "Allocator's pointer type is value_type*"); 266 static_assert(is_same<const char*, 267 typename allocator_traits<_Alloc>::const_pointer>::value, 268 "Allocator's const_pointer type is value_type const*"); 269 static_assert(is_same<void*, 270 typename allocator_traits<_Alloc>::void_pointer>::value, 271 "Allocator's void_pointer type is void*"); 272 static_assert(is_same<const void*, 273 typename allocator_traits<_Alloc>::const_void_pointer>::value, 274 "Allocator's const_void_pointer type is void const*"); 275 276 public: 277 using allocator_type = _Alloc; 278 279 __resource_adaptor_imp() = default; 280 __resource_adaptor_imp(const __resource_adaptor_imp&) = default; 281 __resource_adaptor_imp(__resource_adaptor_imp&&) = default; 282 283 explicit __resource_adaptor_imp(const _Alloc& __a2) 284 : _M_alloc(__a2) 285 { } 286 287 explicit __resource_adaptor_imp(_Alloc&& __a2) 288 : _M_alloc(std::move(__a2)) 289 { } 290 291 __resource_adaptor_imp& 292 operator=(const __resource_adaptor_imp&) = default; 293 294 allocator_type get_allocator() const noexcept { return _M_alloc; } 295 296 protected: 297 virtual void* 298 do_allocate(size_t __bytes, size_t __alignment) 299 { 300 using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 301 size_t __new_size = _S_aligned_size(__bytes, 302 _S_supported(__alignment) ? 303 __alignment : _S_max_align); 304 return _Aligned_alloc(_M_alloc).allocate(__new_size); 305 } 306 307 virtual void 308 do_deallocate(void* __p, size_t __bytes, size_t __alignment) 309 { 310 using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 311 size_t __new_size = _S_aligned_size(__bytes, 312 _S_supported(__alignment) ? 313 __alignment : _S_max_align); 314 using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer; 315 _Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p), 316 __new_size); 317 } 318 319 virtual bool 320 do_is_equal(const memory_resource& __other) const noexcept 321 { 322 auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other); 323 return __p ? (_M_alloc == __p->_M_alloc) : false; 324 } 325 326 private: 327 // Calculate Aligned Size 328 // Returns a size that is larger than or equal to __size and divisible 329 // by __alignment, where __alignment is required to be a power of 2. 330 static size_t 331 _S_aligned_size(size_t __size, size_t __alignment) 332 { return ((__size - 1)|(__alignment - 1)) + 1; } 333 334 // Determine whether alignment meets one of those preconditions: 335 // 1. Equal to Zero 336 // 2. Is power of two 337 static bool 338 _S_supported (size_t __x) 339 { return ((__x != 0) && !(__x & (__x - 1))); } 340 341 _Alloc _M_alloc; 342 }; 343 344 // Global memory resources 345 346 inline memory_resource* 347 new_delete_resource() noexcept 348 { 349 using type = resource_adaptor<std::allocator<char>>; 350 alignas(type) static unsigned char __buf[sizeof(type)]; 351 static type* __r = new(__buf) type; 352 return __r; 353 } 354 355 inline memory_resource* 356 null_memory_resource() noexcept 357 { 358 class type final : public memory_resource 359 { 360 void* 361 do_allocate(size_t, size_t) override 362 { std::__throw_bad_alloc(); } 363 364 void 365 do_deallocate(void*, size_t, size_t) noexcept override 366 { } 367 368 bool 369 do_is_equal(const memory_resource& __other) const noexcept override 370 { return this == &__other; } 371 }; 372 373 alignas(type) static unsigned char __buf[sizeof(type)]; 374 static type* __r = new(__buf) type; 375 return __r; 376 } 377 378 // The default memory resource 379 380 inline std::atomic<memory_resource*>& 381 __get_default_resource() 382 { 383 using type = atomic<memory_resource*>; 384 alignas(type) static unsigned char __buf[sizeof(type)]; 385 static type* __r = new(__buf) type(new_delete_resource()); 386 return *__r; 387 } 388 389 inline memory_resource* 390 get_default_resource() noexcept 391 { return __get_default_resource().load(); } 392 393 inline memory_resource* 394 set_default_resource(memory_resource* __r) noexcept 395 { 396 if (__r == nullptr) 397 __r = new_delete_resource(); 398 return __get_default_resource().exchange(__r); 399 } 400 401_GLIBCXX_END_NAMESPACE_VERSION 402} // namespace pmr 403} // namespace fundamentals_v2 404} // namespace experimental 405} // namespace std 406 407#endif 408