allocate_unique.hpp 11 KB

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