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