allocate_shared_array.hpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. Copyright 2012-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_SHARED_ARRAY_HPP
  8. #define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
  9. #include <boost/core/alloc_construct.hpp>
  10. #include <boost/core/first_scalar.hpp>
  11. #include <boost/smart_ptr/shared_ptr.hpp>
  12. #include <boost/type_traits/alignment_of.hpp>
  13. #include <boost/type_traits/enable_if.hpp>
  14. #include <boost/type_traits/extent.hpp>
  15. #include <boost/type_traits/is_bounded_array.hpp>
  16. #include <boost/type_traits/is_unbounded_array.hpp>
  17. #include <boost/type_traits/remove_cv.hpp>
  18. #include <boost/type_traits/remove_extent.hpp>
  19. #include <boost/type_traits/type_with_alignment.hpp>
  20. namespace boost {
  21. namespace detail {
  22. template<class T>
  23. struct sp_array_element {
  24. typedef typename boost::remove_cv<typename
  25. boost::remove_extent<T>::type>::type type;
  26. };
  27. template<class T>
  28. struct sp_array_count {
  29. enum {
  30. value = 1
  31. };
  32. };
  33. template<class T, std::size_t N>
  34. struct sp_array_count<T[N]> {
  35. enum {
  36. value = N * sp_array_count<T>::value
  37. };
  38. };
  39. template<std::size_t N, std::size_t M>
  40. struct sp_max_size {
  41. enum {
  42. value = N < M ? M : N
  43. };
  44. };
  45. template<std::size_t N, std::size_t M>
  46. struct sp_align_up {
  47. enum {
  48. value = (N + M - 1) & ~(M - 1)
  49. };
  50. };
  51. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  52. template<class A, class T>
  53. struct sp_bind_allocator {
  54. typedef typename std::allocator_traits<A>::template rebind_alloc<T> type;
  55. };
  56. #else
  57. template<class A, class T>
  58. struct sp_bind_allocator {
  59. typedef typename A::template rebind<T>::other type;
  60. };
  61. #endif
  62. template<class T>
  63. BOOST_CONSTEXPR inline std::size_t
  64. sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
  65. {
  66. return (size + sizeof(T) - 1) / sizeof(T);
  67. }
  68. template<class A>
  69. class sp_array_state {
  70. public:
  71. typedef A type;
  72. template<class U>
  73. sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT
  74. : allocator_(_allocator),
  75. size_(_size) { }
  76. A& allocator() BOOST_SP_NOEXCEPT {
  77. return allocator_;
  78. }
  79. std::size_t size() const BOOST_SP_NOEXCEPT {
  80. return size_;
  81. }
  82. private:
  83. A allocator_;
  84. std::size_t size_;
  85. };
  86. template<class A, std::size_t N>
  87. class sp_size_array_state {
  88. public:
  89. typedef A type;
  90. template<class U>
  91. sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT
  92. : allocator_(_allocator) { }
  93. A& allocator() BOOST_SP_NOEXCEPT {
  94. return allocator_;
  95. }
  96. BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
  97. return N;
  98. }
  99. private:
  100. A allocator_;
  101. };
  102. template<class T, class U>
  103. struct sp_array_alignment {
  104. enum {
  105. value = sp_max_size<boost::alignment_of<T>::value,
  106. boost::alignment_of<U>::value>::value
  107. };
  108. };
  109. template<class T, class U>
  110. struct sp_array_offset {
  111. enum {
  112. value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
  113. };
  114. };
  115. template<class U, class T>
  116. inline U*
  117. sp_array_start(T* base) BOOST_SP_NOEXCEPT
  118. {
  119. enum {
  120. size = sp_array_offset<T, U>::value
  121. };
  122. return reinterpret_cast<U*>(reinterpret_cast<char*>(base) + size);
  123. }
  124. template<class A, class T>
  125. class sp_array_creator {
  126. typedef typename A::value_type element;
  127. enum {
  128. offset = sp_array_offset<T, element>::value
  129. };
  130. typedef typename boost::type_with_alignment<sp_array_alignment<T,
  131. element>::value>::type type;
  132. public:
  133. template<class U>
  134. sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
  135. : other_(other),
  136. size_(sp_objects<type>(offset + sizeof(element) * size)) { }
  137. T* create() {
  138. return reinterpret_cast<T*>(other_.allocate(size_));
  139. }
  140. void destroy(T* base) {
  141. other_.deallocate(reinterpret_cast<type*>(base), size_);
  142. }
  143. private:
  144. typename sp_bind_allocator<A, type>::type other_;
  145. std::size_t size_;
  146. };
  147. template<class T>
  148. class BOOST_SYMBOL_VISIBLE sp_array_base
  149. : public sp_counted_base {
  150. typedef typename T::type allocator;
  151. public:
  152. typedef typename allocator::value_type type;
  153. template<class A>
  154. sp_array_base(const A& other, type* start, std::size_t size)
  155. : state_(other, size) {
  156. boost::alloc_construct_n(state_.allocator(),
  157. boost::first_scalar(start),
  158. state_.size() * sp_array_count<type>::value);
  159. }
  160. template<class A, class U>
  161. sp_array_base(const A& other, type* start, std::size_t size, const U& list)
  162. : state_(other, size) {
  163. enum {
  164. count = sp_array_count<type>::value
  165. };
  166. boost::alloc_construct_n(state_.allocator(),
  167. boost::first_scalar(start), state_.size() * count,
  168. boost::first_scalar(&list), count);
  169. }
  170. T& state() BOOST_SP_NOEXCEPT {
  171. return state_;
  172. }
  173. virtual void dispose() BOOST_SP_NOEXCEPT {
  174. boost::alloc_destroy_n(state_.allocator(),
  175. boost::first_scalar(sp_array_start<type>(this)),
  176. state_.size() * sp_array_count<type>::value);
  177. }
  178. virtual void destroy() BOOST_SP_NOEXCEPT {
  179. sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
  180. state_.size());
  181. this->~sp_array_base();
  182. other.destroy(this);
  183. }
  184. virtual void* get_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT {
  185. return 0;
  186. }
  187. virtual void* get_local_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT {
  188. return 0;
  189. }
  190. virtual void* get_untyped_deleter() BOOST_SP_NOEXCEPT {
  191. return 0;
  192. }
  193. private:
  194. T state_;
  195. };
  196. template<class A, class T>
  197. struct sp_array_result {
  198. public:
  199. template<class U>
  200. sp_array_result(const U& other, std::size_t size)
  201. : creator_(other, size),
  202. result_(creator_.create()) { }
  203. ~sp_array_result() {
  204. if (result_) {
  205. creator_.destroy(result_);
  206. }
  207. }
  208. T* get() const BOOST_SP_NOEXCEPT {
  209. return result_;
  210. }
  211. void release() BOOST_SP_NOEXCEPT {
  212. result_ = 0;
  213. }
  214. private:
  215. sp_array_result(const sp_array_result&);
  216. sp_array_result& operator=(const sp_array_result&);
  217. sp_array_creator<A, T> creator_;
  218. T* result_;
  219. };
  220. } /* detail */
  221. template<class T, class A>
  222. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  223. allocate_shared(const A& allocator, std::size_t count)
  224. {
  225. typedef typename detail::sp_array_element<T>::type element;
  226. typedef typename detail::sp_bind_allocator<A, element>::type other;
  227. typedef detail::sp_array_state<other> state;
  228. typedef detail::sp_array_base<state> base;
  229. detail::sp_array_result<other, base> result(allocator, count);
  230. base* node = result.get();
  231. element* start = detail::sp_array_start<element>(node);
  232. ::new(static_cast<void*>(node)) base(allocator, start, count);
  233. result.release();
  234. return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
  235. detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
  236. }
  237. template<class T, class A>
  238. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  239. allocate_shared(const A& allocator)
  240. {
  241. enum {
  242. count = extent<T>::value
  243. };
  244. typedef typename detail::sp_array_element<T>::type element;
  245. typedef typename detail::sp_bind_allocator<A, element>::type other;
  246. typedef detail::sp_size_array_state<other, extent<T>::value> state;
  247. typedef detail::sp_array_base<state> base;
  248. detail::sp_array_result<other, base> result(allocator, count);
  249. base* node = result.get();
  250. element* start = detail::sp_array_start<element>(node);
  251. ::new(static_cast<void*>(node)) base(allocator, start, count);
  252. result.release();
  253. return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
  254. detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
  255. }
  256. template<class T, class A>
  257. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  258. allocate_shared(const A& allocator, std::size_t count,
  259. const typename remove_extent<T>::type& value)
  260. {
  261. typedef typename detail::sp_array_element<T>::type element;
  262. typedef typename detail::sp_bind_allocator<A, element>::type other;
  263. typedef detail::sp_array_state<other> state;
  264. typedef detail::sp_array_base<state> base;
  265. detail::sp_array_result<other, base> result(allocator, count);
  266. base* node = result.get();
  267. element* start = detail::sp_array_start<element>(node);
  268. ::new(static_cast<void*>(node)) base(allocator, start, count, value);
  269. result.release();
  270. return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
  271. detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
  272. }
  273. template<class T, class A>
  274. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  275. allocate_shared(const A& allocator,
  276. const typename remove_extent<T>::type& value)
  277. {
  278. enum {
  279. count = extent<T>::value
  280. };
  281. typedef typename detail::sp_array_element<T>::type element;
  282. typedef typename detail::sp_bind_allocator<A, element>::type other;
  283. typedef detail::sp_size_array_state<other, extent<T>::value> state;
  284. typedef detail::sp_array_base<state> base;
  285. detail::sp_array_result<other, base> result(allocator, count);
  286. base* node = result.get();
  287. element* start = detail::sp_array_start<element>(node);
  288. ::new(static_cast<void*>(node)) base(allocator, start, count, value);
  289. result.release();
  290. return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
  291. detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
  292. }
  293. template<class T, class A>
  294. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  295. allocate_shared_noinit(const A& allocator, std::size_t count)
  296. {
  297. return boost::allocate_shared<T>(boost::noinit_adapt(allocator), count);
  298. }
  299. template<class T, class A>
  300. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  301. allocate_shared_noinit(const A& allocator)
  302. {
  303. return boost::allocate_shared<T>(boost::noinit_adapt(allocator));
  304. }
  305. } /* boost */
  306. #endif