1// <experimental/memory_resource> -*- C++ -*- 2 3// Copyright (C) 2015-2016 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 auto __use_tag = __use_alloc<_Tp1, memory_resource*, 171 _Args...>(this->resource()); 172 _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); 173 } 174 175 // Specializations for pair using piecewise construction 176 template <typename _Tp1, typename _Tp2, 177 typename... _Args1, typename... _Args2> 178 void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 179 tuple<_Args1...> __x, 180 tuple<_Args2...> __y) 181 { 182 auto __x_use_tag = 183 __use_alloc<_Tp1, memory_resource*, _Args1...>(this->resource()); 184 auto __y_use_tag = 185 __use_alloc<_Tp2, memory_resource*, _Args2...>(this->resource()); 186 187 ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, 188 _M_construct_p(__x_use_tag, __x), 189 _M_construct_p(__y_use_tag, __y)); 190 } 191 192 template <typename _Tp1, typename _Tp2> 193 void construct(pair<_Tp1,_Tp2>* __p) 194 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 195 196 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 197 void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) 198 { this->construct(__p, piecewise_construct, 199 forward_as_tuple(std::forward<_Up>(__x)), 200 forward_as_tuple(std::forward<_Vp>(__y))); } 201 202 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 203 void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 204 { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), 205 forward_as_tuple(__pr.second)); } 206 207 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 208 void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) 209 { this->construct(__p, piecewise_construct, 210 forward_as_tuple(std::forward<_Up>(__pr.first)), 211 forward_as_tuple(std::forward<_Vp>(__pr.second))); } 212 213 template <typename _Up> 214 void destroy(_Up* __p) 215 { __p->~_Up(); } 216 217 // Return a default-constructed allocator (no allocator propagation) 218 polymorphic_allocator select_on_container_copy_construction() const 219 { return polymorphic_allocator(); } 220 221 memory_resource* resource() const 222 { return _M_resource; } 223 224 private: 225 template<typename _Tuple> 226 _Tuple&& 227 _M_construct_p(__uses_alloc0, _Tuple& __t) 228 { return std::move(__t); } 229 230 template<typename... _Args> 231 decltype(auto) 232 _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) 233 { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), 234 std::move(__t)); } 235 236 template<typename... _Args> 237 decltype(auto) 238 _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) 239 { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } 240 241 memory_resource* _M_resource; 242 }; 243 244 template <class _Tp1, class _Tp2> 245 bool operator==(const polymorphic_allocator<_Tp1>& __a, 246 const polymorphic_allocator<_Tp2>& __b) noexcept 247 { return *__a.resource() == *__b.resource(); } 248 249 template <class _Tp1, class _Tp2> 250 bool operator!=(const polymorphic_allocator<_Tp1>& __a, 251 const polymorphic_allocator<_Tp2>& __b) noexcept 252 { return !(__a == __b); } 253 254 // 8.7.1 __resource_adaptor_imp 255 template <typename _Alloc> 256 class __resource_adaptor_imp : public memory_resource 257 { 258 static_assert(is_same<char, 259 typename allocator_traits<_Alloc>::value_type>::value, 260 "Allocator's value_type is char"); 261 static_assert(is_same<char*, 262 typename allocator_traits<_Alloc>::pointer>::value, 263 "Allocator's pointer type is value_type*"); 264 static_assert(is_same<const char*, 265 typename allocator_traits<_Alloc>::const_pointer>::value, 266 "Allocator's const_pointer type is value_type const*"); 267 static_assert(is_same<void*, 268 typename allocator_traits<_Alloc>::void_pointer>::value, 269 "Allocator's void_pointer type is void*"); 270 static_assert(is_same<const void*, 271 typename allocator_traits<_Alloc>::const_void_pointer>::value, 272 "Allocator's const_void_pointer type is void const*"); 273 274 public: 275 using allocator_type = _Alloc; 276 277 __resource_adaptor_imp() = default; 278 __resource_adaptor_imp(const __resource_adaptor_imp&) = default; 279 __resource_adaptor_imp(__resource_adaptor_imp&&) = default; 280 281 explicit __resource_adaptor_imp(const _Alloc& __a2) 282 : _M_alloc(__a2) 283 { } 284 285 explicit __resource_adaptor_imp(_Alloc&& __a2) 286 : _M_alloc(std::move(__a2)) 287 { } 288 289 __resource_adaptor_imp& 290 operator=(const __resource_adaptor_imp&) = default; 291 292 allocator_type get_allocator() const noexcept { return _M_alloc; } 293 294 protected: 295 virtual void* 296 do_allocate(size_t __bytes, size_t __alignment) 297 { 298 using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 299 size_t __new_size = _S_aligned_size(__bytes, 300 _S_supported(__alignment) ? 301 __alignment : _S_max_align); 302 return _Aligned_alloc(_M_alloc).allocate(__new_size); 303 } 304 305 virtual void 306 do_deallocate(void* __p, size_t __bytes, size_t __alignment) 307 { 308 using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 309 size_t __new_size = _S_aligned_size(__bytes, 310 _S_supported(__alignment) ? 311 __alignment : _S_max_align); 312 using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer; 313 _Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p), 314 __new_size); 315 } 316 317 virtual bool 318 do_is_equal(const memory_resource& __other) const noexcept 319 { 320 auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other); 321 return __p ? (_M_alloc == __p->_M_alloc) : false; 322 } 323 324 private: 325 // Calculate Aligned Size 326 // Returns a size that is larger than or equal to __size and divisible 327 // by __alignment, where __alignment is required to be a power of 2. 328 static size_t 329 _S_aligned_size(size_t __size, size_t __alignment) 330 { return ((__size - 1)|(__alignment - 1)) + 1; } 331 332 // Determine whether alignment meets one of those preconditions: 333 // 1. Equal to Zero 334 // 2. Is power of two 335 static bool 336 _S_supported (size_t __x) 337 { return ((__x != 0) && !(__x & (__x - 1))); } 338 339 _Alloc _M_alloc; 340 }; 341 342 // Global memory resources 343 344 inline memory_resource* 345 new_delete_resource() noexcept 346 { 347 using type = resource_adaptor<std::allocator<char>>; 348 alignas(type) static unsigned char __buf[sizeof(type)]; 349 static type* __r = new(__buf) type; 350 return __r; 351 } 352 353 inline memory_resource* 354 null_memory_resource() noexcept 355 { 356 class type final : public memory_resource 357 { 358 void* 359 do_allocate(size_t, size_t) override 360 { std::__throw_bad_alloc(); } 361 362 void 363 do_deallocate(void*, size_t, size_t) noexcept override 364 { } 365 366 bool 367 do_is_equal(const memory_resource& __other) const noexcept override 368 { return this == &__other; } 369 }; 370 371 alignas(type) static unsigned char __buf[sizeof(type)]; 372 static type* __r = new(__buf) type; 373 return __r; 374 } 375 376 // The default memory resource 377 378 inline std::atomic<memory_resource*>& 379 __get_default_resource() 380 { 381 using type = atomic<memory_resource*>; 382 alignas(type) static unsigned char __buf[sizeof(type)]; 383 static type* __r = new(__buf) type(new_delete_resource()); 384 return *__r; 385 } 386 387 inline memory_resource* 388 get_default_resource() noexcept 389 { return __get_default_resource().load(); } 390 391 inline memory_resource* 392 set_default_resource(memory_resource* __r) noexcept 393 { 394 if (__r == nullptr) 395 __r = new_delete_resource(); 396 return __get_default_resource().exchange(__r); 397 } 398 399_GLIBCXX_END_NAMESPACE_VERSION 400} // namespace pmr 401} // namespace fundamentals_v2 402} // namespace experimental 403} // namespace std 404 405#endif 406