memory_resource 13 KB

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