allocate_shared_array.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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/smart_ptr/shared_ptr.hpp>
  10. #include <boost/type_traits/alignment_of.hpp>
  11. #include <boost/type_traits/enable_if.hpp>
  12. #include <boost/type_traits/is_bounded_array.hpp>
  13. #include <boost/type_traits/is_unbounded_array.hpp>
  14. #include <boost/type_traits/has_trivial_assign.hpp>
  15. #include <boost/type_traits/has_trivial_constructor.hpp>
  16. #include <boost/type_traits/has_trivial_destructor.hpp>
  17. #include <boost/type_traits/remove_all_extents.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_scalar {
  25. typedef typename boost::remove_cv<typename
  26. boost::remove_all_extents<T>::type>::type type;
  27. };
  28. template<class T, class U>
  29. struct sp_array_count {
  30. enum {
  31. value = sizeof(T) / sizeof(U)
  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. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  47. template<class A, class T>
  48. struct sp_bind_allocator {
  49. typedef typename std::allocator_traits<A>::template rebind_alloc<T> type;
  50. };
  51. #else
  52. template<class A, class T>
  53. struct sp_bind_allocator {
  54. typedef typename A::template rebind<T>::other type;
  55. };
  56. #endif
  57. template<class T>
  58. BOOST_CONSTEXPR inline std::size_t
  59. sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
  60. {
  61. return (size + sizeof(T) - 1) / sizeof(T);
  62. }
  63. template<bool E, class A, class T>
  64. inline typename boost::enable_if_<!E &&
  65. boost::has_trivial_destructor<T>::value>::type
  66. sp_array_destroy(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
  67. template<bool E, class A, class T>
  68. inline typename boost::enable_if_<!E &&
  69. !boost::has_trivial_destructor<T>::value>::type
  70. sp_array_destroy(A&, T* ptr, std::size_t size)
  71. {
  72. while (size > 0) {
  73. ptr[--size].~T();
  74. }
  75. }
  76. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  77. template<bool E, class A, class T>
  78. inline typename boost::enable_if_<E>::type
  79. sp_array_destroy(A& allocator, T* ptr, std::size_t size)
  80. {
  81. while (size > 0) {
  82. std::allocator_traits<A>::destroy(allocator, ptr + --size);
  83. }
  84. }
  85. #endif
  86. template<bool E, class A, class T>
  87. class sp_destroyer {
  88. public:
  89. sp_destroyer(A& allocator, T* ptr) BOOST_SP_NOEXCEPT
  90. : allocator_(allocator),
  91. ptr_(ptr),
  92. size_(0) { }
  93. ~sp_destroyer() {
  94. sp_array_destroy<E>(allocator_, ptr_, size_);
  95. }
  96. std::size_t& size() BOOST_SP_NOEXCEPT {
  97. return size_;
  98. }
  99. private:
  100. sp_destroyer(const sp_destroyer&);
  101. sp_destroyer& operator=(const sp_destroyer&);
  102. A& allocator_;
  103. T* ptr_;
  104. std::size_t size_;
  105. };
  106. template<bool E, class A, class T>
  107. inline typename boost::enable_if_<!E &&
  108. boost::has_trivial_constructor<T>::value &&
  109. boost::has_trivial_assign<T>::value &&
  110. boost::has_trivial_destructor<T>::value>::type
  111. sp_array_construct(A&, T* ptr, std::size_t size)
  112. {
  113. for (std::size_t i = 0; i < size; ++i) {
  114. ptr[i] = T();
  115. }
  116. }
  117. template<bool E, class A, class T>
  118. inline typename boost::enable_if_<!E &&
  119. boost::has_trivial_constructor<T>::value &&
  120. boost::has_trivial_assign<T>::value &&
  121. boost::has_trivial_destructor<T>::value>::type
  122. sp_array_construct(A&, T* ptr, std::size_t size, const T* list,
  123. std::size_t count)
  124. {
  125. for (std::size_t i = 0; i < size; ++i) {
  126. ptr[i] = list[i % count];
  127. }
  128. }
  129. template<bool E, class A, class T>
  130. inline typename boost::enable_if_<!E &&
  131. !(boost::has_trivial_constructor<T>::value &&
  132. boost::has_trivial_assign<T>::value &&
  133. boost::has_trivial_destructor<T>::value)>::type
  134. sp_array_construct(A& none, T* ptr, std::size_t size)
  135. {
  136. sp_destroyer<E, A, T> hold(none, ptr);
  137. for (std::size_t& i = hold.size(); i < size; ++i) {
  138. ::new(static_cast<void*>(ptr + i)) T();
  139. }
  140. hold.size() = 0;
  141. }
  142. template<bool E, class A, class T>
  143. inline typename boost::enable_if_<!E &&
  144. !(boost::has_trivial_constructor<T>::value &&
  145. boost::has_trivial_assign<T>::value &&
  146. boost::has_trivial_destructor<T>::value)>::type
  147. sp_array_construct(A& none, T* ptr, std::size_t size, const T* list,
  148. std::size_t count)
  149. {
  150. sp_destroyer<E, A, T> hold(none, ptr);
  151. for (std::size_t& i = hold.size(); i < size; ++i) {
  152. ::new(static_cast<void*>(ptr + i)) T(list[i % count]);
  153. }
  154. hold.size() = 0;
  155. }
  156. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  157. template<bool E, class A, class T>
  158. inline typename boost::enable_if_<E>::type
  159. sp_array_construct(A& allocator, T* ptr, std::size_t size)
  160. {
  161. sp_destroyer<E, A, T> hold(allocator, ptr);
  162. for (std::size_t& i = hold.size(); i < size; ++i) {
  163. std::allocator_traits<A>::construct(allocator, ptr + i);
  164. }
  165. hold.size() = 0;
  166. }
  167. template<bool E, class A, class T>
  168. inline typename boost::enable_if_<E>::type
  169. sp_array_construct(A& allocator, T* ptr, std::size_t size, const T* list,
  170. std::size_t count)
  171. {
  172. sp_destroyer<E, A, T> hold(allocator, ptr);
  173. for (std::size_t& i = hold.size(); i < size; ++i) {
  174. std::allocator_traits<A>::construct(allocator, ptr + i,
  175. list[i % count]);
  176. }
  177. hold.size() = 0;
  178. }
  179. #endif
  180. template<class A, class T>
  181. inline typename
  182. boost::enable_if_<boost::has_trivial_constructor<T>::value>::type
  183. sp_array_default(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
  184. template<class A, class T>
  185. inline typename
  186. boost::enable_if_<!boost::has_trivial_constructor<T>::value>::type
  187. sp_array_default(A& none, T* ptr, std::size_t size)
  188. {
  189. sp_destroyer<false, A, T> hold(none, ptr);
  190. for (std::size_t& i = hold.size(); i < size; ++i) {
  191. ::new(static_cast<void*>(ptr + i)) T;
  192. }
  193. hold.size() = 0;
  194. }
  195. template<class A>
  196. class sp_array_state {
  197. public:
  198. typedef A type;
  199. template<class U>
  200. sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT
  201. : allocator_(_allocator),
  202. size_(_size) { }
  203. A& allocator() BOOST_SP_NOEXCEPT {
  204. return allocator_;
  205. }
  206. std::size_t size() const BOOST_SP_NOEXCEPT {
  207. return size_;
  208. }
  209. private:
  210. A allocator_;
  211. std::size_t size_;
  212. };
  213. template<class A, std::size_t N>
  214. class sp_size_array_state {
  215. public:
  216. typedef A type;
  217. template<class U>
  218. sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT
  219. : allocator_(_allocator) { }
  220. A& allocator() BOOST_SP_NOEXCEPT {
  221. return allocator_;
  222. }
  223. BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
  224. return N;
  225. }
  226. private:
  227. A allocator_;
  228. };
  229. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  230. template<class A>
  231. struct sp_use_construct {
  232. enum {
  233. value = true
  234. };
  235. };
  236. template<class T>
  237. struct sp_use_construct<std::allocator<T> > {
  238. enum {
  239. value = false
  240. };
  241. };
  242. #else
  243. template<class>
  244. struct sp_use_construct {
  245. enum {
  246. value = false
  247. };
  248. };
  249. #endif
  250. template<class T, class U>
  251. struct sp_array_alignment {
  252. enum {
  253. value = sp_max_size<boost::alignment_of<T>::value,
  254. boost::alignment_of<U>::value>::value
  255. };
  256. };
  257. template<class T, class U>
  258. struct sp_array_offset {
  259. enum {
  260. value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
  261. };
  262. };
  263. template<class T, class U>
  264. struct sp_array_storage {
  265. enum {
  266. value = sp_array_alignment<T, U>::value
  267. };
  268. typedef typename boost::type_with_alignment<value>::type type;
  269. };
  270. template<class T, class U>
  271. inline U*
  272. sp_array_start(void* base) BOOST_SP_NOEXCEPT
  273. {
  274. enum {
  275. size = sp_array_offset<T, U>::value
  276. };
  277. return reinterpret_cast<U*>(static_cast<char*>(base) + size);
  278. }
  279. template<class A, class T>
  280. class sp_array_creator {
  281. typedef typename A::value_type scalar;
  282. enum {
  283. offset = sp_array_offset<T, scalar>::value
  284. };
  285. typedef typename sp_array_storage<T, scalar>::type type;
  286. public:
  287. template<class U>
  288. sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
  289. : other_(other),
  290. size_(sp_objects<type>(offset + sizeof(scalar) * size)) { }
  291. T* create() {
  292. return reinterpret_cast<T*>(other_.allocate(size_));
  293. }
  294. void destroy(T* base) {
  295. other_.deallocate(reinterpret_cast<type*>(base), size_);
  296. }
  297. private:
  298. typename sp_bind_allocator<A, type>::type other_;
  299. std::size_t size_;
  300. };
  301. struct sp_default { };
  302. template<class T, bool E = sp_use_construct<T>::value>
  303. class BOOST_SYMBOL_VISIBLE sp_array_base
  304. : public sp_counted_base {
  305. typedef typename T::type allocator;
  306. public:
  307. typedef typename allocator::value_type type;
  308. template<class A>
  309. sp_array_base(const A& other, std::size_t size, type* start)
  310. : state_(other, size) {
  311. sp_array_construct<E>(state_.allocator(), start, state_.size());
  312. }
  313. template<class A>
  314. sp_array_base(const A& other, std::size_t size, const type* list,
  315. std::size_t count, type* start)
  316. : state_(other, size) {
  317. sp_array_construct<E>(state_.allocator(), start, state_.size(), list,
  318. count);
  319. }
  320. template<class A>
  321. sp_array_base(sp_default, const A& other, std::size_t size, type* start)
  322. : state_(other, size) {
  323. sp_array_default(state_.allocator(), start, state_.size());
  324. }
  325. T& state() BOOST_SP_NOEXCEPT {
  326. return state_;
  327. }
  328. virtual void dispose() BOOST_SP_NOEXCEPT {
  329. sp_array_destroy<E>(state_.allocator(),
  330. sp_array_start<sp_array_base, type>(this), state_.size());
  331. }
  332. virtual void destroy() BOOST_SP_NOEXCEPT {
  333. sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
  334. state_.size());
  335. this->~sp_array_base();
  336. other.destroy(this);
  337. }
  338. virtual void* get_deleter(const sp_typeinfo&) BOOST_SP_NOEXCEPT {
  339. return 0;
  340. }
  341. virtual void* get_local_deleter(const sp_typeinfo&) BOOST_SP_NOEXCEPT {
  342. return 0;
  343. }
  344. virtual void* get_untyped_deleter() BOOST_SP_NOEXCEPT {
  345. return 0;
  346. }
  347. private:
  348. T state_;
  349. };
  350. template<class A, class T>
  351. struct sp_array_result {
  352. public:
  353. template<class U>
  354. sp_array_result(const U& other, std::size_t size)
  355. : creator_(other, size),
  356. result_(creator_.create()) { }
  357. ~sp_array_result() {
  358. if (result_) {
  359. creator_.destroy(result_);
  360. }
  361. }
  362. T* get() const {
  363. return result_;
  364. }
  365. void release() {
  366. result_ = 0;
  367. }
  368. private:
  369. sp_array_result(const sp_array_result&);
  370. sp_array_result& operator=(const sp_array_result&);
  371. sp_array_creator<A, T> creator_;
  372. T* result_;
  373. };
  374. } /* detail */
  375. template<class T, class A>
  376. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  377. allocate_shared(const A& allocator, std::size_t count)
  378. {
  379. typedef typename remove_extent<T>::type type;
  380. typedef typename detail::sp_array_scalar<T>::type scalar;
  381. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  382. typedef detail::sp_array_state<other> state;
  383. typedef detail::sp_array_base<state> base;
  384. std::size_t size = count * detail::sp_array_count<type, scalar>::value;
  385. detail::sp_array_result<other, base> result(allocator, size);
  386. detail::sp_counted_base* node = result.get();
  387. scalar* start = detail::sp_array_start<base, scalar>(node);
  388. ::new(static_cast<void*>(node)) base(allocator, size, start);
  389. result.release();
  390. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  391. reinterpret_cast<type*>(start), detail::shared_count(node));
  392. }
  393. template<class T, class A>
  394. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  395. allocate_shared(const A& allocator)
  396. {
  397. typedef typename remove_extent<T>::type type;
  398. typedef typename detail::sp_array_scalar<T>::type scalar;
  399. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  400. enum {
  401. size = detail::sp_array_count<T, scalar>::value
  402. };
  403. typedef detail::sp_size_array_state<other, size> state;
  404. typedef detail::sp_array_base<state> base;
  405. detail::sp_array_result<other, base> result(allocator, size);
  406. detail::sp_counted_base* node = result.get();
  407. scalar* start = detail::sp_array_start<base, scalar>(node);
  408. ::new(static_cast<void*>(node)) base(allocator, size, start);
  409. result.release();
  410. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  411. reinterpret_cast<type*>(start), detail::shared_count(node));
  412. }
  413. template<class T, class A>
  414. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  415. allocate_shared(const A& allocator, std::size_t count,
  416. const typename remove_extent<T>::type& value)
  417. {
  418. typedef typename remove_extent<T>::type type;
  419. typedef typename detail::sp_array_scalar<T>::type scalar;
  420. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  421. typedef detail::sp_array_state<other> state;
  422. typedef detail::sp_array_base<state> base;
  423. enum {
  424. total = detail::sp_array_count<type, scalar>::value
  425. };
  426. std::size_t size = count * total;
  427. detail::sp_array_result<other, base> result(allocator, size);
  428. detail::sp_counted_base* node = result.get();
  429. scalar* start = detail::sp_array_start<base, scalar>(node);
  430. ::new(static_cast<void*>(node)) base(allocator, size,
  431. reinterpret_cast<const scalar*>(&value), total, start);
  432. result.release();
  433. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  434. reinterpret_cast<type*>(start), detail::shared_count(node));
  435. }
  436. template<class T, class A>
  437. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  438. allocate_shared(const A& allocator,
  439. const typename remove_extent<T>::type& value)
  440. {
  441. typedef typename remove_extent<T>::type type;
  442. typedef typename detail::sp_array_scalar<T>::type scalar;
  443. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  444. enum {
  445. size = detail::sp_array_count<T, scalar>::value
  446. };
  447. typedef detail::sp_size_array_state<other, size> state;
  448. typedef detail::sp_array_base<state> base;
  449. detail::sp_array_result<other, base> result(allocator, size);
  450. detail::sp_counted_base* node = result.get();
  451. scalar* start = detail::sp_array_start<base, scalar>(node);
  452. ::new(static_cast<void*>(node)) base(allocator, size,
  453. reinterpret_cast<const scalar*>(&value),
  454. detail::sp_array_count<type, scalar>::value, start);
  455. result.release();
  456. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  457. reinterpret_cast<type*>(start), detail::shared_count(node));
  458. }
  459. template<class T, class A>
  460. inline typename enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
  461. allocate_shared_noinit(const A& allocator, std::size_t count)
  462. {
  463. typedef typename remove_extent<T>::type type;
  464. typedef typename detail::sp_array_scalar<T>::type scalar;
  465. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  466. typedef detail::sp_array_state<other> state;
  467. typedef detail::sp_array_base<state, false> base;
  468. std::size_t size = count * detail::sp_array_count<type, scalar>::value;
  469. detail::sp_array_result<other, base> result(allocator, size);
  470. detail::sp_counted_base* node = result.get();
  471. scalar* start = detail::sp_array_start<base, scalar>(node);
  472. ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
  473. size, start);
  474. result.release();
  475. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  476. reinterpret_cast<type*>(start), detail::shared_count(node));
  477. }
  478. template<class T, class A>
  479. inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
  480. allocate_shared_noinit(const A& allocator)
  481. {
  482. typedef typename remove_extent<T>::type type;
  483. typedef typename detail::sp_array_scalar<T>::type scalar;
  484. typedef typename detail::sp_bind_allocator<A, scalar>::type other;
  485. enum {
  486. size = detail::sp_array_count<T, scalar>::value
  487. };
  488. typedef detail::sp_size_array_state<other, size> state;
  489. typedef detail::sp_array_base<state, false> base;
  490. detail::sp_array_result<other, base> result(allocator, size);
  491. detail::sp_counted_base* node = result.get();
  492. scalar* start = detail::sp_array_start<base, scalar>(node);
  493. ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
  494. size, start);
  495. result.release();
  496. return shared_ptr<T>(detail::sp_internal_constructor_tag(),
  497. reinterpret_cast<type*>(start), detail::shared_count(node));
  498. }
  499. } /* boost */
  500. #endif