blob: f7235848b4c5a5b3ff7bc168d46f82bc562a9768 [file] [log] [blame]
Jeff Thompsonf7d49942013-08-01 16:47:40 -07001#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
Jeff Thompson2277ce52013-08-01 17:34:11 -070025#include <ndnboost/config.hpp>
26#include <ndnboost/checked_delete.hpp>
27#include <ndnboost/throw_exception.hpp>
28#include <ndnboost/smart_ptr/bad_weak_ptr.hpp>
29#include <ndnboost/smart_ptr/detail/sp_counted_base.hpp>
30#include <ndnboost/smart_ptr/detail/sp_counted_impl.hpp>
31#include <ndnboost/detail/workaround.hpp>
Jeff Thompsonf7d49942013-08-01 16:47:40 -070032// 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:
Jeff Thompson2277ce52013-08-01 17:34:11 -070036#include <ndnboost/config/no_tr1/memory.hpp> // std::auto_ptr
Jeff Thompsonf7d49942013-08-01 16:47:40 -070037#include <functional> // std::less
38
39#ifdef BOOST_NO_EXCEPTIONS
40# include <new> // std::bad_alloc
41#endif
42
43#if !defined( BOOST_NO_CXX11_SMART_PTR )
Jeff Thompson2277ce52013-08-01 17:34:11 -070044# include <ndnboost/utility/addressof.hpp>
Jeff Thompsonf7d49942013-08-01 16:47:40 -070045#endif
46
47namespace ndnboost
48{
49
50namespace detail
51{
52
53#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
54
55int const shared_count_id = 0x2C35F101;
56int const weak_count_id = 0x298C38A4;
57
58#endif
59
60struct sp_nothrow_tag {};
61
62template< class D > struct sp_inplace_tag
63{
64};
65
66#if !defined( BOOST_NO_CXX11_SMART_PTR )
67
68template< class T > class sp_reference_wrapper
69{
70public:
71
72 explicit sp_reference_wrapper( T & t): t_( ndnboost::addressof( t ) )
73 {
74 }
75
76 template< class Y > void operator()( Y * p ) const
77 {
78 (*t_)( p );
79 }
80
81private:
82
83 T * t_;
84};
85
86template< class D > struct sp_convert_reference
87{
88 typedef D type;
89};
90
91template< class D > struct sp_convert_reference< D& >
92{
93 typedef sp_reference_wrapper< D > type;
94};
95
96#endif
97
98class weak_count;
99
100class shared_count
101{
102private:
103
104 sp_counted_base * pi_;
105
106#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
107 int id_;
108#endif
109
110 friend class weak_count;
111
112public:
113
114 shared_count(): pi_(0) // nothrow
115#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
116 , id_(shared_count_id)
117#endif
118 {
119 }
120
121 template<class Y> explicit shared_count( Y * p ): pi_( 0 )
122#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
123 , id_(shared_count_id)
124#endif
125 {
126#ifndef BOOST_NO_EXCEPTIONS
127
128 try
129 {
130 pi_ = new sp_counted_impl_p<Y>( p );
131 }
132 catch(...)
133 {
134 ndnboost::checked_delete( p );
135 throw;
136 }
137
138#else
139
140 pi_ = new sp_counted_impl_p<Y>( p );
141
142 if( pi_ == 0 )
143 {
144 ndnboost::checked_delete( p );
145 ndnboost::throw_exception( std::bad_alloc() );
146 }
147
148#endif
149 }
150
151#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
152 template<class Y, class D> shared_count( Y * p, D d ): pi_(0)
153#else
154 template<class P, class D> shared_count( P p, D d ): pi_(0)
155#endif
156#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
157 , id_(shared_count_id)
158#endif
159 {
160#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 )
161 typedef Y* P;
162#endif
163#ifndef BOOST_NO_EXCEPTIONS
164
165 try
166 {
167 pi_ = new sp_counted_impl_pd<P, D>(p, d);
168 }
169 catch(...)
170 {
171 d(p); // delete p
172 throw;
173 }
174
175#else
176
177 pi_ = new sp_counted_impl_pd<P, D>(p, d);
178
179 if(pi_ == 0)
180 {
181 d(p); // delete p
182 ndnboost::throw_exception(std::bad_alloc());
183 }
184
185#endif
186 }
187
188#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
189
190 template< class P, class D > shared_count( P p, sp_inplace_tag<D> ): pi_( 0 )
191#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
192 , id_(shared_count_id)
193#endif
194 {
195#ifndef BOOST_NO_EXCEPTIONS
196
197 try
198 {
199 pi_ = new sp_counted_impl_pd< P, D >( p );
200 }
201 catch( ... )
202 {
Jeff Thompsona28eed82013-08-22 16:21:10 -0700203 D::operator_fn( p ); // delete p
Jeff Thompsonf7d49942013-08-01 16:47:40 -0700204 throw;
205 }
206
207#else
208
209 pi_ = new sp_counted_impl_pd< P, D >( p );
210
211 if( pi_ == 0 )
212 {
Jeff Thompsona28eed82013-08-22 16:21:10 -0700213 D::operator_fn( p ); // delete p
Jeff Thompsonf7d49942013-08-01 16:47:40 -0700214 ndnboost::throw_exception( std::bad_alloc() );
215 }
216
217#endif // #ifndef BOOST_NO_EXCEPTIONS
218 }
219
220#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
221
222 template<class P, class D, class A> shared_count( P p, D d, A a ): pi_( 0 )
223#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
224 , id_(shared_count_id)
225#endif
226 {
227 typedef sp_counted_impl_pda<P, D, A> impl_type;
228 typedef typename A::template rebind< impl_type >::other A2;
229
230 A2 a2( a );
231
232#ifndef BOOST_NO_EXCEPTIONS
233
234 try
235 {
236 pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
237 new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
238 }
239 catch(...)
240 {
241 d( p );
242
243 if( pi_ != 0 )
244 {
245 a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
246 }
247
248 throw;
249 }
250
251#else
252
253 pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
254
255 if( pi_ != 0 )
256 {
257 new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
258 }
259 else
260 {
261 d( p );
262 ndnboost::throw_exception( std::bad_alloc() );
263 }
264
265#endif
266 }
267
268#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
269
270 template< class P, class D, class A > shared_count( P p, sp_inplace_tag< D >, A a ): pi_( 0 )
271#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
272 , id_(shared_count_id)
273#endif
274 {
275 typedef sp_counted_impl_pda< P, D, A > impl_type;
276 typedef typename A::template rebind< impl_type >::other A2;
277
278 A2 a2( a );
279
280#ifndef BOOST_NO_EXCEPTIONS
281
282 try
283 {
284 pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
285 new( static_cast< void* >( pi_ ) ) impl_type( p, a );
286 }
287 catch(...)
288 {
Jeff Thompsona28eed82013-08-22 16:21:10 -0700289 D::operator_fn( p );
Jeff Thompsonf7d49942013-08-01 16:47:40 -0700290
291 if( pi_ != 0 )
292 {
293 a2.deallocate( static_cast< impl_type* >( pi_ ), 1 );
294 }
295
296 throw;
297 }
298
299#else
300
301 pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
302
303 if( pi_ != 0 )
304 {
305 new( static_cast< void* >( pi_ ) ) impl_type( p, a );
306 }
307 else
308 {
Jeff Thompsona28eed82013-08-22 16:21:10 -0700309 D::operator_fn( p );
Jeff Thompsonf7d49942013-08-01 16:47:40 -0700310 ndnboost::throw_exception( std::bad_alloc() );
311 }
312
313#endif // #ifndef BOOST_NO_EXCEPTIONS
314 }
315
316#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING )
317
318#ifndef BOOST_NO_AUTO_PTR
319
320 // auto_ptr<Y> is special cased to provide the strong guarantee
321
322 template<class Y>
323 explicit shared_count( std::auto_ptr<Y> & r ): pi_( new sp_counted_impl_p<Y>( r.get() ) )
324#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
325 , id_(shared_count_id)
326#endif
327 {
328#ifdef BOOST_NO_EXCEPTIONS
329
330 if( pi_ == 0 )
331 {
332 ndnboost::throw_exception(std::bad_alloc());
333 }
334
335#endif
336
337 r.release();
338 }
339
340#endif
341
342#if !defined( BOOST_NO_CXX11_SMART_PTR )
343
344 template<class Y, class D>
345 explicit shared_count( std::unique_ptr<Y, D> & r ): pi_( 0 )
346#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
347 , id_(shared_count_id)
348#endif
349 {
350 typedef typename sp_convert_reference<D>::type D2;
351
352 D2 d2( r.get_deleter() );
353 pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
354
355#ifdef BOOST_NO_EXCEPTIONS
356
357 if( pi_ == 0 )
358 {
359 ndnboost::throw_exception( std::bad_alloc() );
360 }
361
362#endif
363
364 r.release();
365 }
366
367#endif
368
369 ~shared_count() // nothrow
370 {
371 if( pi_ != 0 ) pi_->release();
372#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
373 id_ = 0;
374#endif
375 }
376
377 shared_count(shared_count const & r): pi_(r.pi_) // nothrow
378#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
379 , id_(shared_count_id)
380#endif
381 {
382 if( pi_ != 0 ) pi_->add_ref_copy();
383 }
384
385#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
386
387 shared_count(shared_count && r): pi_(r.pi_) // nothrow
388#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
389 , id_(shared_count_id)
390#endif
391 {
392 r.pi_ = 0;
393 }
394
395#endif
396
397 explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
398 shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0
399
400 shared_count & operator= (shared_count const & r) // nothrow
401 {
402 sp_counted_base * tmp = r.pi_;
403
404 if( tmp != pi_ )
405 {
406 if( tmp != 0 ) tmp->add_ref_copy();
407 if( pi_ != 0 ) pi_->release();
408 pi_ = tmp;
409 }
410
411 return *this;
412 }
413
414 void swap(shared_count & r) // nothrow
415 {
416 sp_counted_base * tmp = r.pi_;
417 r.pi_ = pi_;
418 pi_ = tmp;
419 }
420
421 long use_count() const // nothrow
422 {
423 return pi_ != 0? pi_->use_count(): 0;
424 }
425
426 bool unique() const // nothrow
427 {
428 return use_count() == 1;
429 }
430
431 bool empty() const // nothrow
432 {
433 return pi_ == 0;
434 }
435
436 friend inline bool operator==(shared_count const & a, shared_count const & b)
437 {
438 return a.pi_ == b.pi_;
439 }
440
441 friend inline bool operator<(shared_count const & a, shared_count const & b)
442 {
443 return std::less<sp_counted_base *>()( a.pi_, b.pi_ );
444 }
445
446 void * get_deleter( sp_typeinfo const & ti ) const
447 {
448 return pi_? pi_->get_deleter( ti ): 0;
449 }
450
451 void * get_untyped_deleter() const
452 {
453 return pi_? pi_->get_untyped_deleter(): 0;
454 }
455};
456
457
458class weak_count
459{
460private:
461
462 sp_counted_base * pi_;
463
464#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
465 int id_;
466#endif
467
468 friend class shared_count;
469
470public:
471
472 weak_count(): pi_(0) // nothrow
473#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
474 , id_(weak_count_id)
475#endif
476 {
477 }
478
479 weak_count(shared_count const & r): pi_(r.pi_) // nothrow
480#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
481 , id_(weak_count_id)
482#endif
483 {
484 if(pi_ != 0) pi_->weak_add_ref();
485 }
486
487 weak_count(weak_count const & r): pi_(r.pi_) // nothrow
488#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
489 , id_(weak_count_id)
490#endif
491 {
492 if(pi_ != 0) pi_->weak_add_ref();
493 }
494
495// Move support
496
497#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
498
499 weak_count(weak_count && r): pi_(r.pi_) // nothrow
500#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
501 , id_(weak_count_id)
502#endif
503 {
504 r.pi_ = 0;
505 }
506
507#endif
508
509 ~weak_count() // nothrow
510 {
511 if(pi_ != 0) pi_->weak_release();
512#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
513 id_ = 0;
514#endif
515 }
516
517 weak_count & operator= (shared_count const & r) // nothrow
518 {
519 sp_counted_base * tmp = r.pi_;
520
521 if( tmp != pi_ )
522 {
523 if(tmp != 0) tmp->weak_add_ref();
524 if(pi_ != 0) pi_->weak_release();
525 pi_ = tmp;
526 }
527
528 return *this;
529 }
530
531 weak_count & operator= (weak_count const & r) // nothrow
532 {
533 sp_counted_base * tmp = r.pi_;
534
535 if( tmp != pi_ )
536 {
537 if(tmp != 0) tmp->weak_add_ref();
538 if(pi_ != 0) pi_->weak_release();
539 pi_ = tmp;
540 }
541
542 return *this;
543 }
544
545 void swap(weak_count & r) // nothrow
546 {
547 sp_counted_base * tmp = r.pi_;
548 r.pi_ = pi_;
549 pi_ = tmp;
550 }
551
552 long use_count() const // nothrow
553 {
554 return pi_ != 0? pi_->use_count(): 0;
555 }
556
557 bool empty() const // nothrow
558 {
559 return pi_ == 0;
560 }
561
562 friend inline bool operator==(weak_count const & a, weak_count const & b)
563 {
564 return a.pi_ == b.pi_;
565 }
566
567 friend inline bool operator<(weak_count const & a, weak_count const & b)
568 {
569 return std::less<sp_counted_base *>()(a.pi_, b.pi_);
570 }
571};
572
573inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )
574#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
575 , id_(shared_count_id)
576#endif
577{
578 if( pi_ == 0 || !pi_->add_ref_lock() )
579 {
580 ndnboost::throw_exception( ndnboost::bad_weak_ptr() );
581 }
582}
583
584inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ )
585#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
586 , id_(shared_count_id)
587#endif
588{
589 if( pi_ != 0 && !pi_->add_ref_lock() )
590 {
591 pi_ = 0;
592 }
593}
594
595} // namespace detail
596
597} // namespace ndnboost
598
599#ifdef __BORLANDC__
600# pragma warn .8027 // Functions containing try are not expanded inline
601#endif
602
603#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED