allocate_unique.hpp 12 KB

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