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