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