shared_count.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED
  2. #define BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED
  3. // MS compatible compilers support #pragma once
  4. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  5. # pragma once
  6. #endif
  7. //
  8. // detail/shared_count.hpp
  9. //
  10. // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
  11. // Copyright 2004-2005 Peter Dimov
  12. //
  13. // Distributed under the Boost Software License, Version 1.0. (See
  14. // accompanying file LICENSE_1_0.txt or copy at
  15. // http://www.boost.org/LICENSE_1_0.txt)
  16. //
  17. #if defined(__BORLANDC__) && !defined(__clang__)
  18. # pragma warn -8027 // Functions containing try are not expanded inline
  19. #endif
  20. #include <boost/smart_ptr/bad_weak_ptr.hpp>
  21. #include <boost/smart_ptr/detail/sp_counted_base.hpp>
  22. #include <boost/smart_ptr/detail/sp_counted_impl.hpp>
  23. #include <boost/smart_ptr/detail/sp_disable_deprecated.hpp>
  24. #include <boost/smart_ptr/detail/sp_noexcept.hpp>
  25. #include <boost/checked_delete.hpp>
  26. #include <boost/throw_exception.hpp>
  27. #include <boost/core/addressof.hpp>
  28. #include <boost/config.hpp>
  29. #include <boost/config/workaround.hpp>
  30. #include <boost/cstdint.hpp>
  31. #include <memory> // std::auto_ptr
  32. #include <functional> // std::less
  33. #include <cstddef> // std::size_t
  34. #ifdef BOOST_NO_EXCEPTIONS
  35. # include <new> // std::bad_alloc
  36. #endif
  37. #if defined( BOOST_SP_DISABLE_DEPRECATED )
  38. #pragma GCC diagnostic push
  39. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  40. #endif
  41. namespace boost
  42. {
  43. namespace movelib
  44. {
  45. template< class T, class D > class unique_ptr;
  46. } // namespace movelib
  47. namespace detail
  48. {
  49. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  50. int const shared_count_id = 0x2C35F101;
  51. int const weak_count_id = 0x298C38A4;
  52. #endif
  53. struct sp_nothrow_tag {};
  54. template< class D > struct sp_inplace_tag
  55. {
  56. };
  57. template< class T > class sp_reference_wrapper
  58. {
  59. public:
  60. explicit sp_reference_wrapper( T & t): t_( boost::addressof( t ) )
  61. {
  62. }
  63. template< class Y > void operator()( Y * p ) const
  64. {
  65. (*t_)( p );
  66. }
  67. private:
  68. T * t_;
  69. };
  70. template< class D > struct sp_convert_reference
  71. {
  72. typedef D type;
  73. };
  74. template< class D > struct sp_convert_reference< D& >
  75. {
  76. typedef sp_reference_wrapper< D > type;
  77. };
  78. template<class T> std::size_t sp_hash_pointer( T* p ) BOOST_NOEXCEPT
  79. {
  80. boost::uintptr_t v = reinterpret_cast<boost::uintptr_t>( p );
  81. // match boost::hash<T*>
  82. return static_cast<std::size_t>( v + ( v >> 3 ) );
  83. }
  84. class weak_count;
  85. class shared_count
  86. {
  87. private:
  88. sp_counted_base * pi_;
  89. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  90. int id_;
  91. #endif
  92. friend class weak_count;
  93. public:
  94. BOOST_CONSTEXPR shared_count() BOOST_SP_NOEXCEPT: pi_(0)
  95. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  96. , id_(shared_count_id)
  97. #endif
  98. {
  99. }
  100. BOOST_CONSTEXPR explicit shared_count( sp_counted_base * pi ) BOOST_SP_NOEXCEPT: pi_( pi )
  101. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  102. , id_(shared_count_id)
  103. #endif
  104. {
  105. }
  106. template<class Y> explicit shared_count( Y * p ): pi_( 0 )
  107. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  108. , id_(shared_count_id)
  109. #endif
  110. {
  111. #ifndef BOOST_NO_EXCEPTIONS
  112. try
  113. {
  114. pi_ = new sp_counted_impl_p<Y>( p );
  115. }
  116. catch(...)
  117. {
  118. boost::checked_delete( p );
  119. throw;
  120. }
  121. #else
  122. pi_ = new sp_counted_impl_p<Y>( p );
  123. if( pi_ == 0 )
  124. {
  125. boost::checked_delete( p );
  126. boost::throw_exception( std::bad_alloc() );
  127. }
  128. #endif
  129. }
  130. #if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
  131. template<class Y, class D> shared_count( Y * p, D d ): pi_(0)
  132. #else
  133. template<class P, class D> shared_count( P p, D d ): pi_(0)
  134. #endif
  135. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  136. , id_(shared_count_id)
  137. #endif
  138. {
  139. #if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
  140. typedef Y* P;
  141. #endif
  142. #ifndef BOOST_NO_EXCEPTIONS
  143. try
  144. {
  145. pi_ = new sp_counted_impl_pd<P, D>(p, d);
  146. }
  147. catch(...)
  148. {
  149. d(p); // delete p
  150. throw;
  151. }
  152. #else
  153. pi_ = new sp_counted_impl_pd<P, D>(p, d);
  154. if(pi_ == 0)
  155. {
  156. d(p); // delete p
  157. boost::throw_exception(std::bad_alloc());
  158. }
  159. #endif
  160. }
  161. #if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
  162. template< class P, class D > shared_count( P p, sp_inplace_tag<D> ): pi_( 0 )
  163. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  164. , id_(shared_count_id)
  165. #endif
  166. {
  167. #ifndef BOOST_NO_EXCEPTIONS
  168. try
  169. {
  170. pi_ = new sp_counted_impl_pd< P, D >( p );
  171. }
  172. catch( ... )
  173. {
  174. D::operator_fn( p ); // delete p
  175. throw;
  176. }
  177. #else
  178. pi_ = new sp_counted_impl_pd< P, D >( p );
  179. if( pi_ == 0 )
  180. {
  181. D::operator_fn( p ); // delete p
  182. boost::throw_exception( std::bad_alloc() );
  183. }
  184. #endif // #ifndef BOOST_NO_EXCEPTIONS
  185. }
  186. #endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
  187. template<class P, class D, class A> shared_count( P p, D d, A a ): pi_( 0 )
  188. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  189. , id_(shared_count_id)
  190. #endif
  191. {
  192. typedef sp_counted_impl_pda<P, D, A> impl_type;
  193. #if !defined( BOOST_NO_CXX11_ALLOCATOR )
  194. typedef typename std::allocator_traits<A>::template rebind_alloc< impl_type > A2;
  195. #else
  196. typedef typename A::template rebind< impl_type >::other A2;
  197. #endif
  198. A2 a2( a );
  199. #ifndef BOOST_NO_EXCEPTIONS
  200. try
  201. {
  202. pi_ = a2.allocate( 1 );
  203. ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
  204. }
  205. catch(...)
  206. {
  207. d( p );
  208. if( pi_ != 0 )
  209. {
  210. a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
  211. }
  212. throw;
  213. }
  214. #else
  215. pi_ = a2.allocate( 1 );
  216. if( pi_ != 0 )
  217. {
  218. ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
  219. }
  220. else
  221. {
  222. d( p );
  223. boost::throw_exception( std::bad_alloc() );
  224. }
  225. #endif
  226. }
  227. #if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
  228. template< class P, class D, class A > shared_count( P p, sp_inplace_tag< D >, A a ): pi_( 0 )
  229. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  230. , id_(shared_count_id)
  231. #endif
  232. {
  233. typedef sp_counted_impl_pda< P, D, A > impl_type;
  234. #if !defined( BOOST_NO_CXX11_ALLOCATOR )
  235. typedef typename std::allocator_traits<A>::template rebind_alloc< impl_type > A2;
  236. #else
  237. typedef typename A::template rebind< impl_type >::other A2;
  238. #endif
  239. A2 a2( a );
  240. #ifndef BOOST_NO_EXCEPTIONS
  241. try
  242. {
  243. pi_ = a2.allocate( 1 );
  244. ::new( static_cast< void* >( pi_ ) ) impl_type( p, a );
  245. }
  246. catch(...)
  247. {
  248. D::operator_fn( p );
  249. if( pi_ != 0 )
  250. {
  251. a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
  252. }
  253. throw;
  254. }
  255. #else
  256. pi_ = a2.allocate( 1 );
  257. if( pi_ != 0 )
  258. {
  259. ::new( static_cast< void* >( pi_ ) ) impl_type( p, a );
  260. }
  261. else
  262. {
  263. D::operator_fn( p );
  264. boost::throw_exception( std::bad_alloc() );
  265. }
  266. #endif // #ifndef BOOST_NO_EXCEPTIONS
  267. }
  268. #endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
  269. #ifndef BOOST_NO_AUTO_PTR
  270. // auto_ptr<Y> is special cased to provide the strong guarantee
  271. template<class Y>
  272. explicit shared_count( std::auto_ptr<Y> & r ): pi_( new sp_counted_impl_p<Y>( r.get() ) )
  273. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  274. , id_(shared_count_id)
  275. #endif
  276. {
  277. #ifdef BOOST_NO_EXCEPTIONS
  278. if( pi_ == 0 )
  279. {
  280. boost::throw_exception(std::bad_alloc());
  281. }
  282. #endif
  283. r.release();
  284. }
  285. #endif
  286. #if !defined( BOOST_NO_CXX11_SMART_PTR )
  287. template<class Y, class D>
  288. explicit shared_count( std::unique_ptr<Y, D> & r ): pi_( 0 )
  289. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  290. , id_(shared_count_id)
  291. #endif
  292. {
  293. typedef typename sp_convert_reference<D>::type D2;
  294. D2 d2( r.get_deleter() );
  295. pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
  296. #ifdef BOOST_NO_EXCEPTIONS
  297. if( pi_ == 0 )
  298. {
  299. boost::throw_exception( std::bad_alloc() );
  300. }
  301. #endif
  302. r.release();
  303. }
  304. #endif
  305. template<class Y, class D>
  306. explicit shared_count( boost::movelib::unique_ptr<Y, D> & r ): pi_( 0 )
  307. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  308. , id_(shared_count_id)
  309. #endif
  310. {
  311. typedef typename sp_convert_reference<D>::type D2;
  312. D2 d2( r.get_deleter() );
  313. pi_ = new sp_counted_impl_pd< typename boost::movelib::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
  314. #ifdef BOOST_NO_EXCEPTIONS
  315. if( pi_ == 0 )
  316. {
  317. boost::throw_exception( std::bad_alloc() );
  318. }
  319. #endif
  320. r.release();
  321. }
  322. ~shared_count() /*BOOST_SP_NOEXCEPT*/
  323. {
  324. if( pi_ != 0 ) pi_->release();
  325. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  326. id_ = 0;
  327. #endif
  328. }
  329. shared_count(shared_count const & r) BOOST_SP_NOEXCEPT: pi_(r.pi_)
  330. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  331. , id_(shared_count_id)
  332. #endif
  333. {
  334. if( pi_ != 0 ) pi_->add_ref_copy();
  335. }
  336. #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
  337. shared_count(shared_count && r) BOOST_SP_NOEXCEPT: pi_(r.pi_)
  338. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  339. , id_(shared_count_id)
  340. #endif
  341. {
  342. r.pi_ = 0;
  343. }
  344. #endif
  345. explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
  346. shared_count( weak_count const & r, sp_nothrow_tag ) BOOST_SP_NOEXCEPT; // constructs an empty *this when r.use_count() == 0
  347. shared_count & operator= (shared_count const & r) BOOST_SP_NOEXCEPT
  348. {
  349. sp_counted_base * tmp = r.pi_;
  350. if( tmp != pi_ )
  351. {
  352. if( tmp != 0 ) tmp->add_ref_copy();
  353. if( pi_ != 0 ) pi_->release();
  354. pi_ = tmp;
  355. }
  356. return *this;
  357. }
  358. void swap(shared_count & r) BOOST_SP_NOEXCEPT
  359. {
  360. sp_counted_base * tmp = r.pi_;
  361. r.pi_ = pi_;
  362. pi_ = tmp;
  363. }
  364. long use_count() const BOOST_SP_NOEXCEPT
  365. {
  366. return pi_ != 0? pi_->use_count(): 0;
  367. }
  368. bool unique() const BOOST_SP_NOEXCEPT
  369. {
  370. return use_count() == 1;
  371. }
  372. bool empty() const BOOST_SP_NOEXCEPT
  373. {
  374. return pi_ == 0;
  375. }
  376. bool operator==( shared_count const & r ) const BOOST_SP_NOEXCEPT
  377. {
  378. return pi_ == r.pi_;
  379. }
  380. bool operator==( weak_count const & r ) const BOOST_SP_NOEXCEPT;
  381. bool operator<( shared_count const & r ) const BOOST_SP_NOEXCEPT
  382. {
  383. return std::less<sp_counted_base *>()( pi_, r.pi_ );
  384. }
  385. bool operator<( weak_count const & r ) const BOOST_SP_NOEXCEPT;
  386. void * get_deleter( sp_typeinfo_ const & ti ) const BOOST_SP_NOEXCEPT
  387. {
  388. return pi_? pi_->get_deleter( ti ): 0;
  389. }
  390. void * get_local_deleter( sp_typeinfo_ const & ti ) const BOOST_SP_NOEXCEPT
  391. {
  392. return pi_? pi_->get_local_deleter( ti ): 0;
  393. }
  394. void * get_untyped_deleter() const BOOST_SP_NOEXCEPT
  395. {
  396. return pi_? pi_->get_untyped_deleter(): 0;
  397. }
  398. std::size_t hash_value() const BOOST_SP_NOEXCEPT
  399. {
  400. return sp_hash_pointer( pi_ );
  401. }
  402. };
  403. class weak_count
  404. {
  405. private:
  406. sp_counted_base * pi_;
  407. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  408. int id_;
  409. #endif
  410. friend class shared_count;
  411. public:
  412. BOOST_CONSTEXPR weak_count() BOOST_SP_NOEXCEPT: pi_(0)
  413. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  414. , id_(weak_count_id)
  415. #endif
  416. {
  417. }
  418. weak_count(shared_count const & r) BOOST_SP_NOEXCEPT: pi_(r.pi_)
  419. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  420. , id_(weak_count_id)
  421. #endif
  422. {
  423. if(pi_ != 0) pi_->weak_add_ref();
  424. }
  425. weak_count(weak_count const & r) BOOST_SP_NOEXCEPT: pi_(r.pi_)
  426. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  427. , id_(weak_count_id)
  428. #endif
  429. {
  430. if(pi_ != 0) pi_->weak_add_ref();
  431. }
  432. // Move support
  433. #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
  434. weak_count(weak_count && r) BOOST_SP_NOEXCEPT: pi_(r.pi_)
  435. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  436. , id_(weak_count_id)
  437. #endif
  438. {
  439. r.pi_ = 0;
  440. }
  441. #endif
  442. ~weak_count() /*BOOST_SP_NOEXCEPT*/
  443. {
  444. if(pi_ != 0) pi_->weak_release();
  445. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  446. id_ = 0;
  447. #endif
  448. }
  449. weak_count & operator= (shared_count const & r) BOOST_SP_NOEXCEPT
  450. {
  451. sp_counted_base * tmp = r.pi_;
  452. if( tmp != pi_ )
  453. {
  454. if(tmp != 0) tmp->weak_add_ref();
  455. if(pi_ != 0) pi_->weak_release();
  456. pi_ = tmp;
  457. }
  458. return *this;
  459. }
  460. weak_count & operator= (weak_count const & r) BOOST_SP_NOEXCEPT
  461. {
  462. sp_counted_base * tmp = r.pi_;
  463. if( tmp != pi_ )
  464. {
  465. if(tmp != 0) tmp->weak_add_ref();
  466. if(pi_ != 0) pi_->weak_release();
  467. pi_ = tmp;
  468. }
  469. return *this;
  470. }
  471. void swap(weak_count & r) BOOST_SP_NOEXCEPT
  472. {
  473. sp_counted_base * tmp = r.pi_;
  474. r.pi_ = pi_;
  475. pi_ = tmp;
  476. }
  477. long use_count() const BOOST_SP_NOEXCEPT
  478. {
  479. return pi_ != 0? pi_->use_count(): 0;
  480. }
  481. bool empty() const BOOST_SP_NOEXCEPT
  482. {
  483. return pi_ == 0;
  484. }
  485. bool operator==( weak_count const & r ) const BOOST_SP_NOEXCEPT
  486. {
  487. return pi_ == r.pi_;
  488. }
  489. bool operator==( shared_count const & r ) const BOOST_SP_NOEXCEPT
  490. {
  491. return pi_ == r.pi_;
  492. }
  493. bool operator<( weak_count const & r ) const BOOST_SP_NOEXCEPT
  494. {
  495. return std::less<sp_counted_base *>()( pi_, r.pi_ );
  496. }
  497. bool operator<( shared_count const & r ) const BOOST_SP_NOEXCEPT
  498. {
  499. return std::less<sp_counted_base *>()( pi_, r.pi_ );
  500. }
  501. std::size_t hash_value() const BOOST_SP_NOEXCEPT
  502. {
  503. return sp_hash_pointer( pi_ );
  504. }
  505. };
  506. inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )
  507. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  508. , id_(shared_count_id)
  509. #endif
  510. {
  511. if( pi_ == 0 || !pi_->add_ref_lock() )
  512. {
  513. boost::throw_exception( boost::bad_weak_ptr() );
  514. }
  515. }
  516. inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ) BOOST_SP_NOEXCEPT: pi_( r.pi_ )
  517. #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
  518. , id_(shared_count_id)
  519. #endif
  520. {
  521. if( pi_ != 0 && !pi_->add_ref_lock() )
  522. {
  523. pi_ = 0;
  524. }
  525. }
  526. inline bool shared_count::operator==( weak_count const & r ) const BOOST_SP_NOEXCEPT
  527. {
  528. return pi_ == r.pi_;
  529. }
  530. inline bool shared_count::operator<( weak_count const & r ) const BOOST_SP_NOEXCEPT
  531. {
  532. return std::less<sp_counted_base *>()( pi_, r.pi_ );
  533. }
  534. } // namespace detail
  535. } // namespace boost
  536. #if defined( BOOST_SP_DISABLE_DEPRECATED )
  537. #pragma GCC diagnostic pop
  538. #endif
  539. #if defined(__BORLANDC__) && !defined(__clang__)
  540. # pragma warn .8027 // Functions containing try are not expanded inline
  541. #endif
  542. #endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED