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