allocate_unique.hpp 13 KB

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