allocate_shared_array.hpp 9.8 KB

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