From fc20a29c991e0b2e6be4b97a2c1e1c8bd304e1d4 Mon Sep 17 00:00:00 2001
From: Andrey Semashev
Date: Sun, 8 Sep 2013 17:17:18 +0000
Subject: [PATCH] Merged changes from trunk: added intrusive_ref_counter.
[SVN r85609]
---
.../boost/smart_ptr/intrusive_ref_counter.hpp | 187 ++++++++++++++++++
intrusive_ptr.html | 4 +-
intrusive_ref_counter.html | 95 +++++++++
test/Jamfile.v2 | 1 +
test/intrusive_ref_counter_test.cpp | 156 +++++++++++++++
5 files changed, 442 insertions(+), 1 deletion(-)
create mode 100644 include/boost/smart_ptr/intrusive_ref_counter.hpp
create mode 100644 intrusive_ref_counter.html
create mode 100644 test/intrusive_ref_counter_test.cpp
diff --git a/include/boost/smart_ptr/intrusive_ref_counter.hpp b/include/boost/smart_ptr/intrusive_ref_counter.hpp
new file mode 100644
index 0000000..82fa8bc
--- /dev/null
+++ b/include/boost/smart_ptr/intrusive_ref_counter.hpp
@@ -0,0 +1,187 @@
+/*
+ * 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
+#include
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+// This is a bogus MSVC warning, which is flagged by friend declarations of intrusive_ptr_add_ref and intrusive_ptr_release in intrusive_ref_counter:
+// 'name' : the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
+// Note that there is no inline specifier in the declarations.
+#pragma warning(disable: 4396)
+#endif
+
+namespace boost {
+
+namespace sp_adl_block {
+
+/*!
+ * \brief Thread unsafe reference counter policy for \c intrusive_ref_counter
+ *
+ * The policy instructs the \c 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 intrusive_ref_counter
+ *
+ * The policy instructs the \c 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 DerivedT, typename CounterPolicyT = thread_safe_counter >
+class intrusive_ref_counter;
+
+template< typename DerivedT, typename CounterPolicyT >
+void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
+template< typename DerivedT, typename CounterPolicyT >
+void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, 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.
+ * Upon releasing the last \c intrusive_ptr referencing the object
+ * derived from the \c intrusive_ref_counter class, operator \c delete
+ * is automatically called on the pointer to the object.
+ *
+ * The other template parameter, \c DerivedT, is the user's class that derives from \c intrusive_ref_counter.
+ */
+template< typename DerivedT, typename CounterPolicyT >
+class 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 use_count() == 0
+ */
+ intrusive_ref_counter() BOOST_NOEXCEPT : m_ref_counter(0)
+ {
+ }
+
+ /*!
+ * Copy constructor
+ *
+ * \post use_count() == 0
+ */
+ intrusive_ref_counter(intrusive_ref_counter const&) BOOST_NOEXCEPT : m_ref_counter(0)
+ {
+ }
+
+ /*!
+ * Assignment
+ *
+ * \post The reference counter is not modified after assignment
+ */
+ intrusive_ref_counter& operator= (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);
+ }
+
+protected:
+ /*!
+ * Destructor
+ */
+ BOOST_DEFAULTED_FUNCTION(~intrusive_ref_counter(), {})
+
+ friend void intrusive_ptr_add_ref< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
+ friend void intrusive_ptr_release< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
+};
+
+template< typename DerivedT, typename CounterPolicyT >
+inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT
+{
+ CounterPolicyT::increment(p->m_ref_counter);
+}
+
+template< typename DerivedT, typename CounterPolicyT >
+inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT
+{
+ if (CounterPolicyT::decrement(p->m_ref_counter) == 0)
+ delete static_cast< const DerivedT* >(p);
+}
+
+} // namespace sp_adl_block
+
+using sp_adl_block::intrusive_ref_counter;
+using sp_adl_block::thread_unsafe_counter;
+using sp_adl_block::thread_safe_counter;
+
+} // namespace boost
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_
diff --git a/intrusive_ptr.html b/intrusive_ptr.html
index 16097dd..562d27a 100644
--- a/intrusive_ptr.html
+++ b/intrusive_ptr.html
@@ -24,7 +24,9 @@
compilers that support argument-dependent lookup, intrusive_ptr_add_ref
and intrusive_ptr_release should be defined in the namespace
that corresponds to their parameter; otherwise, the definitions need to go in
- namespace boost.
+ namespace boost. The library provides a helper base class template
+ intrusive_ref_counter which may
+ help adding support for intrusive_ptr to user's types.
The class template is parameterized on T, the type of the object pointed
to. intrusive_ptr<T> can be implicitly converted to intrusive_ptr<U>
whenever T* can be implicitly converted to U*.
diff --git a/intrusive_ref_counter.html b/intrusive_ref_counter.html
new file mode 100644
index 0000000..72a46e0
--- /dev/null
+++ b/intrusive_ref_counter.html
@@ -0,0 +1,95 @@
+
+
+
+ intrusive_ref_counter
+
+
+
+
basic_intrusive_ref_counter class template
+
+ Introduction
+ Synopsis
+ Members
+
+
+ The intrusive_ref_counter class template implements a reference counter for a derived
+ user's class that is intended to be used with intrusive_ptr.
+ The base class has associated intrusive_ptr_add_ref and intrusive_ptr_release functions
+ which modify the reference counter as needed and destroy the user's object when the counter drops to zero.
+ The class template is parameterized on DerivedT and CounterPolicyT parameters.
+ The first parameter is the user's class that derives from intrusive_ref_counter. This type
+ is needed in order to destroy the object correctly when there are no references to it left.
+ The second parameter is a policy that defines the nature of the reference counter.
+ Boost.SmartPtr provides two such policies: thread_unsafe_counter and thread_safe_counter. The former
+ instructs the intrusive_ref_counter 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, the default counter policy is thread_safe_counter.
+
+ namespace boost {
+
+ struct thread_unsafe_counter;
+ struct thread_safe_counter;
+
+ template<class DerivedT, class CounterPolicyT = thread_safe_counter>
+ class intrusive_ref_counter
+ {
+ public:
+ intrusive_ref_counter() = noexcept;
+ intrusive_ref_counter(intrusive_ref_counter const & r) = noexcept;
+
+ intrusive_ref_counter & operator=(intrusive_ref_counter const & r) noexcept;
+
+ unsigned int use_count() const noexcept;
+
+ protected:
+ ~intrusive_ref_counter() = default;
+ };
+
+}
+
+
+ intrusive_ref_counter();
+
+ Postconditions: use_count() == 0
.
+ Throws: nothing.
+ Notes: The pointer to the constructed object is expected to be passed to intrusive_ptr
+ constructor, assignment operator or reset() method, which would increment the reference counter.
+
+ intrusive_ref_counter(intrusive_ref_counter const &);
+
+ Postconditions: use_count() == 0
.
+ Throws: nothing.
+ Notes: The pointer to the constructed object is expected to be passed to intrusive_ptr
+ constructor, assignment operator or reset() method, which would increment the reference counter.
+
+
+ ~intrusive_ref_counter();
+
+ Throws: nothing.
+ Effects: Destroys the counter object.
+ Notes: The destructor is protected so that the object can only be destroyed through the DerivedT class.
+
+
+ intrusive_ref_counter & operator=(intrusive_ref_counter const & r) noexcept;
+
+ Effects: Does nothing, reference counter is not modified.
+ Returns: *this
.
+
+
+ unsigned int use_count() const noexcept;
+
+ Returns: The current value of the reference counter.
+ Throws: nothing.
+ Notes: The returned value may not be actual in multi-threaded applications.
+
+
+
+ $Date$
+
+ Copyright © 2013 Andrey Semashev. 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.
+
+
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index d4f7af1..874968a 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -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 ]
diff --git a/test/intrusive_ref_counter_test.cpp b/test/intrusive_ref_counter_test.cpp
new file mode 100644
index 0000000..53d0bd3
--- /dev/null
+++ b/test/intrusive_ref_counter_test.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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
+
+#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
+#include
+#include
+#include
+
+namespace N1 {
+
+class my_class :
+ public boost::intrusive_ref_counter< my_class >
+{
+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::intrusive_ref_counter< my_class, 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 root :
+ public boost::intrusive_ref_counter< root >
+{
+ virtual ~root() {}
+};
+
+} // namespace N3
+
+namespace N4 {
+
+struct X :
+ public virtual N3::root
+{
+};
+
+} // namespace N4
+
+namespace N5 {
+
+struct Y :
+ public virtual N3::root
+{
+};
+
+} // namespace N5
+
+namespace N6 {
+
+struct Z :
+ public N4::X,
+ public N5::Y
+{
+ static unsigned int destructor_count;
+
+ ~Z()
+ {
+ ++destructor_count;
+ }
+};
+
+unsigned int Z::destructor_count = 0;
+
+} // namespace N6
+
+
+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< N6::Z > p1 = new N6::Z();
+ BOOST_TEST(p1->use_count() == 1);
+ BOOST_TEST(N6::Z::destructor_count == 0);
+ boost::intrusive_ptr< N3::root > p2 = p1;
+ BOOST_TEST(p1->use_count() == 2);
+ BOOST_TEST(N6::Z::destructor_count == 0);
+ p1 = NULL;
+ BOOST_TEST(N6::Z::destructor_count == 0);
+ p2 = NULL;
+ BOOST_TEST(N6::Z::destructor_count == 1);
+ }
+
+ return boost::report_errors();
+}