allocate_shared_array.hpp 9.3 KB

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