allocate_unique.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. Copyright 2019-2021 Glen Joseph Fernandes
  3. (glenjofe@gmail.com)
  4. Distributed under the Boost Software License, Version 1.0.
  5. (http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #ifndef BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP
  8. #define BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP
  9. #include <boost/smart_ptr/detail/requires_cxx11.hpp>
  10. #include <boost/smart_ptr/detail/sp_noexcept.hpp>
  11. #include <boost/smart_ptr/detail/sp_nullptr_t.hpp>
  12. #include <boost/core/allocator_access.hpp>
  13. #include <boost/core/alloc_construct.hpp>
  14. #include <boost/core/empty_value.hpp>
  15. #include <boost/core/first_scalar.hpp>
  16. #include <boost/core/noinit_adaptor.hpp>
  17. #include <boost/core/pointer_traits.hpp>
  18. #include <boost/type_traits/enable_if.hpp>
  19. #include <boost/type_traits/extent.hpp>
  20. #include <boost/type_traits/is_array.hpp>
  21. #include <boost/type_traits/is_bounded_array.hpp>
  22. #include <boost/type_traits/is_unbounded_array.hpp>
  23. #include <boost/type_traits/remove_cv.hpp>
  24. #include <boost/type_traits/remove_extent.hpp>
  25. #include <boost/type_traits/type_identity.hpp>
  26. #include <boost/config.hpp>
  27. #include <memory>
  28. #include <utility>
  29. namespace boost {
  30. namespace detail {
  31. template<class T>
  32. struct sp_alloc_size {
  33. BOOST_STATIC_CONSTEXPR std::size_t value = 1;
  34. };
  35. template<class T>
  36. struct sp_alloc_size<T[]> {
  37. BOOST_STATIC_CONSTEXPR std::size_t value = sp_alloc_size<T>::value;
  38. };
  39. template<class T, std::size_t N>
  40. struct sp_alloc_size<T[N]> {
  41. BOOST_STATIC_CONSTEXPR std::size_t value = N * sp_alloc_size<T>::value;
  42. };
  43. template<class T>
  44. struct sp_alloc_result {
  45. typedef T type;
  46. };
  47. template<class T, std::size_t N>
  48. struct sp_alloc_result<T[N]> {
  49. typedef T type[];
  50. };
  51. template<class T>
  52. struct sp_alloc_value {
  53. typedef typename boost::remove_cv<typename
  54. boost::remove_extent<T>::type>::type type;
  55. };
  56. template<class T, class P>
  57. class sp_alloc_ptr {
  58. public:
  59. typedef T element_type;
  60. sp_alloc_ptr() BOOST_SP_NOEXCEPT
  61. : p_() { }
  62. #if defined(BOOST_MSVC) && BOOST_MSVC == 1600
  63. sp_alloc_ptr(T* p) BOOST_SP_NOEXCEPT
  64. : p_(const_cast<typename boost::remove_cv<T>::type*>(p)) { }
  65. #endif
  66. sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT
  67. : p_(p) { }
  68. #if !defined(BOOST_NO_CXX11_NULLPTR)
  69. sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
  70. : p_() { }
  71. #endif
  72. T& operator*() const {
  73. return *p_;
  74. }
  75. T* operator->() const BOOST_SP_NOEXCEPT {
  76. return boost::to_address(p_);
  77. }
  78. #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
  79. explicit operator bool() const BOOST_SP_NOEXCEPT {
  80. return !!p_;
  81. }
  82. #endif
  83. bool operator!() const BOOST_SP_NOEXCEPT {
  84. return !p_;
  85. }
  86. P ptr() const BOOST_SP_NOEXCEPT {
  87. return p_;
  88. }
  89. BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT {
  90. return 1;
  91. }
  92. #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
  93. static sp_alloc_ptr pointer_to(T& v) {
  94. return sp_alloc_ptr(1,
  95. std::pointer_traits<P>::pointer_to(const_cast<typename
  96. boost::remove_cv<T>::type&>(v)));
  97. }
  98. #endif
  99. private:
  100. P p_;
  101. };
  102. template<class T, class P>
  103. class sp_alloc_ptr<T[], P> {
  104. public:
  105. typedef T element_type;
  106. sp_alloc_ptr() BOOST_SP_NOEXCEPT
  107. : p_() { }
  108. sp_alloc_ptr(std::size_t n, P p) BOOST_SP_NOEXCEPT
  109. : p_(p)
  110. , n_(n) { }
  111. #if !defined(BOOST_NO_CXX11_NULLPTR)
  112. sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
  113. : p_() { }
  114. #endif
  115. T& operator[](std::size_t i) const {
  116. return p_[i];
  117. }
  118. #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
  119. explicit operator bool() const BOOST_SP_NOEXCEPT {
  120. return !!p_;
  121. }
  122. #endif
  123. bool operator!() const BOOST_SP_NOEXCEPT {
  124. return !p_;
  125. }
  126. P ptr() const BOOST_SP_NOEXCEPT {
  127. return p_;
  128. }
  129. std::size_t size() const BOOST_SP_NOEXCEPT {
  130. return n_;
  131. }
  132. #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
  133. static sp_alloc_ptr pointer_to(T& v) {
  134. return sp_alloc_ptr(n_,
  135. std::pointer_traits<P>::pointer_to(const_cast<typename
  136. boost::remove_cv<T>::type&>(v)));
  137. }
  138. #endif
  139. private:
  140. P p_;
  141. std::size_t n_;
  142. };
  143. template<class T, std::size_t N, class P>
  144. class sp_alloc_ptr<T[N], P> {
  145. public:
  146. typedef T element_type;
  147. sp_alloc_ptr() BOOST_SP_NOEXCEPT
  148. : p_() { }
  149. sp_alloc_ptr(std::size_t, P p) BOOST_SP_NOEXCEPT
  150. : p_(p) { }
  151. #if !defined(BOOST_NO_CXX11_NULLPTR)
  152. sp_alloc_ptr(detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
  153. : p_() { }
  154. #endif
  155. T& operator[](std::size_t i) const {
  156. return p_[i];
  157. }
  158. #if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
  159. explicit operator bool() const BOOST_SP_NOEXCEPT {
  160. return !!p_;
  161. }
  162. #endif
  163. bool operator!() const BOOST_SP_NOEXCEPT {
  164. return !p_;
  165. }
  166. P ptr() const BOOST_SP_NOEXCEPT {
  167. return p_;
  168. }
  169. BOOST_STATIC_CONSTEXPR std::size_t size() BOOST_SP_NOEXCEPT {
  170. return N;
  171. }
  172. #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
  173. static sp_alloc_ptr pointer_to(T& v) {
  174. return sp_alloc_ptr(N,
  175. std::pointer_traits<P>::pointer_to(const_cast<typename
  176. boost::remove_cv<T>::type&>(v)));
  177. }
  178. #endif
  179. private:
  180. P p_;
  181. };
  182. template<class T, class P>
  183. inline bool
  184. operator==(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
  185. {
  186. return lhs.ptr() == rhs.ptr();
  187. }
  188. template<class T, class P>
  189. inline bool
  190. operator!=(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
  191. {
  192. return !(lhs == rhs);
  193. }
  194. #if !defined(BOOST_NO_CXX11_NULLPTR)
  195. template<class T, class P>
  196. inline bool
  197. operator==(const sp_alloc_ptr<T, P>& lhs,
  198. detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
  199. {
  200. return !lhs.ptr();
  201. }
  202. template<class T, class P>
  203. inline bool
  204. operator==(detail::sp_nullptr_t,
  205. const sp_alloc_ptr<T, P>& rhs) BOOST_SP_NOEXCEPT
  206. {
  207. return !rhs.ptr();
  208. }
  209. template<class T, class P>
  210. inline bool
  211. operator!=(const sp_alloc_ptr<T, P>& lhs,
  212. detail::sp_nullptr_t) BOOST_SP_NOEXCEPT
  213. {
  214. return !!lhs.ptr();
  215. }
  216. template<class T, class P>
  217. inline bool
  218. operator!=(detail::sp_nullptr_t,
  219. const sp_alloc_ptr<T, P>& rhs) BOOST_SP_NOEXCEPT
  220. {
  221. return !!rhs.ptr();
  222. }
  223. #endif
  224. template<class A>
  225. inline void
  226. sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p, std::size_t,
  227. boost::false_type)
  228. {
  229. boost::alloc_destroy(a, boost::to_address(p));
  230. }
  231. template<class A>
  232. inline void
  233. sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p,
  234. std::size_t n, boost::true_type)
  235. {
  236. #if defined(BOOST_MSVC) && BOOST_MSVC < 1800
  237. if (!p) {
  238. return;
  239. }
  240. #endif
  241. boost::alloc_destroy_n(a, boost::first_scalar(boost::to_address(p)),
  242. n * sp_alloc_size<typename A::value_type>::value);
  243. }
  244. } /* detail */
  245. template<class T, class A>
  246. class alloc_deleter
  247. : empty_value<typename allocator_rebind<A,
  248. typename detail::sp_alloc_value<T>::type>::type> {
  249. typedef typename allocator_rebind<A,
  250. typename detail::sp_alloc_value<T>::type>::type allocator;
  251. typedef empty_value<allocator> base;
  252. public:
  253. typedef detail::sp_alloc_ptr<T,
  254. typename allocator_pointer<allocator>::type> pointer;
  255. explicit alloc_deleter(const allocator& a) BOOST_SP_NOEXCEPT
  256. : base(empty_init_t(), a) { }
  257. void operator()(pointer p) {
  258. detail::sp_alloc_clear(base::get(), p.ptr(), p.size(), is_array<T>());
  259. base::get().deallocate(p.ptr(), p.size());
  260. }
  261. };
  262. #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
  263. template<class T, class A>
  264. using alloc_noinit_deleter = alloc_deleter<T, noinit_adaptor<A> >;
  265. #endif
  266. namespace detail {
  267. template<class T, class A>
  268. class sp_alloc_make {
  269. public:
  270. typedef typename boost::allocator_rebind<A,
  271. typename sp_alloc_value<T>::type>::type allocator;
  272. private:
  273. typedef boost::alloc_deleter<T, A> deleter;
  274. public:
  275. typedef std::unique_ptr<typename sp_alloc_result<T>::type, deleter> type;
  276. sp_alloc_make(const A& a, std::size_t n)
  277. : a_(a)
  278. , n_(n)
  279. , p_(a_.allocate(n)) { }
  280. ~sp_alloc_make() {
  281. if (p_) {
  282. a_.deallocate(p_, n_);
  283. }
  284. }
  285. typename allocator::value_type* get() const BOOST_SP_NOEXCEPT {
  286. return boost::to_address(p_);
  287. }
  288. allocator& state() BOOST_SP_NOEXCEPT {
  289. return a_;
  290. }
  291. type release() BOOST_SP_NOEXCEPT {
  292. pointer p = p_;
  293. p_ = pointer();
  294. return type(typename deleter::pointer(n_, p), deleter(a_));
  295. }
  296. private:
  297. typedef typename boost::allocator_pointer<allocator>::type pointer;
  298. allocator a_;
  299. std::size_t n_;
  300. pointer p_;
  301. };
  302. } /* detail */
  303. template<class T, class A>
  304. inline typename enable_if_<!is_array<T>::value,
  305. std::unique_ptr<T, alloc_deleter<T, A> > >::type
  306. allocate_unique(const A& alloc)
  307. {
  308. detail::sp_alloc_make<T, A> c(alloc, 1);
  309. boost::alloc_construct(c.state(), c.get());
  310. return c.release();
  311. }
  312. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  313. template<class T, class A, class... Args>
  314. inline typename enable_if_<!is_array<T>::value,
  315. std::unique_ptr<T, alloc_deleter<T, A> > >::type
  316. allocate_unique(const A& alloc, Args&&... args)
  317. {
  318. detail::sp_alloc_make<T, A> c(alloc, 1);
  319. boost::alloc_construct(c.state(), c.get(), std::forward<Args>(args)...);
  320. return c.release();
  321. }
  322. #endif
  323. template<class T, class A>
  324. inline typename enable_if_<!is_array<T>::value,
  325. std::unique_ptr<T, alloc_deleter<T, A> > >::type
  326. allocate_unique(const A& alloc, typename type_identity<T>::type&& value)
  327. {
  328. detail::sp_alloc_make<T, A> c(alloc, 1);
  329. boost::alloc_construct(c.state(), c.get(), std::move(value));
  330. return c.release();
  331. }
  332. template<class T, class A>
  333. inline typename enable_if_<!is_array<T>::value,
  334. std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
  335. allocate_unique_noinit(const A& alloc)
  336. {
  337. return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
  338. }
  339. template<class T, class A>
  340. inline typename enable_if_<is_unbounded_array<T>::value,
  341. std::unique_ptr<T, alloc_deleter<T, A> > >::type
  342. allocate_unique(const A& alloc, std::size_t size)
  343. {
  344. detail::sp_alloc_make<T, A> c(alloc, size);
  345. boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
  346. size * detail::sp_alloc_size<T>::value);
  347. return c.release();
  348. }
  349. template<class T, class A>
  350. inline typename enable_if_<is_bounded_array<T>::value,
  351. std::unique_ptr<typename detail::sp_alloc_result<T>::type,
  352. alloc_deleter<T, A> > >::type
  353. allocate_unique(const A& alloc)
  354. {
  355. detail::sp_alloc_make<T, A> c(alloc, extent<T>::value);
  356. boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
  357. detail::sp_alloc_size<T>::value);
  358. return c.release();
  359. }
  360. template<class T, class A>
  361. inline typename enable_if_<is_unbounded_array<T>::value,
  362. std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
  363. allocate_unique_noinit(const A& alloc, std::size_t size)
  364. {
  365. return boost::allocate_unique<T, noinit_adaptor<A> >(alloc, size);
  366. }
  367. template<class T, class A>
  368. inline typename enable_if_<is_bounded_array<T>::value,
  369. std::unique_ptr<typename detail::sp_alloc_result<T>::type,
  370. alloc_deleter<T, noinit_adaptor<A> > > >::type
  371. allocate_unique_noinit(const A& alloc)
  372. {
  373. return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
  374. }
  375. template<class T, class A>
  376. inline typename enable_if_<is_unbounded_array<T>::value,
  377. std::unique_ptr<T, alloc_deleter<T, A> > >::type
  378. allocate_unique(const A& alloc, std::size_t size,
  379. const typename remove_extent<T>::type& value)
  380. {
  381. detail::sp_alloc_make<T, A> c(alloc, size);
  382. boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
  383. size * detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
  384. detail::sp_alloc_size<typename remove_extent<T>::type>::value);
  385. return c.release();
  386. }
  387. template<class T, class A>
  388. inline typename enable_if_<is_bounded_array<T>::value,
  389. std::unique_ptr<typename detail::sp_alloc_result<T>::type,
  390. alloc_deleter<T, A> > >::type
  391. allocate_unique(const A& alloc,
  392. const typename remove_extent<T>::type& value)
  393. {
  394. detail::sp_alloc_make<T, A> c(alloc, extent<T>::value);
  395. boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
  396. detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
  397. detail::sp_alloc_size<typename remove_extent<T>::type>::value);
  398. return c.release();
  399. }
  400. template<class T, class U, class A>
  401. inline typename allocator_pointer<typename allocator_rebind<A,
  402. typename detail::sp_alloc_value<T>::type>::type>::type
  403. get_allocator_pointer(const std::unique_ptr<T,
  404. alloc_deleter<U, A> >& p) BOOST_NOEXCEPT
  405. {
  406. return p.get().ptr();
  407. }
  408. } /* boost */
  409. #endif