allocate_shared_array.hpp 9.7 KB

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