You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
569 lines
12 KiB
569 lines
12 KiB
#ifndef BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED |
|
#define BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED |
|
|
|
// MS compatible compilers support #pragma once |
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1020) |
|
# pragma once |
|
#endif |
|
|
|
// |
|
// detail/shared_count.hpp |
|
// |
|
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. |
|
// |
|
// Distributed under the Boost Software License, Version 1.0. (See |
|
// accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
|
|
#include <boost/config.hpp> |
|
|
|
#if defined(BOOST_SP_USE_STD_ALLOCATOR) && defined(BOOST_SP_USE_QUICK_ALLOCATOR) |
|
# error BOOST_SP_USE_STD_ALLOCATOR and BOOST_SP_USE_QUICK_ALLOCATOR are incompatible. |
|
#endif |
|
|
|
#include <boost/checked_delete.hpp> |
|
#include <boost/serialization/throw_exception.hpp> |
|
#include <boost/detail/lightweight_mutex.hpp> |
|
|
|
#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) |
|
#include <boost/detail/quick_allocator.hpp> |
|
#endif |
|
|
|
#include <memory> // std::auto_ptr, std::allocator |
|
#include <functional> // std::less |
|
#include <exception> // std::exception |
|
#include <new> // std::bad_alloc |
|
#include <typeinfo> // std::type_info in get_deleter |
|
#include <cstddef> // std::size_t |
|
|
|
#include <boost/config.hpp> // msvc 6.0 needs this for warning suppression |
|
#if defined(BOOST_NO_STDC_NAMESPACE) |
|
namespace std{ |
|
using ::size_t; |
|
} // namespace std |
|
#endif |
|
|
|
#ifdef __BORLANDC__ |
|
# pragma warn -8026 // Functions with excep. spec. are not expanded inline |
|
# pragma warn -8027 // Functions containing try are not expanded inline |
|
#endif |
|
|
|
namespace boost_132 { |
|
|
|
// Debug hooks |
|
|
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
|
|
void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn); |
|
void sp_array_constructor_hook(void * px); |
|
void sp_scalar_destructor_hook(void * px, std::size_t size, void * pn); |
|
void sp_array_destructor_hook(void * px); |
|
|
|
#endif |
|
|
|
|
|
// The standard library that comes with Borland C++ 5.5.1 |
|
// defines std::exception and its members as having C calling |
|
// convention (-pc). When the definition of bad_weak_ptr |
|
// is compiled with -ps, the compiler issues an error. |
|
// Hence, the temporary #pragma option -pc below. The version |
|
// check is deliberately conservative. |
|
|
|
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 |
|
# pragma option push -pc |
|
#endif |
|
|
|
class bad_weak_ptr: public std::exception |
|
{ |
|
public: |
|
|
|
virtual char const * what() const throw() |
|
{ |
|
return "boost::bad_weak_ptr"; |
|
} |
|
}; |
|
|
|
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 |
|
# pragma option pop |
|
#endif |
|
|
|
namespace detail{ |
|
|
|
class sp_counted_base |
|
{ |
|
//private: |
|
|
|
typedef boost::detail::lightweight_mutex mutex_type; |
|
|
|
public: |
|
|
|
sp_counted_base(): use_count_(1), weak_count_(1) |
|
{ |
|
} |
|
|
|
virtual ~sp_counted_base() // nothrow |
|
{ |
|
} |
|
|
|
// dispose() is called when use_count_ drops to zero, to release |
|
// the resources managed by *this. |
|
|
|
virtual void dispose() = 0; // nothrow |
|
|
|
// destruct() is called when weak_count_ drops to zero. |
|
|
|
virtual void destruct() // nothrow |
|
{ |
|
delete this; |
|
} |
|
|
|
virtual void * get_deleter(std::type_info const & ti) = 0; |
|
|
|
void add_ref_copy() |
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
++use_count_; |
|
} |
|
|
|
void add_ref_lock() |
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
if(use_count_ == 0) boost::serialization::throw_exception(bad_weak_ptr()); |
|
++use_count_; |
|
} |
|
|
|
void release() // nothrow |
|
{ |
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
long new_use_count = --use_count_; |
|
|
|
if(new_use_count != 0) return; |
|
} |
|
|
|
dispose(); |
|
weak_release(); |
|
} |
|
|
|
void weak_add_ref() // nothrow |
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
++weak_count_; |
|
} |
|
|
|
void weak_release() // nothrow |
|
{ |
|
long new_weak_count; |
|
|
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
new_weak_count = --weak_count_; |
|
} |
|
|
|
if(new_weak_count == 0) |
|
{ |
|
destruct(); |
|
} |
|
} |
|
|
|
long use_count() const // nothrow |
|
{ |
|
#if defined(BOOST_HAS_THREADS) |
|
mutex_type::scoped_lock lock(mtx_); |
|
#endif |
|
return use_count_; |
|
} |
|
|
|
//private: |
|
public: |
|
sp_counted_base(sp_counted_base const &); |
|
sp_counted_base & operator= (sp_counted_base const &); |
|
|
|
long use_count_; // #shared |
|
long weak_count_; // #weak + (#shared != 0) |
|
|
|
#if defined(BOOST_HAS_THREADS) || defined(BOOST_LWM_WIN32) |
|
mutable mutex_type mtx_; |
|
#endif |
|
}; |
|
|
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
|
|
template<class T> void cbi_call_constructor_hook(sp_counted_base * pn, T * px, checked_deleter< T > const &, int) |
|
{ |
|
boost::sp_scalar_constructor_hook(px, sizeof(T), pn); |
|
} |
|
|
|
template<class T> void cbi_call_constructor_hook(sp_counted_base *, T * px, checked_array_deleter< T > const &, int) |
|
{ |
|
boost::sp_array_constructor_hook(px); |
|
} |
|
|
|
template<class P, class D> void cbi_call_constructor_hook(sp_counted_base *, P const &, D const &, long) |
|
{ |
|
} |
|
|
|
template<class T> void cbi_call_destructor_hook(sp_counted_base * pn, T * px, checked_deleter< T > const &, int) |
|
{ |
|
boost::sp_scalar_destructor_hook(px, sizeof(T), pn); |
|
} |
|
|
|
template<class T> void cbi_call_destructor_hook(sp_counted_base *, T * px, checked_array_deleter< T > const &, int) |
|
{ |
|
boost::sp_array_destructor_hook(px); |
|
} |
|
|
|
template<class P, class D> void cbi_call_destructor_hook(sp_counted_base *, P const &, D const &, long) |
|
{ |
|
} |
|
|
|
#endif |
|
|
|
// |
|
// Borland's Codeguard trips up over the -Vx- option here: |
|
// |
|
#ifdef __CODEGUARD__ |
|
# pragma option push -Vx- |
|
#endif |
|
|
|
template<class P, class D> class sp_counted_base_impl: public sp_counted_base |
|
{ |
|
//private: |
|
public: |
|
P ptr; // copy constructor must not throw |
|
D del; // copy constructor must not throw |
|
|
|
sp_counted_base_impl(sp_counted_base_impl const &); |
|
sp_counted_base_impl & operator= (sp_counted_base_impl const &); |
|
|
|
typedef sp_counted_base_impl<P, D> this_type; |
|
|
|
public: |
|
|
|
// pre: initial_use_count <= initial_weak_count, d(p) must not throw |
|
|
|
sp_counted_base_impl(P p, D d): ptr(p), del(d) |
|
{ |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
detail::cbi_call_constructor_hook(this, p, d, 0); |
|
#endif |
|
} |
|
|
|
virtual void dispose() // nothrow |
|
{ |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
detail::cbi_call_destructor_hook(this, ptr, del, 0); |
|
#endif |
|
del(ptr); |
|
} |
|
|
|
virtual void * get_deleter(std::type_info const & ti) |
|
{ |
|
return ti == typeid(D)? &del: 0; |
|
} |
|
|
|
#if defined(BOOST_SP_USE_STD_ALLOCATOR) |
|
|
|
void * operator new(std::size_t) |
|
{ |
|
return std::allocator<this_type>().allocate(1, static_cast<this_type *>(0)); |
|
} |
|
|
|
void operator delete(void * p) |
|
{ |
|
std::allocator<this_type>().deallocate(static_cast<this_type *>(p), 1); |
|
} |
|
|
|
#endif |
|
|
|
#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) |
|
|
|
void * operator new(std::size_t) |
|
{ |
|
return boost::detail::quick_allocator<this_type>::alloc(); |
|
} |
|
|
|
void operator delete(void * p) |
|
{ |
|
boost::detail::quick_allocator<this_type>::dealloc(p); |
|
} |
|
|
|
#endif |
|
}; |
|
|
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
|
|
int const shared_count_id = 0x2C35F101; |
|
int const weak_count_id = 0x298C38A4; |
|
|
|
#endif |
|
|
|
class weak_count; |
|
|
|
class shared_count |
|
{ |
|
//private: |
|
public: |
|
sp_counted_base * pi_; |
|
|
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
int id_; |
|
#endif |
|
|
|
friend class weak_count; |
|
|
|
public: |
|
|
|
shared_count(): pi_(0) // nothrow |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
} |
|
|
|
template<class P, class D> shared_count(P p, D d): pi_(0) |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
#ifndef BOOST_NO_EXCEPTIONS |
|
|
|
try |
|
{ |
|
pi_ = new sp_counted_base_impl<P, D>(p, d); |
|
} |
|
catch(...) |
|
{ |
|
d(p); // delete p |
|
throw; |
|
} |
|
|
|
#else |
|
|
|
pi_ = new sp_counted_base_impl<P, D>(p, d); |
|
|
|
if(pi_ == 0) |
|
{ |
|
d(p); // delete p |
|
boost::serialization::throw_exception(std::bad_alloc()); |
|
} |
|
|
|
#endif |
|
} |
|
|
|
#ifndef BOOST_NO_AUTO_PTR |
|
|
|
// auto_ptr<Y> is special cased to provide the strong guarantee |
|
|
|
template<class Y> |
|
explicit shared_count(std::auto_ptr<Y> & r): pi_( |
|
new sp_counted_base_impl< |
|
Y *, |
|
boost::checked_deleter<Y> |
|
>(r.get(), boost::checked_deleter<Y>())) |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
r.release(); |
|
} |
|
|
|
#endif |
|
|
|
~shared_count() // nothrow |
|
{ |
|
if(pi_ != 0) pi_->release(); |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
id_ = 0; |
|
#endif |
|
} |
|
|
|
shared_count(shared_count const & r): pi_(r.pi_) // nothrow |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
if(pi_ != 0) pi_->add_ref_copy(); |
|
} |
|
|
|
explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 |
|
|
|
shared_count & operator= (shared_count const & r) // nothrow |
|
{ |
|
sp_counted_base * tmp = r.pi_; |
|
|
|
if(tmp != pi_) |
|
{ |
|
if(tmp != 0) tmp->add_ref_copy(); |
|
if(pi_ != 0) pi_->release(); |
|
pi_ = tmp; |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
void swap(shared_count & r) // nothrow |
|
{ |
|
sp_counted_base * tmp = r.pi_; |
|
r.pi_ = pi_; |
|
pi_ = tmp; |
|
} |
|
|
|
long use_count() const // nothrow |
|
{ |
|
return pi_ != 0? pi_->use_count(): 0; |
|
} |
|
|
|
bool unique() const // nothrow |
|
{ |
|
return use_count() == 1; |
|
} |
|
|
|
friend inline bool operator==(shared_count const & a, shared_count const & b) |
|
{ |
|
return a.pi_ == b.pi_; |
|
} |
|
|
|
friend inline bool operator<(shared_count const & a, shared_count const & b) |
|
{ |
|
return std::less<sp_counted_base *>()(a.pi_, b.pi_); |
|
} |
|
|
|
void * get_deleter(std::type_info const & ti) const |
|
{ |
|
return pi_? pi_->get_deleter(ti): 0; |
|
} |
|
}; |
|
|
|
#ifdef __CODEGUARD__ |
|
# pragma option pop |
|
#endif |
|
|
|
|
|
class weak_count |
|
{ |
|
private: |
|
|
|
sp_counted_base * pi_; |
|
|
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
int id_; |
|
#endif |
|
|
|
friend class shared_count; |
|
|
|
public: |
|
|
|
weak_count(): pi_(0) // nothrow |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(weak_count_id) |
|
#endif |
|
{ |
|
} |
|
|
|
weak_count(shared_count const & r): pi_(r.pi_) // nothrow |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
if(pi_ != 0) pi_->weak_add_ref(); |
|
} |
|
|
|
weak_count(weak_count const & r): pi_(r.pi_) // nothrow |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
if(pi_ != 0) pi_->weak_add_ref(); |
|
} |
|
|
|
~weak_count() // nothrow |
|
{ |
|
if(pi_ != 0) pi_->weak_release(); |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
id_ = 0; |
|
#endif |
|
} |
|
|
|
weak_count & operator= (shared_count const & r) // nothrow |
|
{ |
|
sp_counted_base * tmp = r.pi_; |
|
if(tmp != 0) tmp->weak_add_ref(); |
|
if(pi_ != 0) pi_->weak_release(); |
|
pi_ = tmp; |
|
|
|
return *this; |
|
} |
|
|
|
weak_count & operator= (weak_count const & r) // nothrow |
|
{ |
|
sp_counted_base * tmp = r.pi_; |
|
if(tmp != 0) tmp->weak_add_ref(); |
|
if(pi_ != 0) pi_->weak_release(); |
|
pi_ = tmp; |
|
|
|
return *this; |
|
} |
|
|
|
void swap(weak_count & r) // nothrow |
|
{ |
|
sp_counted_base * tmp = r.pi_; |
|
r.pi_ = pi_; |
|
pi_ = tmp; |
|
} |
|
|
|
long use_count() const // nothrow |
|
{ |
|
return pi_ != 0? pi_->use_count(): 0; |
|
} |
|
|
|
friend inline bool operator==(weak_count const & a, weak_count const & b) |
|
{ |
|
return a.pi_ == b.pi_; |
|
} |
|
|
|
friend inline bool operator<(weak_count const & a, weak_count const & b) |
|
{ |
|
return std::less<sp_counted_base *>()(a.pi_, b.pi_); |
|
} |
|
}; |
|
|
|
inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) |
|
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) |
|
, id_(shared_count_id) |
|
#endif |
|
{ |
|
if(pi_ != 0) |
|
{ |
|
pi_->add_ref_lock(); |
|
} |
|
else |
|
{ |
|
boost::serialization::throw_exception(bad_weak_ptr()); |
|
} |
|
} |
|
|
|
} // namespace detail |
|
|
|
} // namespace boost |
|
|
|
BOOST_SERIALIZATION_ASSUME_ABSTRACT(boost_132::detail::sp_counted_base) |
|
|
|
#ifdef __BORLANDC__ |
|
# pragma warn .8027 // Functions containing try are not expanded inline |
|
# pragma warn .8026 // Functions with excep. spec. are not expanded inline |
|
#endif |
|
|
|
#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
|
|
|