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 
52 namespace boost
53 {
54 
55 namespace movelib
56 {
57 
58 template< class T, class D > class unique_ptr;
59 
60 } // namespace movelib
61 
62 namespace detail
63 {
64 
65 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
66 
67 int const shared_count_id = 0x2C35F101;
68 int const   weak_count_id = 0x298C38A4;
69 
70 #endif
71 
72 struct sp_nothrow_tag {};
73 
74 template< class D > struct sp_inplace_tag
75 {
76 };
77 
78 template< class T > class sp_reference_wrapper
79 {
80 public:
81 
sp_reference_wrapper(T & t)82     explicit sp_reference_wrapper( T & t): t_( boost::addressof( t ) )
83     {
84     }
85 
operator ()(Y * p) const86     template< class Y > void operator()( Y * p ) const
87     {
88         (*t_)( p );
89     }
90 
91 private:
92 
93     T * t_;
94 };
95 
96 template< class D > struct sp_convert_reference
97 {
98     typedef D type;
99 };
100 
101 template< class D > struct sp_convert_reference< D& >
102 {
103     typedef sp_reference_wrapper< D > type;
104 };
105 
106 class weak_count;
107 
108 class shared_count
109 {
110 private:
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 
120 public:
121 
shared_count()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 
shared_count(sp_counted_base * pi)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 
shared_count(Y * p)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 )
shared_count(Y * p,D d)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 
shared_count(P p,sp_inplace_tag<D>)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 
shared_count(P p,D d,A a)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 
shared_count(P p,sp_inplace_tag<D>,A a)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>
shared_count(std::auto_ptr<Y> & r)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>
shared_count(std::unique_ptr<Y,D> & r)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>
shared_count(boost::movelib::unique_ptr<Y,D> & r)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 
~shared_count()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 
shared_count(shared_count const & r)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 
shared_count(shared_count && r)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 
operator =(shared_count const & r)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 
swap(shared_count & r)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 
use_count() const477     long use_count() const BOOST_SP_NOEXCEPT
478     {
479         return pi_ != 0? pi_->use_count(): 0;
480     }
481 
unique() const482     bool unique() const BOOST_SP_NOEXCEPT
483     {
484         return use_count() == 1;
485     }
486 
empty() const487     bool empty() const BOOST_SP_NOEXCEPT
488     {
489         return pi_ == 0;
490     }
491 
operator ==(shared_count const & a,shared_count const & b)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 
operator <(shared_count const & a,shared_count const & b)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 
get_deleter(sp_typeinfo_ const & ti) const502     void * get_deleter( sp_typeinfo_ const & ti ) const BOOST_SP_NOEXCEPT
503     {
504         return pi_? pi_->get_deleter( ti ): 0;
505     }
506 
get_local_deleter(sp_typeinfo_ const & ti) const507     void * get_local_deleter( sp_typeinfo_ const & ti ) const BOOST_SP_NOEXCEPT
508     {
509         return pi_? pi_->get_local_deleter( ti ): 0;
510     }
511 
get_untyped_deleter() const512     void * get_untyped_deleter() const BOOST_SP_NOEXCEPT
513     {
514         return pi_? pi_->get_untyped_deleter(): 0;
515     }
516 };
517 
518 
519 class weak_count
520 {
521 private:
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 
531 public:
532 
weak_count()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 
weak_count(shared_count const & r)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 
weak_count(weak_count const & r)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 
weak_count(weak_count && r)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 
~weak_count()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 
operator =(shared_count const & r)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 
operator =(weak_count const & r)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 
swap(weak_count & r)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 
use_count() const613     long use_count() const BOOST_SP_NOEXCEPT
614     {
615         return pi_ != 0? pi_->use_count(): 0;
616     }
617 
empty() const618     bool empty() const BOOST_SP_NOEXCEPT
619     {
620         return pi_ == 0;
621     }
622 
operator ==(weak_count const & a,weak_count const & b)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 
operator <(weak_count const & a,weak_count const & b)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 
shared_count(weak_count const & r)634 inline 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 
shared_count(weak_count const & r,sp_nothrow_tag)645 inline 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