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 pdalboost
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_( pdalboost::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     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(Y * p)128     template<class Y> explicit shared_count( Y * p ): pi_( 0 )
129 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
130         , id_(shared_count_id)
131 #endif
132     {
133 #ifndef BOOST_NO_EXCEPTIONS
134 
135         try
136         {
137             pi_ = new sp_counted_impl_p<Y>( p );
138         }
139         catch(...)
140         {
141             pdalboost::checked_delete( p );
142             throw;
143         }
144 
145 #else
146 
147         pi_ = new sp_counted_impl_p<Y>( p );
148 
149         if( pi_ == 0 )
150         {
151             pdalboost::checked_delete( p );
152             pdalboost::throw_exception( std::bad_alloc() );
153         }
154 
155 #endif
156     }
157 
158 #if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
shared_count(Y * p,D d)159     template<class Y, class D> shared_count( Y * p, D d ): pi_(0)
160 #else
161     template<class P, class D> shared_count( P p, D d ): pi_(0)
162 #endif
163 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
164         , id_(shared_count_id)
165 #endif
166     {
167 #if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
168         typedef Y* P;
169 #endif
170 #ifndef BOOST_NO_EXCEPTIONS
171 
172         try
173         {
174             pi_ = new sp_counted_impl_pd<P, D>(p, d);
175         }
176         catch(...)
177         {
178             d(p); // delete p
179             throw;
180         }
181 
182 #else
183 
184         pi_ = new sp_counted_impl_pd<P, D>(p, d);
185 
186         if(pi_ == 0)
187         {
188             d(p); // delete p
189             pdalboost::throw_exception(std::bad_alloc());
190         }
191 
192 #endif
193     }
194 
195 #if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
196 
shared_count(P p,sp_inplace_tag<D>)197     template< class P, class D > shared_count( P p, sp_inplace_tag<D> ): pi_( 0 )
198 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
199         , id_(shared_count_id)
200 #endif
201     {
202 #ifndef BOOST_NO_EXCEPTIONS
203 
204         try
205         {
206             pi_ = new sp_counted_impl_pd< P, D >( p );
207         }
208         catch( ... )
209         {
210             D::operator_fn( p ); // delete p
211             throw;
212         }
213 
214 #else
215 
216         pi_ = new sp_counted_impl_pd< P, D >( p );
217 
218         if( pi_ == 0 )
219         {
220             D::operator_fn( p ); // delete p
221             pdalboost::throw_exception( std::bad_alloc() );
222         }
223 
224 #endif // #ifndef BOOST_NO_EXCEPTIONS
225     }
226 
227 #endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
228 
shared_count(P p,D d,A a)229     template<class P, class D, class A> shared_count( P p, D d, A a ): pi_( 0 )
230 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
231         , id_(shared_count_id)
232 #endif
233     {
234         typedef sp_counted_impl_pda<P, D, A> impl_type;
235 
236 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
237 
238         typedef typename std::allocator_traits<A>::template rebind_alloc< impl_type > A2;
239 
240 #else
241 
242         typedef typename A::template rebind< impl_type >::other A2;
243 
244 #endif
245 
246         A2 a2( a );
247 
248 #ifndef BOOST_NO_EXCEPTIONS
249 
250         try
251         {
252 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
253 
254             impl_type * pi = std::allocator_traits<A2>::allocate( a2, 1 );
255             pi_ = pi;
256             std::allocator_traits<A2>::construct( a2, pi, p, d, a );
257 
258 #else
259 
260             pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
261             ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
262 
263 #endif
264         }
265         catch(...)
266         {
267             d( p );
268 
269             if( pi_ != 0 )
270             {
271                 a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
272             }
273 
274             throw;
275         }
276 
277 #else
278 
279 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
280 
281         impl_type * pi = std::allocator_traits<A2>::allocate( a2, 1 );
282         pi_ = pi;
283 
284 #else
285 
286         pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
287 
288 #endif
289 
290         if( pi_ != 0 )
291         {
292 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
293 
294             std::allocator_traits<A2>::construct( a2, pi, p, d, a );
295 
296 #else
297 
298             ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
299 
300 #endif
301         }
302         else
303         {
304             d( p );
305             pdalboost::throw_exception( std::bad_alloc() );
306         }
307 
308 #endif
309     }
310 
311 #if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
312 
shared_count(P p,sp_inplace_tag<D>,A a)313     template< class P, class D, class A > shared_count( P p, sp_inplace_tag< D >, A a ): pi_( 0 )
314 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
315         , id_(shared_count_id)
316 #endif
317     {
318         typedef sp_counted_impl_pda< P, D, A > impl_type;
319 
320 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
321 
322         typedef typename std::allocator_traits<A>::template rebind_alloc< impl_type > A2;
323 
324 #else
325 
326         typedef typename A::template rebind< impl_type >::other A2;
327 
328 #endif
329 
330         A2 a2( a );
331 
332 #ifndef BOOST_NO_EXCEPTIONS
333 
334         try
335         {
336 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
337 
338             impl_type * pi = std::allocator_traits<A2>::allocate( a2, 1 );
339             pi_ = pi;
340             std::allocator_traits<A2>::construct( a2, pi, p, a );
341 
342 #else
343 
344             pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
345             ::new( static_cast< void* >( pi_ ) ) impl_type( p, a );
346 
347 #endif
348         }
349         catch(...)
350         {
351             D::operator_fn( p );
352 
353             if( pi_ != 0 )
354             {
355                 a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
356             }
357 
358             throw;
359         }
360 
361 #else
362 
363 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
364 
365         impl_type * pi = std::allocator_traits<A2>::allocate( a2, 1 );
366         pi_ = pi;
367 
368 #else
369 
370         pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
371 
372 #endif
373 
374         if( pi_ != 0 )
375         {
376 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
377 
378             std::allocator_traits<A2>::construct( a2, pi, p, a );
379 
380 #else
381 
382             ::new( static_cast< void* >( pi_ ) ) impl_type( p, a );
383 
384 #endif
385         }
386         else
387         {
388             D::operator_fn( p );
389             pdalboost::throw_exception( std::bad_alloc() );
390         }
391 
392 #endif // #ifndef BOOST_NO_EXCEPTIONS
393     }
394 
395 #endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
396 
397 #ifndef BOOST_NO_AUTO_PTR
398 
399     // auto_ptr<Y> is special cased to provide the strong guarantee
400 
401     template<class Y>
shared_count(std::auto_ptr<Y> & r)402     explicit shared_count( std::auto_ptr<Y> & r ): pi_( new sp_counted_impl_p<Y>( r.get() ) )
403 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
404         , id_(shared_count_id)
405 #endif
406     {
407 #ifdef BOOST_NO_EXCEPTIONS
408 
409         if( pi_ == 0 )
410         {
411             pdalboost::throw_exception(std::bad_alloc());
412         }
413 
414 #endif
415 
416         r.release();
417     }
418 
419 #endif
420 
421 #if !defined( BOOST_NO_CXX11_SMART_PTR )
422 
423     template<class Y, class D>
shared_count(std::unique_ptr<Y,D> & r)424     explicit shared_count( std::unique_ptr<Y, D> & r ): pi_( 0 )
425 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
426         , id_(shared_count_id)
427 #endif
428     {
429         typedef typename sp_convert_reference<D>::type D2;
430 
431         D2 d2( r.get_deleter() );
432         pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
433 
434 #ifdef BOOST_NO_EXCEPTIONS
435 
436         if( pi_ == 0 )
437         {
438             pdalboost::throw_exception( std::bad_alloc() );
439         }
440 
441 #endif
442 
443         r.release();
444     }
445 
446 #endif
447 
448     template<class Y, class D>
shared_count(pdalboost::movelib::unique_ptr<Y,D> & r)449     explicit shared_count( pdalboost::movelib::unique_ptr<Y, D> & r ): pi_( 0 )
450 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
451         , id_(shared_count_id)
452 #endif
453     {
454         typedef typename sp_convert_reference<D>::type D2;
455 
456         D2 d2( r.get_deleter() );
457         pi_ = new sp_counted_impl_pd< typename pdalboost::movelib::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
458 
459 #ifdef BOOST_NO_EXCEPTIONS
460 
461         if( pi_ == 0 )
462         {
463             pdalboost::throw_exception( std::bad_alloc() );
464         }
465 
466 #endif
467 
468         r.release();
469     }
470 
~shared_count()471     ~shared_count() // nothrow
472     {
473         if( pi_ != 0 ) pi_->release();
474 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
475         id_ = 0;
476 #endif
477     }
478 
shared_count(shared_count const & r)479     shared_count(shared_count const & r): pi_(r.pi_) // nothrow
480 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
481         , id_(shared_count_id)
482 #endif
483     {
484         if( pi_ != 0 ) pi_->add_ref_copy();
485     }
486 
487 #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
488 
shared_count(shared_count && r)489     shared_count(shared_count && r): pi_(r.pi_) // nothrow
490 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
491         , id_(shared_count_id)
492 #endif
493     {
494         r.pi_ = 0;
495     }
496 
497 #endif
498 
499     explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
500     shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0
501 
operator =(shared_count const & r)502     shared_count & operator= (shared_count const & r) // nothrow
503     {
504         sp_counted_base * tmp = r.pi_;
505 
506         if( tmp != pi_ )
507         {
508             if( tmp != 0 ) tmp->add_ref_copy();
509             if( pi_ != 0 ) pi_->release();
510             pi_ = tmp;
511         }
512 
513         return *this;
514     }
515 
swap(shared_count & r)516     void swap(shared_count & r) // nothrow
517     {
518         sp_counted_base * tmp = r.pi_;
519         r.pi_ = pi_;
520         pi_ = tmp;
521     }
522 
use_count() const523     long use_count() const // nothrow
524     {
525         return pi_ != 0? pi_->use_count(): 0;
526     }
527 
unique() const528     bool unique() const // nothrow
529     {
530         return use_count() == 1;
531     }
532 
empty() const533     bool empty() const // nothrow
534     {
535         return pi_ == 0;
536     }
537 
operator ==(shared_count const & a,shared_count const & b)538     friend inline bool operator==(shared_count const & a, shared_count const & b)
539     {
540         return a.pi_ == b.pi_;
541     }
542 
operator <(shared_count const & a,shared_count const & b)543     friend inline bool operator<(shared_count const & a, shared_count const & b)
544     {
545         return std::less<sp_counted_base *>()( a.pi_, b.pi_ );
546     }
547 
get_deleter(sp_typeinfo const & ti) const548     void * get_deleter( sp_typeinfo const & ti ) const
549     {
550         return pi_? pi_->get_deleter( ti ): 0;
551     }
552 
get_untyped_deleter() const553     void * get_untyped_deleter() const
554     {
555         return pi_? pi_->get_untyped_deleter(): 0;
556     }
557 };
558 
559 
560 class weak_count
561 {
562 private:
563 
564     sp_counted_base * pi_;
565 
566 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
567     int id_;
568 #endif
569 
570     friend class shared_count;
571 
572 public:
573 
weak_count()574     weak_count(): pi_(0) // nothrow
575 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
576         , id_(weak_count_id)
577 #endif
578     {
579     }
580 
weak_count(shared_count const & r)581     weak_count(shared_count const & r): pi_(r.pi_) // nothrow
582 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
583         , id_(weak_count_id)
584 #endif
585     {
586         if(pi_ != 0) pi_->weak_add_ref();
587     }
588 
weak_count(weak_count const & r)589     weak_count(weak_count const & r): pi_(r.pi_) // nothrow
590 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
591         , id_(weak_count_id)
592 #endif
593     {
594         if(pi_ != 0) pi_->weak_add_ref();
595     }
596 
597 // Move support
598 
599 #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
600 
weak_count(weak_count && r)601     weak_count(weak_count && r): pi_(r.pi_) // nothrow
602 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
603         , id_(weak_count_id)
604 #endif
605     {
606         r.pi_ = 0;
607     }
608 
609 #endif
610 
~weak_count()611     ~weak_count() // nothrow
612     {
613         if(pi_ != 0) pi_->weak_release();
614 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
615         id_ = 0;
616 #endif
617     }
618 
operator =(shared_count const & r)619     weak_count & operator= (shared_count const & r) // nothrow
620     {
621         sp_counted_base * tmp = r.pi_;
622 
623         if( tmp != pi_ )
624         {
625             if(tmp != 0) tmp->weak_add_ref();
626             if(pi_ != 0) pi_->weak_release();
627             pi_ = tmp;
628         }
629 
630         return *this;
631     }
632 
operator =(weak_count const & r)633     weak_count & operator= (weak_count const & r) // nothrow
634     {
635         sp_counted_base * tmp = r.pi_;
636 
637         if( tmp != pi_ )
638         {
639             if(tmp != 0) tmp->weak_add_ref();
640             if(pi_ != 0) pi_->weak_release();
641             pi_ = tmp;
642         }
643 
644         return *this;
645     }
646 
swap(weak_count & r)647     void swap(weak_count & r) // nothrow
648     {
649         sp_counted_base * tmp = r.pi_;
650         r.pi_ = pi_;
651         pi_ = tmp;
652     }
653 
use_count() const654     long use_count() const // nothrow
655     {
656         return pi_ != 0? pi_->use_count(): 0;
657     }
658 
empty() const659     bool empty() const // nothrow
660     {
661         return pi_ == 0;
662     }
663 
operator ==(weak_count const & a,weak_count const & b)664     friend inline bool operator==(weak_count const & a, weak_count const & b)
665     {
666         return a.pi_ == b.pi_;
667     }
668 
operator <(weak_count const & a,weak_count const & b)669     friend inline bool operator<(weak_count const & a, weak_count const & b)
670     {
671         return std::less<sp_counted_base *>()(a.pi_, b.pi_);
672     }
673 };
674 
shared_count(weak_count const & r)675 inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )
676 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
677         , id_(shared_count_id)
678 #endif
679 {
680     if( pi_ == 0 || !pi_->add_ref_lock() )
681     {
682         pdalboost::throw_exception( pdalboost::bad_weak_ptr() );
683     }
684 }
685 
shared_count(weak_count const & r,sp_nothrow_tag)686 inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ )
687 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
688         , id_(shared_count_id)
689 #endif
690 {
691     if( pi_ != 0 && !pi_->add_ref_lock() )
692     {
693         pi_ = 0;
694     }
695 }
696 
697 } // namespace detail
698 
699 } // namespace pdalboost
700 
701 #if defined( BOOST_SP_DISABLE_DEPRECATED )
702 #pragma GCC diagnostic pop
703 #endif
704 
705 #ifdef __BORLANDC__
706 # pragma warn .8027     // Functions containing try are not expanded inline
707 #endif
708 
709 #endif  // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED
710