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