memory_resource 16 KB

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