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