deconstruct.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #ifndef BOOST_SIGNALS2_DECONSTRUCT_HPP
  2. #define BOOST_SIGNALS2_DECONSTRUCT_HPP
  3. // deconstruct.hpp
  4. //
  5. // A factory function for creating a shared_ptr which creates
  6. // an object and its owning shared_ptr with one allocation, similar
  7. // to make_shared<T>(). It also supports postconstructors
  8. // and predestructors through unqualified calls of adl_postconstruct() and
  9. // adl_predestruct, relying on argument-dependent
  10. // lookup to find the appropriate postconstructor or predestructor.
  11. // Passing arguments to postconstructors is also supported.
  12. //
  13. // based on make_shared.hpp and make_shared_access patch from Michael Marcin
  14. //
  15. // Copyright (c) 2007, 2008 Peter Dimov
  16. // Copyright (c) 2008 Michael Marcin
  17. // Copyright (c) 2009 Frank Mori Hess
  18. //
  19. // Distributed under the Boost Software License, Version 1.0.
  20. // See accompanying file LICENSE_1_0.txt or copy at
  21. // http://www.boost.org/LICENSE_1_0.txt
  22. //
  23. // See http://www.boost.org
  24. // for more information
  25. #include <boost/config.hpp>
  26. #include <boost/shared_ptr.hpp>
  27. #include <boost/signals2/deconstruct_ptr.hpp>
  28. #include <boost/type_traits/alignment_of.hpp>
  29. #include <boost/type_traits/remove_const.hpp>
  30. #include <boost/type_traits/type_with_alignment.hpp>
  31. #include <cstddef>
  32. #include <new>
  33. namespace boost
  34. {
  35. template<typename T> class enable_shared_from_this;
  36. namespace signals2
  37. {
  38. class deconstruct_access;
  39. namespace detail
  40. {
  41. inline void adl_predestruct(...) {}
  42. } // namespace detail
  43. template<typename T>
  44. class postconstructor_invoker
  45. {
  46. public:
  47. operator const shared_ptr<T> & () const
  48. {
  49. return postconstruct();
  50. }
  51. const shared_ptr<T>& postconstruct() const
  52. {
  53. if(!_postconstructed)
  54. {
  55. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()));
  56. _postconstructed = true;
  57. }
  58. return _sp;
  59. }
  60. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  61. template<class... Args>
  62. const shared_ptr<T>& postconstruct(Args && ... args)
  63. {
  64. if(!_postconstructed)
  65. {
  66. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  67. std::forward<Args>(args)...);
  68. _postconstructed = true;
  69. }
  70. return _sp;
  71. }
  72. #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  73. template<typename A1>
  74. const shared_ptr<T>& postconstruct(const A1 &a1) const
  75. {
  76. if(!_postconstructed)
  77. {
  78. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  79. a1);
  80. _postconstructed = true;
  81. }
  82. return _sp;
  83. }
  84. template<typename A1, typename A2>
  85. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2) const
  86. {
  87. if(!_postconstructed)
  88. {
  89. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  90. a1, a2);
  91. _postconstructed = true;
  92. }
  93. return _sp;
  94. }
  95. template<typename A1, typename A2, typename A3>
  96. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3) const
  97. {
  98. if(!_postconstructed)
  99. {
  100. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  101. a1, a2, a3);
  102. _postconstructed = true;
  103. }
  104. return _sp;
  105. }
  106. template<typename A1, typename A2, typename A3, typename A4>
  107. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) const
  108. {
  109. if(!_postconstructed)
  110. {
  111. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  112. a1, a2, a3, a4);
  113. _postconstructed = true;
  114. }
  115. return _sp;
  116. }
  117. template<typename A1, typename A2, typename A3, typename A4, typename A5>
  118. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5) const
  119. {
  120. if(!_postconstructed)
  121. {
  122. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  123. a1, a2, a3, a4, a5);
  124. _postconstructed = true;
  125. }
  126. return _sp;
  127. }
  128. template<typename A1, typename A2, typename A3, typename A4, typename A5,
  129. typename A6>
  130. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
  131. const A6 &a6) const
  132. {
  133. if(!_postconstructed)
  134. {
  135. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  136. a1, a2, a3, a4, a5, a6);
  137. _postconstructed = true;
  138. }
  139. return _sp;
  140. }
  141. template<typename A1, typename A2, typename A3, typename A4, typename A5,
  142. typename A6, typename A7>
  143. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
  144. const A6 &a6, const A7 &a7) const
  145. {
  146. if(!_postconstructed)
  147. {
  148. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  149. a1, a2, a3, a4, a5, a6, a7);
  150. _postconstructed = true;
  151. }
  152. return _sp;
  153. }
  154. template<typename A1, typename A2, typename A3, typename A4, typename A5,
  155. typename A6, typename A7, typename A8>
  156. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
  157. const A6 &a6, const A7 &a7, const A8 &a8) const
  158. {
  159. if(!_postconstructed)
  160. {
  161. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  162. a1, a2, a3, a4, a5, a6, a7, a8);
  163. _postconstructed = true;
  164. }
  165. return _sp;
  166. }
  167. template<typename A1, typename A2, typename A3, typename A4, typename A5,
  168. typename A6, typename A7, typename A8, typename A9>
  169. const shared_ptr<T>& postconstruct(const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4, const A5 &a5,
  170. const A6 &a6, const A7 &a7, const A8 &a8, const A9 &a9) const
  171. {
  172. if(!_postconstructed)
  173. {
  174. adl_postconstruct(_sp, const_cast<typename boost::remove_const<T>::type *>(_sp.get()),
  175. a1, a2, a3, a4, a5, a6, a7, a8, a9);
  176. _postconstructed = true;
  177. }
  178. return _sp;
  179. }
  180. #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  181. private:
  182. friend class boost::signals2::deconstruct_access;
  183. postconstructor_invoker(const shared_ptr<T> & sp):
  184. _sp(sp), _postconstructed(false)
  185. {}
  186. shared_ptr<T> _sp;
  187. mutable bool _postconstructed;
  188. };
  189. namespace detail
  190. {
  191. template< std::size_t N, std::size_t A > struct sp_aligned_storage
  192. {
  193. union type
  194. {
  195. char data_[ N ];
  196. typename boost::type_with_alignment< A >::type align_;
  197. };
  198. };
  199. template< class T > class deconstruct_deleter
  200. {
  201. private:
  202. typedef typename sp_aligned_storage< sizeof( T ), ::boost::alignment_of< T >::value >::type storage_type;
  203. bool initialized_;
  204. storage_type storage_;
  205. private:
  206. void destroy()
  207. {
  208. if( initialized_ )
  209. {
  210. T* p = reinterpret_cast< T* >( storage_.data_ );
  211. using boost::signals2::detail::adl_predestruct;
  212. adl_predestruct(const_cast<typename boost::remove_const<T>::type *>(p));
  213. p->~T();
  214. initialized_ = false;
  215. }
  216. }
  217. public:
  218. deconstruct_deleter(): initialized_( false )
  219. {
  220. }
  221. // this copy constructor is an optimization: we don't need to copy the storage_ member,
  222. // and shouldn't be copying anyways after initialized_ becomes true
  223. deconstruct_deleter(const deconstruct_deleter &): initialized_( false )
  224. {
  225. }
  226. ~deconstruct_deleter()
  227. {
  228. destroy();
  229. }
  230. void operator()( T * )
  231. {
  232. destroy();
  233. }
  234. void * address()
  235. {
  236. return storage_.data_;
  237. }
  238. void set_initialized()
  239. {
  240. initialized_ = true;
  241. }
  242. };
  243. } // namespace detail
  244. class deconstruct_access
  245. {
  246. public:
  247. template< class T >
  248. static postconstructor_invoker<T> deconstruct()
  249. {
  250. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  251. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  252. void * pv = pd->address();
  253. new( pv ) T();
  254. pd->set_initialized();
  255. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  256. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  257. return retval;
  258. }
  259. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  260. // Variadic templates, rvalue reference
  261. template< class T, class... Args >
  262. static postconstructor_invoker<T> deconstruct( Args && ... args )
  263. {
  264. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  265. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  266. void * pv = pd->address();
  267. new( pv ) T( std::forward<Args>( args )... );
  268. pd->set_initialized();
  269. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  270. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  271. return retval;
  272. }
  273. #else
  274. template< class T, class A1 >
  275. static postconstructor_invoker<T> deconstruct( A1 const & a1 )
  276. {
  277. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  278. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  279. void * pv = pd->address();
  280. new( pv ) T( a1 );
  281. pd->set_initialized();
  282. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  283. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  284. return retval;
  285. }
  286. template< class T, class A1, class A2 >
  287. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2 )
  288. {
  289. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  290. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  291. void * pv = pd->address();
  292. new( pv ) T( a1, a2 );
  293. pd->set_initialized();
  294. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  295. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  296. return retval;
  297. }
  298. template< class T, class A1, class A2, class A3 >
  299. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3 )
  300. {
  301. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  302. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  303. void * pv = pd->address();
  304. new( pv ) T( a1, a2, a3 );
  305. pd->set_initialized();
  306. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  307. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  308. return retval;
  309. }
  310. template< class T, class A1, class A2, class A3, class A4 >
  311. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
  312. {
  313. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  314. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  315. void * pv = pd->address();
  316. new( pv ) T( a1, a2, a3, a4 );
  317. pd->set_initialized();
  318. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  319. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  320. return retval;
  321. }
  322. template< class T, class A1, class A2, class A3, class A4, class A5 >
  323. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 )
  324. {
  325. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  326. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  327. void * pv = pd->address();
  328. new( pv ) T( a1, a2, a3, a4, a5 );
  329. pd->set_initialized();
  330. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  331. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  332. return retval;
  333. }
  334. template< class T, class A1, class A2, class A3, class A4, class A5, class A6 >
  335. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 )
  336. {
  337. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  338. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  339. void * pv = pd->address();
  340. new( pv ) T( a1, a2, a3, a4, a5, a6 );
  341. pd->set_initialized();
  342. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  343. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  344. return retval;
  345. }
  346. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
  347. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 )
  348. {
  349. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  350. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  351. void * pv = pd->address();
  352. new( pv ) T( a1, a2, a3, a4, a5, a6, a7 );
  353. pd->set_initialized();
  354. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  355. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  356. return retval;
  357. }
  358. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
  359. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 )
  360. {
  361. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  362. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  363. void * pv = pd->address();
  364. new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 );
  365. pd->set_initialized();
  366. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  367. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  368. return retval;
  369. }
  370. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
  371. static postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 )
  372. {
  373. boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::deconstruct_deleter< T >() );
  374. detail::deconstruct_deleter< T > * pd = boost::get_deleter< detail::deconstruct_deleter< T > >( pt );
  375. void * pv = pd->address();
  376. new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 );
  377. pd->set_initialized();
  378. boost::shared_ptr< T > retval( pt, static_cast< T* >( pv ) );
  379. boost::detail::sp_enable_shared_from_this(&retval, retval.get(), retval.get());
  380. return retval;
  381. }
  382. #endif
  383. };
  384. // Zero-argument versions
  385. //
  386. // Used even when variadic templates are available because of the new T() vs new T issue
  387. template< class T > postconstructor_invoker<T> deconstruct()
  388. {
  389. return deconstruct_access::deconstruct<T>();
  390. }
  391. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  392. // Variadic templates, rvalue reference
  393. template< class T, class... Args > postconstructor_invoker< T > deconstruct( Args && ... args )
  394. {
  395. return deconstruct_access::deconstruct<T>( std::forward<Args>( args )... );
  396. }
  397. #else
  398. // C++03 version
  399. template< class T, class A1 >
  400. postconstructor_invoker<T> deconstruct( A1 const & a1 )
  401. {
  402. return deconstruct_access::deconstruct<T>(a1);
  403. }
  404. template< class T, class A1, class A2 >
  405. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2 )
  406. {
  407. return deconstruct_access::deconstruct<T>(a1,a2);
  408. }
  409. template< class T, class A1, class A2, class A3 >
  410. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3 )
  411. {
  412. return deconstruct_access::deconstruct<T>(a1,a2,a3);
  413. }
  414. template< class T, class A1, class A2, class A3, class A4 >
  415. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
  416. {
  417. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4);
  418. }
  419. template< class T, class A1, class A2, class A3, class A4, class A5 >
  420. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 )
  421. {
  422. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4,a5);
  423. }
  424. template< class T, class A1, class A2, class A3, class A4, class A5, class A6 >
  425. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 )
  426. {
  427. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4,a5,a6);
  428. }
  429. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
  430. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 )
  431. {
  432. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4,a5,a6,a7);
  433. }
  434. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
  435. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 )
  436. {
  437. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4,a5,a6,a7,a8);
  438. }
  439. template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
  440. postconstructor_invoker<T> deconstruct( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 )
  441. {
  442. return deconstruct_access::deconstruct<T>(a1,a2,a3,a4,a5,a6,a7,a8,a9);
  443. }
  444. #endif
  445. } // namespace signals2
  446. } // namespace boost
  447. #endif // #ifndef BOOST_SIGNALS2_DECONSTRUCT_HPP