]>
Commit | Line | Data |
---|---|---|
bfeffbd1 FY |
1 | // <experimental/memory_resource> -*- C++ -*- |
2 | ||
a5544970 | 3 | // Copyright (C) 2015-2019 Free Software Foundation, Inc. |
bfeffbd1 FY |
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 | ||
7a4be380 JW |
32 | #include <memory> // align, uses_allocator, __uses_alloc |
33 | #include <experimental/utility> // pair, experimental::erased_type | |
34 | #include <atomic> // atomic | |
16d0ab7f JW |
35 | #include <new> // placement new |
36 | #include <cstddef> // max_align_t | |
7956c508 | 37 | #include <ext/new_allocator.h> |
7a4be380 | 38 | #include <debug/assertions.h> |
bfeffbd1 | 39 | |
2d6c8eea JW |
40 | namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) |
41 | { | |
42 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
43 | template<typename _Tp> class malloc_allocator; | |
44 | _GLIBCXX_END_NAMESPACE_VERSION | |
45 | } // namespace __gnu_cxx | |
46 | ||
bfeffbd1 | 47 | namespace std { |
4a15d842 FD |
48 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
49 | ||
bfeffbd1 FY |
50 | namespace experimental { |
51 | inline namespace fundamentals_v2 { | |
52 | namespace pmr { | |
80144045 JW |
53 | #define __cpp_lib_experimental_memory_resources 201402L |
54 | ||
7a4be380 JW |
55 | // Standard memory resources |
56 | ||
57 | // 8.5 Class memory_resource | |
bfeffbd1 FY |
58 | class memory_resource; |
59 | ||
7a4be380 JW |
60 | // 8.6 Class template polymorphic_allocator |
61 | template<typename _Tp> | |
bfeffbd1 FY |
62 | class polymorphic_allocator; |
63 | ||
7a4be380 | 64 | template<typename _Alloc, typename _Resource = memory_resource> |
bfeffbd1 FY |
65 | class __resource_adaptor_imp; |
66 | ||
7a4be380 JW |
67 | // 8.7 Alias template resource_adaptor |
68 | template<typename _Alloc> | |
bfeffbd1 FY |
69 | using resource_adaptor = __resource_adaptor_imp< |
70 | typename allocator_traits<_Alloc>::template rebind_alloc<char>>; | |
71 | ||
7a4be380 | 72 | // 8.8 Global memory resources |
bfeffbd1 FY |
73 | memory_resource* new_delete_resource() noexcept; |
74 | memory_resource* null_memory_resource() noexcept; | |
bfeffbd1 FY |
75 | memory_resource* get_default_resource() noexcept; |
76 | memory_resource* set_default_resource(memory_resource* __r) noexcept; | |
77 | ||
7a4be380 | 78 | // TODO 8.9 Pool resource classes |
bfeffbd1 | 79 | |
bfeffbd1 FY |
80 | class memory_resource |
81 | { | |
82 | static constexpr size_t _S_max_align = alignof(max_align_t); | |
83 | ||
84 | public: | |
7a4be380 JW |
85 | memory_resource() = default; |
86 | memory_resource(const memory_resource&) = default; | |
87 | virtual ~memory_resource() = default; | |
88 | ||
89 | memory_resource& operator=(const memory_resource&) = default; | |
bfeffbd1 | 90 | |
d715f554 | 91 | _GLIBCXX_NODISCARD void* |
bfeffbd1 FY |
92 | allocate(size_t __bytes, size_t __alignment = _S_max_align) |
93 | { return do_allocate(__bytes, __alignment); } | |
94 | ||
95 | void | |
96 | deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) | |
97 | { return do_deallocate(__p, __bytes, __alignment); } | |
98 | ||
99 | bool | |
100 | is_equal(const memory_resource& __other) const noexcept | |
101 | { return do_is_equal(__other); } | |
102 | ||
103 | protected: | |
104 | virtual void* | |
105 | do_allocate(size_t __bytes, size_t __alignment) = 0; | |
106 | ||
107 | virtual void | |
108 | do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; | |
109 | ||
110 | virtual bool | |
111 | do_is_equal(const memory_resource& __other) const noexcept = 0; | |
112 | }; | |
113 | ||
114 | inline bool | |
7a4be380 | 115 | operator==(const memory_resource& __a, const memory_resource& __b) noexcept |
bfeffbd1 FY |
116 | { return &__a == &__b || __a.is_equal(__b); } |
117 | ||
118 | inline bool | |
7a4be380 | 119 | operator!=(const memory_resource& __a, const memory_resource& __b) noexcept |
bfeffbd1 FY |
120 | { return !(__a == __b); } |
121 | ||
122 | ||
7a4be380 | 123 | template<typename _Tp> |
bfeffbd1 FY |
124 | class polymorphic_allocator |
125 | { | |
bfeffbd1 FY |
126 | public: |
127 | using value_type = _Tp; | |
128 | ||
129 | polymorphic_allocator() noexcept | |
130 | : _M_resource(get_default_resource()) | |
131 | { } | |
132 | ||
133 | polymorphic_allocator(memory_resource* __r) | |
134 | : _M_resource(__r) | |
135 | { _GLIBCXX_DEBUG_ASSERT(__r); } | |
136 | ||
137 | polymorphic_allocator(const polymorphic_allocator& __other) = default; | |
138 | ||
139 | template <typename _Up> | |
140 | polymorphic_allocator(const polymorphic_allocator<_Up>& | |
141 | __other) noexcept | |
142 | : _M_resource(__other.resource()) | |
143 | { } | |
144 | ||
145 | polymorphic_allocator& | |
146 | operator=(const polymorphic_allocator& __rhs) = default; | |
147 | ||
d715f554 | 148 | _GLIBCXX_NODISCARD _Tp* allocate(size_t __n) |
bfeffbd1 FY |
149 | { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), |
150 | alignof(_Tp))); } | |
151 | ||
7a4be380 JW |
152 | void |
153 | deallocate(_Tp* __p, size_t __n) | |
bfeffbd1 FY |
154 | { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } |
155 | ||
156 | template <typename _Tp1, typename... _Args> //used here | |
7a4be380 JW |
157 | void |
158 | construct(_Tp1* __p, _Args&&... __args) | |
bfeffbd1 | 159 | { |
b479fbad JW |
160 | std::__uses_allocator_construct(this->resource(), __p, |
161 | std::forward<_Args>(__args)...); | |
bfeffbd1 FY |
162 | } |
163 | ||
164 | // Specializations for pair using piecewise construction | |
165 | template <typename _Tp1, typename _Tp2, | |
166 | typename... _Args1, typename... _Args2> | |
7a4be380 JW |
167 | void |
168 | construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, | |
169 | tuple<_Args1...> __x, tuple<_Args2...> __y) | |
bfeffbd1 | 170 | { |
318c48e3 | 171 | memory_resource* const __resource = this->resource(); |
bfeffbd1 | 172 | auto __x_use_tag = |
b479fbad | 173 | std::__use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); |
bfeffbd1 | 174 | auto __y_use_tag = |
b479fbad | 175 | std::__use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); |
bfeffbd1 FY |
176 | |
177 | ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, | |
178 | _M_construct_p(__x_use_tag, __x), | |
179 | _M_construct_p(__y_use_tag, __y)); | |
180 | } | |
181 | ||
182 | template <typename _Tp1, typename _Tp2> | |
7a4be380 JW |
183 | void |
184 | construct(pair<_Tp1,_Tp2>* __p) | |
bfeffbd1 FY |
185 | { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } |
186 | ||
187 | template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
7a4be380 JW |
188 | void |
189 | construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) | |
190 | { | |
191 | this->construct(__p, piecewise_construct, | |
bfeffbd1 | 192 | forward_as_tuple(std::forward<_Up>(__x)), |
7a4be380 JW |
193 | forward_as_tuple(std::forward<_Vp>(__y))); |
194 | } | |
bfeffbd1 FY |
195 | |
196 | template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
7a4be380 JW |
197 | void |
198 | construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) | |
199 | { | |
200 | this->construct(__p, piecewise_construct, | |
201 | forward_as_tuple(__pr.first), | |
202 | forward_as_tuple(__pr.second)); | |
203 | } | |
bfeffbd1 FY |
204 | |
205 | template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> | |
7a4be380 JW |
206 | void |
207 | construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) | |
208 | { | |
209 | this->construct(__p, piecewise_construct, | |
bfeffbd1 | 210 | forward_as_tuple(std::forward<_Up>(__pr.first)), |
7a4be380 JW |
211 | forward_as_tuple(std::forward<_Vp>(__pr.second))); |
212 | } | |
bfeffbd1 FY |
213 | |
214 | template <typename _Up> | |
7a4be380 JW |
215 | void |
216 | destroy(_Up* __p) | |
bfeffbd1 FY |
217 | { __p->~_Up(); } |
218 | ||
219 | // Return a default-constructed allocator (no allocator propagation) | |
7a4be380 JW |
220 | polymorphic_allocator |
221 | select_on_container_copy_construction() const | |
bfeffbd1 FY |
222 | { return polymorphic_allocator(); } |
223 | ||
7a4be380 | 224 | memory_resource* resource() const { return _M_resource; } |
bfeffbd1 FY |
225 | |
226 | private: | |
b479fbad JW |
227 | using __uses_alloc1_ = __uses_alloc1<memory_resource*>; |
228 | using __uses_alloc2_ = __uses_alloc2<memory_resource*>; | |
229 | ||
bfeffbd1 FY |
230 | template<typename _Tuple> |
231 | _Tuple&& | |
232 | _M_construct_p(__uses_alloc0, _Tuple& __t) | |
233 | { return std::move(__t); } | |
234 | ||
235 | template<typename... _Args> | |
236 | decltype(auto) | |
237 | _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) | |
238 | { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), | |
239 | std::move(__t)); } | |
240 | ||
241 | template<typename... _Args> | |
242 | decltype(auto) | |
243 | _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) | |
244 | { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } | |
245 | ||
246 | memory_resource* _M_resource; | |
247 | }; | |
248 | ||
249 | template <class _Tp1, class _Tp2> | |
7a4be380 JW |
250 | bool |
251 | operator==(const polymorphic_allocator<_Tp1>& __a, | |
252 | const polymorphic_allocator<_Tp2>& __b) noexcept | |
bfeffbd1 FY |
253 | { return *__a.resource() == *__b.resource(); } |
254 | ||
255 | template <class _Tp1, class _Tp2> | |
7a4be380 JW |
256 | bool |
257 | operator!=(const polymorphic_allocator<_Tp1>& __a, | |
258 | const polymorphic_allocator<_Tp2>& __b) noexcept | |
bfeffbd1 FY |
259 | { return !(__a == __b); } |
260 | ||
7a4be380 | 261 | |
7956c508 JW |
262 | class __resource_adaptor_common |
263 | { | |
7a4be380 | 264 | template<typename, typename> friend class __resource_adaptor_imp; |
7956c508 JW |
265 | |
266 | struct _AlignMgr | |
267 | { | |
268 | _AlignMgr(size_t __nbytes, size_t __align) | |
269 | : _M_nbytes(__nbytes), _M_align(__align) | |
270 | { } | |
271 | ||
272 | // Total size that needs to be allocated. | |
273 | size_t | |
274 | _M_alloc_size() const { return _M_buf_size() + _M_token_size(); } | |
275 | ||
276 | void* | |
277 | _M_adjust(void* __ptr) const | |
278 | { | |
279 | const auto __orig_ptr = static_cast<char*>(__ptr); | |
280 | size_t __space = _M_buf_size(); | |
281 | // Align the pointer within the buffer: | |
282 | std::align(_M_align, _M_nbytes, __ptr, __space); | |
283 | const auto __aligned_ptr = static_cast<char*>(__ptr); | |
284 | const auto __token_size = _M_token_size(); | |
285 | // Store token immediately after the aligned block: | |
286 | char* const __end = __aligned_ptr + _M_nbytes; | |
287 | if (__token_size == 1) | |
288 | _S_write<unsigned char>(__end, __aligned_ptr - __orig_ptr); | |
289 | else if (__token_size == sizeof(short)) | |
290 | _S_write<unsigned short>(__end, __aligned_ptr - __orig_ptr); | |
291 | else if (__token_size == sizeof(int) && sizeof(int) < sizeof(char*)) | |
292 | _S_write<unsigned int>(__end, __aligned_ptr - __orig_ptr); | |
293 | else // (__token_size == sizeof(char*)) | |
294 | // Just store the original pointer: | |
295 | _S_write<char*>(__end, __orig_ptr); | |
296 | return __aligned_ptr; | |
297 | } | |
298 | ||
299 | char* | |
300 | _M_unadjust(char* __ptr) const | |
301 | { | |
302 | const char* const __end = __ptr + _M_nbytes; | |
303 | char* __orig_ptr; | |
304 | const auto __token_size = _M_token_size(); | |
305 | // Read the token and restore the original pointer: | |
306 | if (__token_size == 1) | |
307 | __orig_ptr = __ptr - _S_read<unsigned char>(__end); | |
308 | else if (__token_size == sizeof(short)) | |
309 | __orig_ptr = __ptr - _S_read<unsigned short>(__end); | |
310 | else if (__token_size == sizeof(int) | |
311 | && sizeof(int) < sizeof(char*)) | |
312 | __orig_ptr = __ptr - _S_read<unsigned int>(__end); | |
313 | else // (__token_size == sizeof(char*)) | |
314 | __orig_ptr = _S_read<char*>(__end); | |
2d6c8eea JW |
315 | // The adjustment is always less than the requested alignment, |
316 | // so if that isn't true now then either the wrong size was passed | |
317 | // to deallocate or the token was overwritten by a buffer overflow: | |
318 | __glibcxx_assert(static_cast<size_t>(__ptr - __orig_ptr) < _M_align); | |
7956c508 JW |
319 | return __orig_ptr; |
320 | } | |
321 | ||
322 | private: | |
323 | size_t _M_nbytes; | |
324 | size_t _M_align; | |
325 | ||
326 | // Number of bytes needed to fit block of given size and alignment. | |
327 | size_t | |
328 | _M_buf_size() const { return _M_nbytes + _M_align - 1; } | |
329 | ||
330 | // Number of additional bytes needed to write the token. | |
331 | int | |
332 | _M_token_size() const | |
333 | { | |
334 | if (_M_align <= (1ul << __CHAR_BIT__)) | |
335 | return 1; | |
336 | if (_M_align <= (1ul << (sizeof(short) * __CHAR_BIT__))) | |
337 | return sizeof(short); | |
0b4bc9a1 | 338 | if (_M_align <= (1ull << (sizeof(int) * __CHAR_BIT__))) |
7956c508 JW |
339 | return sizeof(int); |
340 | return sizeof(char*); | |
341 | } | |
342 | ||
343 | template<typename _Tp> | |
344 | static void | |
345 | _S_write(void* __to, _Tp __val) | |
346 | { __builtin_memcpy(__to, &__val, sizeof(_Tp)); } | |
347 | ||
348 | template<typename _Tp> | |
349 | static _Tp | |
350 | _S_read(const void* __from) | |
351 | { | |
352 | _Tp __val; | |
353 | __builtin_memcpy(&__val, __from, sizeof(_Tp)); | |
354 | return __val; | |
355 | } | |
356 | }; | |
2d6c8eea JW |
357 | |
358 | template<typename _Alloc> | |
359 | struct __guaranteed_alignment : std::integral_constant<size_t, 1> { }; | |
360 | ||
361 | template<typename _Tp> | |
362 | struct __guaranteed_alignment<__gnu_cxx::new_allocator<_Tp>> | |
363 | : std::alignment_of<std::max_align_t>::type { }; | |
364 | ||
365 | template<typename _Tp> | |
366 | struct __guaranteed_alignment<__gnu_cxx::malloc_allocator<_Tp>> | |
367 | : std::alignment_of<std::max_align_t>::type { }; | |
368 | ||
369 | #if _GLIBCXX_USE_ALLOCATOR_NEW | |
370 | template<typename _Tp> | |
371 | struct __guaranteed_alignment<std::allocator<_Tp>> | |
372 | : std::alignment_of<std::max_align_t>::type { }; | |
373 | #endif | |
7956c508 JW |
374 | }; |
375 | ||
bfeffbd1 | 376 | // 8.7.1 __resource_adaptor_imp |
7a4be380 | 377 | template<typename _Alloc, typename _Resource> |
7956c508 | 378 | class __resource_adaptor_imp |
7a4be380 | 379 | : public _Resource, private __resource_adaptor_common |
bfeffbd1 | 380 | { |
7a4be380 JW |
381 | using memory_resource = _Resource; |
382 | ||
e70359b3 JW |
383 | static_assert(is_same<char, |
384 | typename allocator_traits<_Alloc>::value_type>::value, | |
385 | "Allocator's value_type is char"); | |
386 | static_assert(is_same<char*, | |
387 | typename allocator_traits<_Alloc>::pointer>::value, | |
388 | "Allocator's pointer type is value_type*"); | |
389 | static_assert(is_same<const char*, | |
390 | typename allocator_traits<_Alloc>::const_pointer>::value, | |
391 | "Allocator's const_pointer type is value_type const*"); | |
392 | static_assert(is_same<void*, | |
393 | typename allocator_traits<_Alloc>::void_pointer>::value, | |
394 | "Allocator's void_pointer type is void*"); | |
395 | static_assert(is_same<const void*, | |
396 | typename allocator_traits<_Alloc>::const_void_pointer>::value, | |
397 | "Allocator's const_void_pointer type is void const*"); | |
398 | ||
bfeffbd1 FY |
399 | public: |
400 | using allocator_type = _Alloc; | |
401 | ||
402 | __resource_adaptor_imp() = default; | |
403 | __resource_adaptor_imp(const __resource_adaptor_imp&) = default; | |
404 | __resource_adaptor_imp(__resource_adaptor_imp&&) = default; | |
405 | ||
406 | explicit __resource_adaptor_imp(const _Alloc& __a2) | |
407 | : _M_alloc(__a2) | |
408 | { } | |
409 | ||
410 | explicit __resource_adaptor_imp(_Alloc&& __a2) | |
411 | : _M_alloc(std::move(__a2)) | |
412 | { } | |
413 | ||
414 | __resource_adaptor_imp& | |
415 | operator=(const __resource_adaptor_imp&) = default; | |
416 | ||
e70359b3 | 417 | allocator_type get_allocator() const noexcept { return _M_alloc; } |
bfeffbd1 FY |
418 | |
419 | protected: | |
420 | virtual void* | |
7956c508 | 421 | do_allocate(size_t __bytes, size_t __alignment) override |
bfeffbd1 | 422 | { |
2d6c8eea | 423 | if (__alignment <= __guaranteed_alignment<_Alloc>::value) |
49cb790a JW |
424 | { |
425 | if (__bytes < __alignment) | |
426 | __bytes = __alignment; | |
427 | return _M_alloc.allocate(__bytes); | |
428 | } | |
429 | ||
7956c508 JW |
430 | |
431 | const _AlignMgr __mgr(__bytes, __alignment); | |
432 | // Assume _M_alloc returns 1-byte aligned memory, so allocate enough | |
433 | // space to fit a block of the right size and alignment, plus some | |
434 | // extra bytes to store a token for retrieving the original pointer. | |
435 | return __mgr._M_adjust(_M_alloc.allocate(__mgr._M_alloc_size())); | |
bfeffbd1 FY |
436 | } |
437 | ||
438 | virtual void | |
7956c508 JW |
439 | do_deallocate(void* __p, size_t __bytes, size_t __alignment) noexcept |
440 | override | |
bfeffbd1 | 441 | { |
7956c508 | 442 | auto __ptr = static_cast<char*>(__p); |
2d6c8eea | 443 | if (__alignment <= __guaranteed_alignment<_Alloc>::value) |
e9df6a8f | 444 | { |
49cb790a JW |
445 | if (__bytes < __alignment) |
446 | __bytes = __alignment; | |
e9df6a8f JW |
447 | _M_alloc.deallocate(__ptr, __bytes); |
448 | return; | |
449 | } | |
7956c508 JW |
450 | |
451 | const _AlignMgr __mgr(__bytes, __alignment); | |
452 | // Use the stored token to retrieve the original pointer to deallocate. | |
453 | _M_alloc.deallocate(__mgr._M_unadjust(__ptr), __mgr._M_alloc_size()); | |
bfeffbd1 FY |
454 | } |
455 | ||
456 | virtual bool | |
7956c508 | 457 | do_is_equal(const memory_resource& __other) const noexcept override |
bfeffbd1 | 458 | { |
7956c508 JW |
459 | if (auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other)) |
460 | return _M_alloc == __p->_M_alloc; | |
461 | return false; | |
bfeffbd1 FY |
462 | } |
463 | ||
464 | private: | |
7956c508 | 465 | _Alloc _M_alloc{}; |
bfeffbd1 FY |
466 | }; |
467 | ||
468 | // Global memory resources | |
bfeffbd1 FY |
469 | |
470 | inline memory_resource* | |
471 | new_delete_resource() noexcept | |
472 | { | |
7956c508 | 473 | using type = resource_adaptor<__gnu_cxx::new_allocator<char>>; |
e70359b3 JW |
474 | alignas(type) static unsigned char __buf[sizeof(type)]; |
475 | static type* __r = new(__buf) type; | |
476 | return __r; | |
bfeffbd1 FY |
477 | } |
478 | ||
e70359b3 JW |
479 | inline memory_resource* |
480 | null_memory_resource() noexcept | |
481 | { | |
482 | class type final : public memory_resource | |
bfeffbd1 | 483 | { |
bfeffbd1 | 484 | void* |
e70359b3 | 485 | do_allocate(size_t, size_t) override |
bfeffbd1 FY |
486 | { std::__throw_bad_alloc(); } |
487 | ||
488 | void | |
e70359b3 | 489 | do_deallocate(void*, size_t, size_t) noexcept override |
bfeffbd1 FY |
490 | { } |
491 | ||
492 | bool | |
e70359b3 | 493 | do_is_equal(const memory_resource& __other) const noexcept override |
d9cb3e75 | 494 | { return this == &__other; } |
bfeffbd1 FY |
495 | }; |
496 | ||
e70359b3 JW |
497 | alignas(type) static unsigned char __buf[sizeof(type)]; |
498 | static type* __r = new(__buf) type; | |
499 | return __r; | |
bfeffbd1 FY |
500 | } |
501 | ||
502 | // The default memory resource | |
0568ade6 JW |
503 | |
504 | inline std::atomic<memory_resource*>& | |
505 | __get_default_resource() | |
506 | { | |
507 | using type = atomic<memory_resource*>; | |
508 | alignas(type) static unsigned char __buf[sizeof(type)]; | |
509 | static type* __r = new(__buf) type(new_delete_resource()); | |
510 | return *__r; | |
511 | } | |
512 | ||
bfeffbd1 FY |
513 | inline memory_resource* |
514 | get_default_resource() noexcept | |
515 | { return __get_default_resource().load(); } | |
516 | ||
517 | inline memory_resource* | |
518 | set_default_resource(memory_resource* __r) noexcept | |
519 | { | |
520 | if (__r == nullptr) | |
521 | __r = new_delete_resource(); | |
522 | return __get_default_resource().exchange(__r); | |
523 | } | |
7a4be380 | 524 | |
bfeffbd1 FY |
525 | } // namespace pmr |
526 | } // namespace fundamentals_v2 | |
527 | } // namespace experimental | |
4a15d842 FD |
528 | |
529 | _GLIBCXX_END_NAMESPACE_VERSION | |
bfeffbd1 | 530 | } // namespace std |
7a4be380 | 531 | #endif // _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE |