forked from boostorg/smart_ptr
Extracted intrusive_ref_counter from Boost.Log. The extracted version supports customizing the reference counter nature, two policies provided: thread_unsafe_counter and thread_safe_counter.
[SVN r85535]
This commit is contained in:
176
include/boost/smart_ptr/intrusive_ref_counter.hpp
Normal file
176
include/boost/smart_ptr/intrusive_ref_counter.hpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2013.
|
||||
* 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)
|
||||
*/
|
||||
/*!
|
||||
* \file intrusive_ref_counter.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 12.03.2009
|
||||
*
|
||||
* This header contains a reference counter class for \c intrusive_ptr.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_
|
||||
#define BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/smart_ptr/detail/atomic_count.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace sp_adl_block {
|
||||
|
||||
/*!
|
||||
* \brief Thread unsafe reference counter policy for \c basic_intrusive_ref_counter
|
||||
*
|
||||
* The policy instructs the \c basic_intrusive_ref_counter base class to implement
|
||||
* a reference counter suitable for single threaded use only. Pointers to the same
|
||||
* object with this kind of reference counter must not be used by different threads.
|
||||
*/
|
||||
struct thread_unsafe_counter
|
||||
{
|
||||
typedef unsigned int type;
|
||||
|
||||
static unsigned int load(unsigned int const& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void increment(unsigned int& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
++counter;
|
||||
}
|
||||
|
||||
static unsigned int decrement(unsigned int& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
return --counter;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Thread safe reference counter policy for \c basic_intrusive_ref_counter
|
||||
*
|
||||
* The policy instructs the \c basic_intrusive_ref_counter base class to implement
|
||||
* a thread-safe reference counter, if the target platform supports multithreading.
|
||||
*/
|
||||
struct thread_safe_counter
|
||||
{
|
||||
typedef boost::detail::atomic_count type;
|
||||
|
||||
static unsigned int load(boost::detail::atomic_count const& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
return static_cast< unsigned int >(static_cast< long >(counter));
|
||||
}
|
||||
|
||||
static void increment(boost::detail::atomic_count& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
++counter;
|
||||
}
|
||||
|
||||
static unsigned int decrement(boost::detail::atomic_count& counter) BOOST_NOEXCEPT
|
||||
{
|
||||
return --counter;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename CounterPolicyT >
|
||||
class basic_intrusive_ref_counter;
|
||||
|
||||
template< typename CounterPolicyT >
|
||||
void intrusive_ptr_add_ref(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT;
|
||||
template< typename CounterPolicyT >
|
||||
void intrusive_ptr_release(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT;
|
||||
|
||||
/*!
|
||||
* \brief A reference counter base class
|
||||
*
|
||||
* This base class can be used with user-defined classes to add support
|
||||
* for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT
|
||||
* and a virtual destructor, which makes the derived class polymorphic.
|
||||
* Upon releasing the last \c intrusive_ptr referencing the object
|
||||
* derived from the \c basic_intrusive_ref_counter class, operator \c delete
|
||||
* is automatically called on the pointer to the object.
|
||||
*/
|
||||
template< typename CounterPolicyT >
|
||||
class basic_intrusive_ref_counter
|
||||
{
|
||||
private:
|
||||
//! Reference counter type
|
||||
typedef typename CounterPolicyT::type counter_type;
|
||||
//! Reference counter
|
||||
mutable counter_type m_ref_counter;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor
|
||||
*
|
||||
* \post <tt>use_count() == 0</tt>
|
||||
*/
|
||||
basic_intrusive_ref_counter() : m_ref_counter(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Copy constructor
|
||||
*
|
||||
* \post <tt>use_count() == 0</tt>
|
||||
*/
|
||||
basic_intrusive_ref_counter(basic_intrusive_ref_counter const&) : m_ref_counter(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~basic_intrusive_ref_counter() {}
|
||||
|
||||
/*!
|
||||
* Assignment
|
||||
*
|
||||
* \post The reference counter is not modified after assignment
|
||||
*/
|
||||
basic_intrusive_ref_counter& operator= (basic_intrusive_ref_counter const&) BOOST_NOEXCEPT { return *this; }
|
||||
|
||||
/*!
|
||||
* \return The reference counter
|
||||
*/
|
||||
unsigned int use_count() const BOOST_NOEXCEPT
|
||||
{
|
||||
return CounterPolicyT::load(m_ref_counter);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_add_ref< CounterPolicyT >(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT;
|
||||
friend void intrusive_ptr_release< CounterPolicyT >(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
template< typename CounterPolicyT >
|
||||
inline void intrusive_ptr_add_ref(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT
|
||||
{
|
||||
CounterPolicyT::increment(p->m_ref_counter);
|
||||
}
|
||||
|
||||
template< typename CounterPolicyT >
|
||||
inline void intrusive_ptr_release(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT
|
||||
{
|
||||
if (CounterPolicyT::decrement(p->m_ref_counter) == 0)
|
||||
delete p;
|
||||
}
|
||||
|
||||
} // namespace sp_adl_block
|
||||
|
||||
using sp_adl_block::basic_intrusive_ref_counter;
|
||||
using sp_adl_block::thread_unsafe_counter;
|
||||
using sp_adl_block::thread_safe_counter;
|
||||
|
||||
//! Convenience typedef for the default reference counter type
|
||||
typedef basic_intrusive_ref_counter< thread_safe_counter > intrusive_ref_counter;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_
|
@ -24,7 +24,9 @@
|
||||
compilers that support argument-dependent lookup, <STRONG>intrusive_ptr_add_ref</STRONG>
|
||||
and <STRONG>intrusive_ptr_release</STRONG> should be defined in the namespace
|
||||
that corresponds to their parameter; otherwise, the definitions need to go in
|
||||
namespace <STRONG>boost</STRONG>.</p>
|
||||
namespace <STRONG>boost</STRONG>. The library provides a helper base class template
|
||||
<STRONG><a href="intrusive_ref_counter.html">basic_intrusive_ref_counter</a></STRONG> which may
|
||||
help adding support for <STRONG>intrusive_ptr</STRONG> to user's types.</p>
|
||||
<p>The class template is parameterized on <b>T</b>, the type of the object pointed
|
||||
to. <STRONG>intrusive_ptr<T></STRONG> can be implicitly converted to <STRONG>intrusive_ptr<U></STRONG>
|
||||
whenever <STRONG>T*</STRONG> can be implicitly converted to <STRONG>U*</STRONG>.</p>
|
||||
|
92
intrusive_ref_counter.html
Normal file
92
intrusive_ref_counter.html
Normal file
@ -0,0 +1,92 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>basic_intrusive_ref_counter</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body text="#000000" bgColor="#ffffff">
|
||||
<h1><A href="../../index.htm"><IMG height="86" alt="boost.png (6897 bytes)" src="../../boost.png" width="277" align="middle"
|
||||
border="0"></A>basic_intrusive_ref_counter class template</h1>
|
||||
<p>
|
||||
<A href="#Introduction">Introduction</A><br>
|
||||
<A href="#Synopsis">Synopsis</A><br>
|
||||
<A href="#Members">Members</A><br>
|
||||
</p>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
<p>The <STRONG>basic_intrusive_ref_counter</STRONG> class template implements a reference counter for a defived
|
||||
user's class that is intended to be used with <STRONG><a href="intrusive_ptr.html">intrusive_ptr</a></STRONG>.
|
||||
The base class has associated <STRONG>intrusive_ptr_add_ref</STRONG> and <STRONG>intrusive_ptr_release</STRONG> functions
|
||||
which modify the reference counter as needed and destroy the user's object when the counter drops to zero.</p>
|
||||
<p>The class template is parameterized on <STRONG>CounterPolicyT</STRONG>, which is a policy that defines the nature of the reference counter.
|
||||
Boost.SmartPtr provides two such policies: <STRONG>thread_unsafe_counter</STRONG> and <STRONG>thread_safe_counter</STRONG>. The former
|
||||
instructs the <STRONG>basic_intrusive_ref_counter</STRONG> base class to use a counter only suitable for a single-threaded use.
|
||||
Pointers to a single object that uses this kind of reference counter must not be used in different threads. The latter policy
|
||||
makes the reference counter thread-safe, unless the target platform doesn't support threading. Since in modern systems support for
|
||||
threading is common, a shorthand <STRONG>intrusive_ref_counter</STRONG> is provided, which is an alias for
|
||||
<STRONG>basic_intrusive_ref_counter<thread_safe_counter></STRONG>.</p>
|
||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
||||
<pre>namespace boost {
|
||||
|
||||
template<class CounterPolicyT> class basic_intrusive_ref_counter {
|
||||
|
||||
public:
|
||||
|
||||
<A href="#constructors" >basic_intrusive_ref_counter</A>();
|
||||
<A href="#constructors" >basic_intrusive_ref_counter</A>(basic_intrusive_ref_counter const & r);
|
||||
|
||||
virtual <A href="#destructor" >~basic_intrusive_ref_counter</A>();
|
||||
|
||||
basic_intrusive_ref_counter & <A href="#assignment" >operator=</A>(basic_intrusive_ref_counter const & r) noexcept;
|
||||
|
||||
unsigned int <a href="#use_count" >use_count</a>() const noexcept;
|
||||
};
|
||||
|
||||
struct thread_unsafe_counter;
|
||||
struct thread_safe_counter;
|
||||
|
||||
typedef basic_intrusive_ref_counter<thread_safe_counter> intrusive_ref_counter;
|
||||
|
||||
}</pre>
|
||||
<h2><a name="Members">Members</a></h2>
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<pre>basic_intrusive_ref_counter();</pre>
|
||||
<blockquote>
|
||||
<p><b>Postconditions:</b> <code>use_count() == 0</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> The pointer to the constructed object is expected to be passed to <STRONG>intrusive_ptr</STRONG>
|
||||
constructor, assignment operator or <STRONG>reset()</STRONG> method, which would increment the reference counter.</P>
|
||||
</blockquote>
|
||||
<pre>basic_intrusive_ref_counter(basic_intrusive_ref_counter const &);</pre>
|
||||
<blockquote>
|
||||
<p><b>Postconditions:</b> <code>use_count() == 0</code>.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> The pointer to the constructed object is expected to be passed to <STRONG>intrusive_ptr</STRONG>
|
||||
constructor, assignment operator or <STRONG>reset()</STRONG> method, which would increment the reference counter.</P>
|
||||
</blockquote>
|
||||
<h3><a name="destructor">destructor</a></h3>
|
||||
<pre>virtual ~basic_intrusive_ref_counter();</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Destroys the counter object.</P>
|
||||
</BLOCKQUOTE>
|
||||
<H3><a name="assignment">assignment</a></H3>
|
||||
<pre>basic_intrusive_ref_counter & operator=(basic_intrusive_ref_counter const & r) noexcept;</pre>
|
||||
<BLOCKQUOTE>
|
||||
<P><B>Effects:</B> Does nothing, reference counter is not modified.</P>
|
||||
<P><B>Returns:</B> <code>*this</code>.</P>
|
||||
</BLOCKQUOTE>
|
||||
<H3><a name="use_count">use_count</a></H3>
|
||||
<pre>unsigned int use_count() const noexcept;</pre>
|
||||
<BLOCKQUOTE>
|
||||
<p><b>Returns:</b> The current value of the reference counter.</p>
|
||||
<p><b>Throws:</b> nothing.</p>
|
||||
<P><B>Notes:</B> The returned value may not be actual in multi-threaded applications.</P>
|
||||
</BLOCKQUOTE>
|
||||
<hr>
|
||||
<p>
|
||||
$Date: 2013-08-31 23:37:43 +0400 (Sat, 31 Aug 2013) $</p>
|
||||
<p>
|
||||
<small>Copyright <20> 2013 Andrey Semashev. Distributed under the Boost Software License, Version
|
||||
1.0. See accompanying file <A href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</A> or
|
||||
copy at <A href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</A>.</small></p>
|
||||
</body>
|
||||
</html>
|
@ -21,6 +21,7 @@ import testing ;
|
||||
[ run get_deleter_test.cpp ]
|
||||
[ run intrusive_ptr_test.cpp ]
|
||||
[ run intrusive_ptr_move_test.cpp ]
|
||||
[ run intrusive_ref_counter_test.cpp ]
|
||||
[ run atomic_count_test.cpp ]
|
||||
[ run lw_mutex_test.cpp ]
|
||||
[ compile-fail shared_ptr_assign_fail.cpp ]
|
||||
|
146
test/intrusive_ref_counter_test.cpp
Normal file
146
test/intrusive_ref_counter_test.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2013.
|
||||
* 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)
|
||||
*/
|
||||
/*!
|
||||
* \file intrusive_ref_counter_test.cpp
|
||||
* \author Andrey Semashev
|
||||
* \date 31.08.2013
|
||||
*
|
||||
* This file contains tests for the \c intrusive_ref_counter base class.
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
|
||||
#pragma warning(disable: 4786) // identifier truncated in debug info
|
||||
#pragma warning(disable: 4710) // function not inlined
|
||||
#pragma warning(disable: 4711) // function selected for automatic inline expansion
|
||||
#pragma warning(disable: 4514) // unreferenced inline removed
|
||||
#pragma warning(disable: 4355) // 'this' : used in base member initializer list
|
||||
#pragma warning(disable: 4511) // copy constructor could not be generated
|
||||
#pragma warning(disable: 4512) // assignment operator could not be generated
|
||||
|
||||
#if (BOOST_MSVC >= 1310)
|
||||
#pragma warning(disable: 4675) // resolved overload found with Koenig lookup
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
namespace N1 {
|
||||
|
||||
class my_class :
|
||||
public boost::intrusive_ref_counter
|
||||
{
|
||||
public:
|
||||
static unsigned int destructor_count;
|
||||
|
||||
~my_class()
|
||||
{
|
||||
++destructor_count;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int my_class::destructor_count = 0;
|
||||
|
||||
} // namespace N1
|
||||
|
||||
namespace N2 {
|
||||
|
||||
class my_class :
|
||||
public boost::basic_intrusive_ref_counter< boost::thread_unsafe_counter >
|
||||
{
|
||||
public:
|
||||
static unsigned int destructor_count;
|
||||
|
||||
~my_class()
|
||||
{
|
||||
++destructor_count;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int my_class::destructor_count = 0;
|
||||
|
||||
} // namespace N2
|
||||
|
||||
namespace N3 {
|
||||
|
||||
struct X :
|
||||
public virtual boost::intrusive_ref_counter
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace N3
|
||||
|
||||
namespace N4 {
|
||||
|
||||
struct Y :
|
||||
public virtual boost::intrusive_ref_counter
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace N4
|
||||
|
||||
namespace N5 {
|
||||
|
||||
struct Z :
|
||||
public N3::X,
|
||||
public N4::Y
|
||||
{
|
||||
static unsigned int destructor_count;
|
||||
|
||||
~Z()
|
||||
{
|
||||
++destructor_count;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int Z::destructor_count = 0;
|
||||
|
||||
} // namespace N5
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// The test check that ADL works
|
||||
{
|
||||
boost::intrusive_ptr< N1::my_class > p = new N1::my_class();
|
||||
p = NULL;
|
||||
BOOST_TEST(N1::my_class::destructor_count == 1);
|
||||
}
|
||||
{
|
||||
boost::intrusive_ptr< N2::my_class > p = new N2::my_class();
|
||||
p = NULL;
|
||||
BOOST_TEST(N2::my_class::destructor_count == 1);
|
||||
}
|
||||
{
|
||||
N1::my_class* p = new N1::my_class();
|
||||
intrusive_ptr_add_ref(p);
|
||||
intrusive_ptr_release(p);
|
||||
BOOST_TEST(N1::my_class::destructor_count == 2);
|
||||
}
|
||||
|
||||
// The test checks that destroying through the base class works
|
||||
{
|
||||
boost::intrusive_ptr< N5::Z > p1 = new N5::Z();
|
||||
BOOST_TEST(p1->use_count() == 1);
|
||||
BOOST_TEST(N5::Z::destructor_count == 0);
|
||||
boost::intrusive_ptr< boost::intrusive_ref_counter > p2 = p1;
|
||||
BOOST_TEST(p1->use_count() == 2);
|
||||
BOOST_TEST(N5::Z::destructor_count == 0);
|
||||
p1 = NULL;
|
||||
BOOST_TEST(N5::Z::destructor_count == 0);
|
||||
p2 = NULL;
|
||||
BOOST_TEST(N5::Z::destructor_count == 1);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user