diff --git a/compatibility.htm b/compatibility.htm new file mode 100644 index 0000000..d520bd1 --- /dev/null +++ b/compatibility.htm @@ -0,0 +1,88 @@ + + + + Smart Pointer Changes + + + +

boost.png (6897 bytes)Smart Pointer Changes

+

The February 2002 change to the Boost smart pointers introduced a number of + changes. Since the previous version of the smart pointers was in use for a long + time, it's useful to have a detailed list of what changed from a library user's + point of view.

+

Note that for compilers that don't support member templates well enough, a + separate implementation is used that lacks many of the new features and is more + like the old version.

+

Features Requiring Code Changes to Take Advantage

+ +

Features That Improve Robustness

+ +

Implementation Details

+ +
+

Revised 1 February 2002

+

Copyright 2002 Darin Adler. 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/enable_shared_from_this.html b/enable_shared_from_this.html new file mode 100644 index 0000000..3f35665 --- /dev/null +++ b/enable_shared_from_this.html @@ -0,0 +1,91 @@ + + + + Boost: enable_shared_from_this.hpp documentation + + + + + + + + + + + +
boost.png (6897 bytes) + +

enable_shared_from_this.hpp

+
 
+

Purpose

+

+ The header <boost/enable_shared_from_this.hpp> defines + the class template enable_shared_from_this. It is used as a + base class that allows a shared_ptr to the current + object to be obtained from within a member function. +

+

enable_shared_from_this<T> defines two member functions + called shared_from_this that return a shared_ptr<T> + and shared_ptr<T const>, depending on constness, to this.

+

Example

+
+class Y: public enable_shared_from_this<Y>
+{
+public:
+
+    shared_ptr<Y> f()
+    {
+        return shared_from_this();
+    }
+}
+
+int main()
+{
+    shared_ptr<Y> p(new Y);
+    shared_ptr<Y> q = p->f();
+    assert(p == q);
+    assert(!(p < q || q < p)); // p and q must share ownership
+}
+
+

Synopsis

+
+namespace boost
+{
+
+template<class T> class enable_shared_from_this
+{
+public:
+
+    shared_ptr<T> shared_from_this();
+    shared_ptr<T const> shared_from_this() const;
+}
+
+}
+
+

template<class T> shared_ptr<T> + enable_shared_from_this<T>::shared_from_this();

+

template<class T> shared_ptr<T const> + enable_shared_from_this<T>::shared_from_this() const;

+
+

+ Requires: enable_shared_from_this<T> must be an + accessible base class of T. *this must be a subobject + of an instance t of type T . There must exist + at least one shared_ptr instance p that owns + t. +

+

+ Returns: A shared_ptr<T> instance r that shares + ownership with p. +

+

+ Postconditions: r.get() == this. +

+
+

+
+ Copyright © 2002, 2003 by Peter Dimov. 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/example/scoped_ptr_example.cpp b/example/scoped_ptr_example.cpp new file mode 100644 index 0000000..3dcfbb1 --- /dev/null +++ b/example/scoped_ptr_example.cpp @@ -0,0 +1,23 @@ +// Boost scoped_ptr_example implementation file -----------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include "scoped_ptr_example.hpp" +#include + +class example::implementation +{ + public: + ~implementation() { std::cout << "destroying implementation\n"; } +}; + +example::example() : _imp( new implementation ) {} + +void example::do_something() { std::cout << "did something\n"; } + +example::~example() {} diff --git a/example/scoped_ptr_example.hpp b/example/scoped_ptr_example.hpp new file mode 100644 index 0000000..0d9c603 --- /dev/null +++ b/example/scoped_ptr_example.hpp @@ -0,0 +1,29 @@ +// Boost scoped_ptr_example header file ------------------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include +#include + +// The point of this example is to prove that even though +// example::implementation is an incomplete type in translation units using +// this header, scoped_ptr< implementation > is still valid because the type +// is complete where it counts - in the inplementation translation unit where +// destruction is actually instantiated. + +class example : private boost::noncopyable +{ + public: + example(); + ~example(); + void do_something(); + private: + class implementation; + boost::scoped_ptr< implementation > _imp; // hide implementation details +}; + diff --git a/example/scoped_ptr_example_test.cpp b/example/scoped_ptr_example_test.cpp new file mode 100644 index 0000000..26b3a18 --- /dev/null +++ b/example/scoped_ptr_example_test.cpp @@ -0,0 +1,17 @@ +// Boost scoped_ptr_example_test main program -------------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include "scoped_ptr_example.hpp" + +int main() +{ + example my_example; + my_example.do_something(); + return 0; +} diff --git a/example/shared_ptr_example.cpp b/example/shared_ptr_example.cpp new file mode 100644 index 0000000..c3b1f3b --- /dev/null +++ b/example/shared_ptr_example.cpp @@ -0,0 +1,95 @@ +// Boost shared_ptr_example.cpp --------------------------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +// Revision History +// 21 May 01 Initial complete version (Beman Dawes) + +// The original code for this example appeared in the shared_ptr documentation. +// Ray Gallimore pointed out that foo_set was missing a Compare template +// argument, so would not work as intended. At that point the code was +// turned into an actual .cpp file so it could be compiled and tested. + +#include +#include +#include +#include +#include + +// The application will produce a series of +// objects of type Foo which later must be +// accessed both by occurrence (std::vector) +// and by ordering relationship (std::set). + +struct Foo +{ + Foo( int _x ) : x(_x) {} + ~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; } + int x; + /* ... */ +}; + +typedef boost::shared_ptr FooPtr; + +struct FooPtrOps +{ + bool operator()( const FooPtr & a, const FooPtr & b ) + { return a->x > b->x; } + void operator()( const FooPtr & a ) + { std::cout << a->x << "\n"; } +}; + +int main() +{ + std::vector foo_vector; + std::set foo_set; // NOT multiset! + + FooPtr foo_ptr( new Foo( 2 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset( new Foo( 1 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset( new Foo( 3 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + foo_ptr.reset ( new Foo( 2 ) ); + foo_vector.push_back( foo_ptr ); + foo_set.insert( foo_ptr ); + + std::cout << "foo_vector:\n"; + std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() ); + + std::cout << "\nfoo_set:\n"; + std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() ); + std::cout << "\n"; + +// Expected output: +// +// foo_vector: +// 2 +// 1 +// 3 +// 2 +// +// foo_set: +// 3 +// 2 +// 1 +// +// Destructing a Foo with x=2 +// Destructing a Foo with x=1 +// Destructing a Foo with x=3 +// Destructing a Foo with x=2 + + return 0; +} + diff --git a/example/shared_ptr_example2.cpp b/example/shared_ptr_example2.cpp new file mode 100644 index 0000000..fdefc8d --- /dev/null +++ b/example/shared_ptr_example2.cpp @@ -0,0 +1,22 @@ +// Boost shared_ptr_example2 implementation file -----------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include "shared_ptr_example2.hpp" +#include + +class example::implementation +{ + public: + ~implementation() { std::cout << "destroying implementation\n"; } +}; + +example::example() : _imp( new implementation ) {} + +void example::do_something() + { std::cout << "use_count() is " << _imp.use_count() << "\n"; } diff --git a/example/shared_ptr_example2.hpp b/example/shared_ptr_example2.hpp new file mode 100644 index 0000000..5ca7a07 --- /dev/null +++ b/example/shared_ptr_example2.hpp @@ -0,0 +1,31 @@ +// Boost shared_ptr_example2 header file -----------------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include + +// This example demonstrates the handle/body idiom (also called pimpl and +// several other names). It separates the interface (in this header file) +// from the implementation (in shared_ptr_example2.cpp). + +// Note that even though example::implementation is an incomplete type in +// some translation units using this header, shared_ptr< implementation > +// is still valid because the type is complete where it counts - in the +// shared_ptr_example2.cpp translation unit where functions requiring a +// complete type are actually instantiated. + +class example +{ +public: + example(); + void do_something(); +private: + class implementation; + boost::shared_ptr< implementation > _imp; // hide implementation details +}; + diff --git a/example/shared_ptr_example2_test.cpp b/example/shared_ptr_example2_test.cpp new file mode 100644 index 0000000..2702cb8 --- /dev/null +++ b/example/shared_ptr_example2_test.cpp @@ -0,0 +1,22 @@ +// Boost shared_ptr_example2_test main program ------------------------------// + +// Copyright Beman Dawes 2001. 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) + + +// See http://www.boost.org/libs/smart_ptr for documentation. + +#include "shared_ptr_example2.hpp" + +int main() +{ + example a; + a.do_something(); + example b(a); + b.do_something(); + example c; + c = a; + c.do_something(); + return 0; +} diff --git a/gccspeed.gif b/gccspeed.gif new file mode 100644 index 0000000..d78c06b Binary files /dev/null and b/gccspeed.gif differ diff --git a/include/boost/detail/atomic_count.hpp b/include/boost/detail/atomic_count.hpp new file mode 100644 index 0000000..5411c7a --- /dev/null +++ b/include/boost/detail/atomic_count.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED +#define BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/atomic_count.hpp - thread/SMP safe reference counter +// +// Copyright (c) 2001, 2002 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 + +#endif // #ifndef BOOST_DETAIL_ATOMIC_COUNT_HPP_INCLUDED diff --git a/include/boost/detail/lightweight_mutex.hpp b/include/boost/detail/lightweight_mutex.hpp new file mode 100644 index 0000000..b7a7f6d --- /dev/null +++ b/include/boost/detail/lightweight_mutex.hpp @@ -0,0 +1,22 @@ +#ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED +#define BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/lightweight_mutex.hpp - lightweight mutex +// +// Copyright (c) 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 + +#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED diff --git a/include/boost/detail/sp_typeinfo.hpp b/include/boost/detail/sp_typeinfo.hpp new file mode 100644 index 0000000..e78c943 --- /dev/null +++ b/include/boost/detail/sp_typeinfo.hpp @@ -0,0 +1,83 @@ +#ifndef BOOST_DETAIL_SP_TYPEINFO_HPP_INCLUDED +#define BOOST_DETAIL_SP_TYPEINFO_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_typeinfo.hpp +// +// Copyright 2007 Peter Dimov +// +// 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 + +#if defined( BOOST_NO_TYPEID ) + +namespace boost +{ + +namespace detail +{ + +typedef void* sp_typeinfo; + +template struct sp_typeid_ +{ + static char v_; +}; + +template char sp_typeid_< T >::v_; + +template struct sp_typeid_< T const >: sp_typeid_< T > +{ +}; + +template struct sp_typeid_< T volatile >: sp_typeid_< T > +{ +}; + +template struct sp_typeid_< T const volatile >: sp_typeid_< T > +{ +}; + +} // namespace detail + +} // namespace boost + +#define BOOST_SP_TYPEID(T) (&boost::detail::sp_typeid_::v_) + +#else + +#include + +namespace boost +{ + +namespace detail +{ + +#if defined( BOOST_NO_STD_TYPEINFO ) + +typedef ::type_info sp_typeinfo; + +#else + +typedef std::type_info sp_typeinfo; + +#endif + +} // namespace detail + +} // namespace boost + +#define BOOST_SP_TYPEID(T) typeid(T) + +#endif + +#endif // #ifndef BOOST_DETAIL_SP_TYPEINFO_HPP_INCLUDED diff --git a/include/boost/enable_shared_from_this.hpp b/include/boost/enable_shared_from_this.hpp new file mode 100644 index 0000000..b1bb63d --- /dev/null +++ b/include/boost/enable_shared_from_this.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED +#define BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + +// +// enable_shared_from_this.hpp +// +// Copyright (c) 2002 Peter Dimov +// +// 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 +// +// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html +// + +#include + +#endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED diff --git a/include/boost/get_pointer.hpp b/include/boost/get_pointer.hpp new file mode 100644 index 0000000..a0cd5c0 --- /dev/null +++ b/include/boost/get_pointer.hpp @@ -0,0 +1,33 @@ +// Copyright Peter Dimov and David Abrahams 2002. +// 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) +#ifndef GET_POINTER_DWA20021219_HPP +# define GET_POINTER_DWA20021219_HPP + +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +# include // std::auto_ptr + +namespace boost { + +// get_pointer(p) extracts a ->* capable pointer from p + +template T * get_pointer(T * p) +{ + return p; +} + +// get_pointer(shared_ptr const & p) has been moved to shared_ptr.hpp + +template T * get_pointer(std::auto_ptr const& p) +{ + return p.get(); +} + + +} // namespace boost + +#endif // GET_POINTER_DWA20021219_HPP diff --git a/include/boost/intrusive_ptr.hpp b/include/boost/intrusive_ptr.hpp new file mode 100644 index 0000000..63036dc --- /dev/null +++ b/include/boost/intrusive_ptr.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED +#define BOOST_INTRUSIVE_PTR_HPP_INCLUDED + +// +// intrusive_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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 +// +// See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation. +// + +#include + +#endif // #ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/include/boost/make_shared.hpp b/include/boost/make_shared.hpp new file mode 100644 index 0000000..c04938f --- /dev/null +++ b/include/boost/make_shared.hpp @@ -0,0 +1,17 @@ +#ifndef BOOST_MAKE_SHARED_HPP_INCLUDED +#define BOOST_MAKE_SHARED_HPP_INCLUDED + +// make_shared.hpp +// +// Copyright (c) 2007, 2008 Peter Dimov +// +// 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 +// +// See http://www.boost.org/libs/smart_ptr/make_shared.html +// for documentation. + +#include + +#endif // #ifndef BOOST_MAKE_SHARED_HPP_INCLUDED diff --git a/include/boost/memory_order.hpp b/include/boost/memory_order.hpp new file mode 100644 index 0000000..2524e8a --- /dev/null +++ b/include/boost/memory_order.hpp @@ -0,0 +1,35 @@ +#ifndef BOOST_MEMORY_ORDER_HPP_INCLUDED +#define BOOST_MEMORY_ORDER_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/memory_order.hpp +// +// Defines enum boost::memory_order per the C++0x working draft +// +// Copyright (c) 2008 Peter Dimov +// +// 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) + + +namespace boost +{ + +enum memory_order +{ + memory_order_relaxed = 0, + memory_order_acquire = 1, + memory_order_release = 2, + memory_order_acq_rel = 3, // acquire | release + memory_order_seq_cst = 7 // acq_rel | 4 +}; + +} // namespace boost + +#endif // #ifndef BOOST_MEMORY_ORDER_HPP_INCLUDED diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp new file mode 100644 index 0000000..6e532eb --- /dev/null +++ b/include/boost/pointer_cast.hpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005. +// 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) +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_POINTER_CAST_HPP +#define BOOST_POINTER_CAST_HPP + +namespace boost { + +//static_pointer_cast overload for raw pointers +template +inline T* static_pointer_cast(U *ptr) +{ + return static_cast(ptr); +} + +//dynamic_pointer_cast overload for raw pointers +template +inline T* dynamic_pointer_cast(U *ptr) +{ + return dynamic_cast(ptr); +} + +//const_pointer_cast overload for raw pointers +template +inline T* const_pointer_cast(U *ptr) +{ + return const_cast(ptr); +} + +//reinterpret_pointer_cast overload for raw pointers +template +inline T* reinterpret_pointer_cast(U *ptr) +{ + return reinterpret_cast(ptr); +} + +} // namespace boost + +#endif //BOOST_POINTER_CAST_HPP diff --git a/include/boost/pointer_to_other.hpp b/include/boost/pointer_to_other.hpp new file mode 100644 index 0000000..8516734 --- /dev/null +++ b/include/boost/pointer_to_other.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED +#define BOOST_POINTER_TO_OTHER_HPP_INCLUDED + +// +// pointer_to_other.hpp +// +// (C) Copyright Ion Gaztanaga 2005. +// Copyright (c) 2005 Peter Dimov. +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/pointer_to_other.html +// + +namespace boost +{ + +// Defines the same pointer type (raw or smart) to another pointee type + +template +struct pointer_to_other; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template +struct pointer_to_other< T*, U > +{ + typedef U* type; +}; + +} // namespace boost + +#endif // #ifndef BOOST_POINTER_TO_OTHER_HPP_INCLUDED diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp new file mode 100644 index 0000000..c02fa31 --- /dev/null +++ b/include/boost/scoped_array.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED +#define BOOST_SCOPED_ARRAY_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// http://www.boost.org/libs/smart_ptr/scoped_array.htm +// + +#include + +#endif // #ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp new file mode 100644 index 0000000..cb916da --- /dev/null +++ b/include/boost/scoped_ptr.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED +#define BOOST_SCOPED_PTR_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm +// + +#include + +#endif // #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/shared_array.hpp b/include/boost/shared_array.hpp new file mode 100644 index 0000000..0700ce4 --- /dev/null +++ b/include/boost/shared_array.hpp @@ -0,0 +1,19 @@ +#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED +#define BOOST_SHARED_ARRAY_HPP_INCLUDED + +// +// shared_array.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. +// + +#include + +#endif // #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp new file mode 100644 index 0000000..d31978c --- /dev/null +++ b/include/boost/shared_ptr.hpp @@ -0,0 +1,19 @@ +#ifndef BOOST_SHARED_PTR_HPP_INCLUDED +#define BOOST_SHARED_PTR_HPP_INCLUDED + +// +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001-2008 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include + +#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr.hpp b/include/boost/smart_ptr.hpp new file mode 100644 index 0000000..98e0894 --- /dev/null +++ b/include/boost/smart_ptr.hpp @@ -0,0 +1,25 @@ +// +// smart_ptr.hpp +// +// For convenience, this header includes the rest of the smart +// pointer library headers. +// +// Copyright (c) 2003 Peter Dimov 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) +// +// http://www.boost.org/libs/smart_ptr/smart_ptr.htm +// + +#include + +#include +#include +#include +#include + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) +# include +# include +# include +#endif diff --git a/include/boost/smart_ptr/bad_weak_ptr.hpp b/include/boost/smart_ptr/bad_weak_ptr.hpp new file mode 100644 index 0000000..3e0a1b7 --- /dev/null +++ b/include/boost/smart_ptr/bad_weak_ptr.hpp @@ -0,0 +1,59 @@ +#ifndef BOOST_SMART_PTR_BAD_WEAK_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_BAD_WEAK_PTR_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/smart_ptr/bad_weak_ptr.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 + +#ifdef __BORLANDC__ +# pragma warn -8026 // Functions with excep. spec. are not expanded inline +#endif + +namespace boost +{ + +// The standard library that comes with Borland C++ 5.5.1, 5.6.4 +// 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. + +#if defined(__BORLANDC__) && __BORLANDC__ <= 0x564 +# pragma option push -pc +#endif + +class bad_weak_ptr: public std::exception +{ +public: + + virtual char const * what() const throw() + { + return "tr1::bad_weak_ptr"; + } +}; + +#if defined(__BORLANDC__) && __BORLANDC__ <= 0x564 +# pragma option pop +#endif + +} // namespace boost + +#ifdef __BORLANDC__ +# pragma warn .8026 // Functions with excep. spec. are not expanded inline +#endif + +#endif // #ifndef BOOST_SMART_PTR_BAD_WEAK_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count.hpp b/include/boost/smart_ptr/detail/atomic_count.hpp new file mode 100644 index 0000000..cc44ac2 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count.hpp @@ -0,0 +1,119 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/atomic_count.hpp - thread/SMP safe reference counter +// +// Copyright (c) 2001, 2002 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) +// +// typedef boost::detail::atomic_count; +// +// atomic_count a(n); +// +// (n is convertible to long) +// +// Effects: Constructs an atomic_count with an initial value of n +// +// a; +// +// Returns: (long) the current value of a +// +// ++a; +// +// Effects: Atomically increments the value of a +// Returns: (long) the new value of a +// +// --a; +// +// Effects: Atomically decrements the value of a +// Returns: (long) the new value of a +// +// Important note: when --a returns zero, it must act as a +// read memory barrier (RMB); i.e. the calling thread must +// have a synchronized view of the memory +// +// On Intel IA-32 (x86) memory is always synchronized, so this +// is not a problem. +// +// On many architectures the atomic instructions already act as +// a memory barrier. +// +// This property is necessary for proper reference counting, since +// a thread can update the contents of a shared object, then +// release its reference, and another thread may immediately +// release the last reference causing object destruction. +// +// The destructor needs to have a synchronized view of the +// object to perform proper cleanup. +// +// Original example by Alexander Terekhov: +// +// Given: +// +// - a mutable shared object OBJ; +// - two threads THREAD1 and THREAD2 each holding +// a private smart_ptr object pointing to that OBJ. +// +// t1: THREAD1 updates OBJ (thread-safe via some synchronization) +// and a few cycles later (after "unlock") destroys smart_ptr; +// +// t2: THREAD2 destroys smart_ptr WITHOUT doing any synchronization +// with respect to shared mutable object OBJ; OBJ destructors +// are called driven by smart_ptr interface... +// + +#include +#include + +#ifndef BOOST_HAS_THREADS + +namespace boost +{ + +namespace detail +{ + +typedef long atomic_count; + +} + +} + +#elif defined(BOOST_AC_USE_PTHREADS) +# include + +#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) +# include + +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include + +#elif defined( BOOST_SP_HAS_SYNC ) +# include + +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) +# include + +#elif defined(BOOST_HAS_PTHREADS) + +# define BOOST_AC_USE_PTHREADS +# include + +#else + +// Use #define BOOST_DISABLE_THREADS to avoid the error +#error Unrecognized threading platform + +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_gcc.hpp b/include/boost/smart_ptr/detail/atomic_count_gcc.hpp new file mode 100644 index 0000000..54807e9 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_gcc.hpp @@ -0,0 +1,72 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED + +// +// boost/detail/atomic_count_gcc.hpp +// +// atomic_count for GNU libstdc++ v3 +// +// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2002 Lars Gullik Bjønnes +// Copyright 2003-2005 Peter Dimov +// +// 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) +// + +#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402 +# include +#else +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#if defined(__GLIBCXX__) // g++ 3.4+ + +using __gnu_cxx::__atomic_add; +using __gnu_cxx::__exchange_and_add; + +#endif + +class atomic_count +{ +public: + + explicit atomic_count( long v ) : value_( v ) {} + + long operator++() + { + return __exchange_and_add( &value_, +1 ) + 1; + } + + long operator--() + { + return __exchange_and_add( &value_, -1 ) - 1; + } + + operator long() const + { + return __exchange_and_add( &value_, 0 ); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + mutable _Atomic_word value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp b/include/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp new file mode 100644 index 0000000..5c44d7c --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp @@ -0,0 +1,77 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_X86_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_X86_HPP_INCLUDED + +// +// boost/detail/atomic_count_gcc_x86.hpp +// +// atomic_count for g++ on 486+/AMD64 +// +// Copyright 2007 Peter Dimov +// +// 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) +// + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count( long v ) : value_( static_cast< int >( v ) ) {} + + long operator++() + { + return atomic_exchange_and_add( &value_, +1 ) + 1; + } + + long operator--() + { + return atomic_exchange_and_add( &value_, -1 ) - 1; + } + + operator long() const + { + return atomic_exchange_and_add( &value_, 0 ); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + mutable int value_; + +private: + + static int atomic_exchange_and_add( int * pw, int dv ) + { + // int r = *pw; + // *pw += dv; + // return r; + + int r; + + __asm__ __volatile__ + ( + "lock\n\t" + "xadd %1, %0": + "+m"( *pw ), "=r"( r ): // outputs (%0, %1) + "1"( dv ): // inputs (%2 == %1) + "memory", "cc" // clobbers + ); + + return r; + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_GCC_X86_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_pthreads.hpp b/include/boost/smart_ptr/detail/atomic_count_pthreads.hpp new file mode 100644 index 0000000..05f7867 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_pthreads.hpp @@ -0,0 +1,96 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED + +// +// boost/detail/atomic_count_pthreads.hpp +// +// Copyright (c) 2001, 2002 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 + +// +// The generic pthread_mutex-based implementation sometimes leads to +// inefficiencies. Example: a class with two atomic_count members +// can get away with a single mutex. +// +// Users can detect this situation by checking BOOST_AC_USE_PTHREADS. +// + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +private: + + class scoped_lock + { + public: + + scoped_lock(pthread_mutex_t & m): m_(m) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock() + { + pthread_mutex_unlock(&m_); + } + + private: + + pthread_mutex_t & m_; + }; + +public: + + explicit atomic_count(long v): value_(v) + { + pthread_mutex_init(&mutex_, 0); + } + + ~atomic_count() + { + pthread_mutex_destroy(&mutex_); + } + + long operator++() + { + scoped_lock lock(mutex_); + return ++value_; + } + + long operator--() + { + scoped_lock lock(mutex_); + return --value_; + } + + operator long() const + { + scoped_lock lock(mutex_); + return value_; + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + mutable pthread_mutex_t mutex_; + long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_PTHREADS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_solaris.hpp b/include/boost/smart_ptr/detail/atomic_count_solaris.hpp new file mode 100644 index 0000000..a13bcfb --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_solaris.hpp @@ -0,0 +1,59 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SOLARIS_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SOLARIS_HPP_INCLUDED + +// +// boost/detail/atomic_count_solaris.hpp +// based on: boost/detail/atomic_count_win32.hpp +// +// Copyright (c) 2001-2005 Peter Dimov +// Copyright (c) 2006 Michael van der Westhuizen +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count( uint32_t v ): value_( v ) + { + } + + long operator++() + { + return atomic_inc_32_nv( &value_ ); + } + + long operator--() + { + return atomic_dec_32_nv( &value_ ); + } + + operator uint32_t() const + { + return static_cast( value_ ); + } + +private: + + atomic_count( atomic_count const & ); + atomic_count & operator=( atomic_count const & ); + + uint32_t value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SOLARIS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_sync.hpp b/include/boost/smart_ptr/detail/atomic_count_sync.hpp new file mode 100644 index 0000000..b6359b5 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_sync.hpp @@ -0,0 +1,61 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SYNC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SYNC_HPP_INCLUDED + +// +// boost/detail/atomic_count_sync.hpp +// +// atomic_count for g++ 4.1+ +// +// http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html +// +// Copyright 2007 Peter Dimov +// +// 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) +// + +#if defined( __ia64__ ) && defined( __INTEL_COMPILER ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count( long v ) : value_( v ) {} + + long operator++() + { + return __sync_add_and_fetch( &value_, 1 ); + } + + long operator--() + { + return __sync_add_and_fetch( &value_, -1 ); + } + + operator long() const + { + return __sync_fetch_and_add( &value_, 0 ); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + mutable long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SYNC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_win32.hpp b/include/boost/smart_ptr/detail/atomic_count_win32.hpp new file mode 100644 index 0000000..60a0569 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_win32.hpp @@ -0,0 +1,63 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/atomic_count_win32.hpp +// +// Copyright (c) 2001-2005 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count( long v ): value_( v ) + { + } + + long operator++() + { + return BOOST_INTERLOCKED_INCREMENT( &value_ ); + } + + long operator--() + { + return BOOST_INTERLOCKED_DECREMENT( &value_ ); + } + + operator long() const + { + return static_cast( value_ ); + } + +private: + + atomic_count( atomic_count const & ); + atomic_count & operator=( atomic_count const & ); + + long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_WIN32_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/lightweight_mutex.hpp b/include/boost/smart_ptr/detail/lightweight_mutex.hpp new file mode 100644 index 0000000..d46b193 --- /dev/null +++ b/include/boost/smart_ptr/detail/lightweight_mutex.hpp @@ -0,0 +1,42 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/lightweight_mutex.hpp - lightweight mutex +// +// Copyright (c) 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) +// +// typedef boost::detail::lightweight_mutex; +// +// boost::detail::lightweight_mutex is a header-only implementation of +// a subset of the Mutex concept requirements: +// +// http://www.boost.org/doc/html/threads/concepts.html#threads.concepts.Mutex +// +// It maps to a CRITICAL_SECTION on Windows or a pthread_mutex on POSIX. +// + +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#elif defined(BOOST_HAS_WINTHREADS) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include +#else +// Use #define BOOST_DISABLE_THREADS to avoid the error +# error Unrecognized threading platform +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LIGHTWEIGHT_MUTEX_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/lwm_nop.hpp b/include/boost/smart_ptr/detail/lwm_nop.hpp new file mode 100644 index 0000000..521a88e --- /dev/null +++ b/include/boost/smart_ptr/detail/lwm_nop.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LWM_NOP_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LWM_NOP_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/lwm_nop.hpp +// +// Copyright (c) 2002 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) +// + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +public: + + typedef lightweight_mutex scoped_lock; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LWM_NOP_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/lwm_pthreads.hpp b/include/boost/smart_ptr/detail/lwm_pthreads.hpp new file mode 100644 index 0000000..fc20dbb --- /dev/null +++ b/include/boost/smart_ptr/detail/lwm_pthreads.hpp @@ -0,0 +1,86 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LWM_PTHREADS_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LWM_PTHREADS_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/lwm_pthreads.hpp +// +// Copyright (c) 2002 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 + +namespace boost +{ + +namespace detail +{ + +class lightweight_mutex +{ +private: + + pthread_mutex_t m_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + +// HPUX 10.20 / DCE has a nonstandard pthread_mutex_init + +#if defined(__hpux) && defined(_DECTHREADS_) + pthread_mutex_init(&m_, pthread_mutexattr_default); +#else + pthread_mutex_init(&m_, 0); +#endif + } + + ~lightweight_mutex() + { + pthread_mutex_destroy(&m_); + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + pthread_mutex_t & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + scoped_lock(lightweight_mutex & m): m_(m.m_) + { + pthread_mutex_lock(&m_); + } + + ~scoped_lock() + { + pthread_mutex_unlock(&m_); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LWM_PTHREADS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/lwm_win32_cs.hpp b/include/boost/smart_ptr/detail/lwm_win32_cs.hpp new file mode 100644 index 0000000..00477e4 --- /dev/null +++ b/include/boost/smart_ptr/detail/lwm_win32_cs.hpp @@ -0,0 +1,108 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LWM_WIN32_CS_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LWM_WIN32_CS_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/lwm_win32_cs.hpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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) +// + +#ifdef BOOST_USE_WINDOWS_H +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#ifndef BOOST_USE_WINDOWS_H + +struct critical_section +{ + struct critical_section_debug * DebugInfo; + long LockCount; + long RecursionCount; + void * OwningThread; + void * LockSemaphore; +#if defined(_WIN64) + unsigned __int64 SpinCount; +#else + unsigned long SpinCount; +#endif +}; + +extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(critical_section *); +extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(critical_section *); + +#else + +typedef ::CRITICAL_SECTION critical_section; + +#endif // #ifndef BOOST_USE_WINDOWS_H + +class lightweight_mutex +{ +private: + + critical_section cs_; + + lightweight_mutex(lightweight_mutex const &); + lightweight_mutex & operator=(lightweight_mutex const &); + +public: + + lightweight_mutex() + { + InitializeCriticalSection(&cs_); + } + + ~lightweight_mutex() + { + DeleteCriticalSection(&cs_); + } + + class scoped_lock; + friend class scoped_lock; + + class scoped_lock + { + private: + + lightweight_mutex & m_; + + scoped_lock(scoped_lock const &); + scoped_lock & operator=(scoped_lock const &); + + public: + + explicit scoped_lock(lightweight_mutex & m): m_(m) + { + EnterCriticalSection(&m_.cs_); + } + + ~scoped_lock() + { + LeaveCriticalSection(&m_.cs_); + } + }; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LWM_WIN32_CS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/operator_bool.hpp b/include/boost/smart_ptr/detail/operator_bool.hpp new file mode 100644 index 0000000..842a05d --- /dev/null +++ b/include/boost/smart_ptr/detail/operator_bool.hpp @@ -0,0 +1,56 @@ +// This header intentionally has no include guards. +// +// Copyright (c) 2001-2009 Peter Dimov +// +// 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 + +#if ( defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, < 0x570) ) || defined(__CINT__) + + operator bool () const + { + return px != 0; + } + +#elif defined( _MANAGED ) + + static void unspecified_bool( this_type*** ) + { + } + + typedef void (*unspecified_bool_type)( this_type*** ); + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: unspecified_bool; + } + +#elif \ + ( defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, < 0x3200) ) || \ + ( defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304) ) || \ + ( defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) ) + + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + +#else + + typedef T * this_type::*unspecified_bool_type; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::px; + } + +#endif + + // operator! is redundant, but some compilers need it + bool operator! () const // never throws + { + return px == 0; + } diff --git a/include/boost/smart_ptr/detail/quick_allocator.hpp b/include/boost/smart_ptr/detail/quick_allocator.hpp new file mode 100644 index 0000000..6d136f8 --- /dev/null +++ b/include/boost/smart_ptr/detail/quick_allocator.hpp @@ -0,0 +1,198 @@ +#ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/quick_allocator.hpp +// +// Copyright (c) 2003 David Abrahams +// Copyright (c) 2003 Peter Dimov +// +// 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 + +#include +#include +#include + +#include // ::operator new, ::operator delete +#include // std::size_t + +namespace boost +{ + +namespace detail +{ + +template union freeblock +{ + typedef typename boost::type_with_alignment::type aligner_type; + aligner_type aligner; + char bytes[size]; + freeblock * next; +}; + +template struct allocator_impl +{ + typedef freeblock block; + + // It may seem odd to use such small pages. + // + // However, on a typical Windows implementation that uses + // the OS allocator, "normal size" pages interact with the + // "ordinary" operator new, slowing it down dramatically. + // + // 512 byte pages are handled by the small object allocator, + // and don't interfere with ::new. + // + // The other alternative is to use much bigger pages (1M.) + // + // It is surprisingly easy to hit pathological behavior by + // varying the page size. g++ 2.96 on Red Hat Linux 7.2, + // for example, passionately dislikes 496. 512 seems OK. + +#if defined(BOOST_QA_PAGE_SIZE) + + enum { items_per_page = BOOST_QA_PAGE_SIZE / size }; + +#else + + enum { items_per_page = 512 / size }; // 1048560 / size + +#endif + +#ifdef BOOST_HAS_THREADS + + static lightweight_mutex & mutex() + { + static lightweight_mutex m; + return m; + } + + static lightweight_mutex * mutex_init; + +#endif + + static block * free; + static block * page; + static unsigned last; + + static inline void * alloc() + { +#ifdef BOOST_HAS_THREADS + lightweight_mutex::scoped_lock lock( mutex() ); +#endif + if(block * x = free) + { + free = x->next; + return x; + } + else + { + if(last == items_per_page) + { + // "Listen to me carefully: there is no memory leak" + // -- Scott Meyers, Eff C++ 2nd Ed Item 10 + page = ::new block[items_per_page]; + last = 0; + } + + return &page[last++]; + } + } + + static inline void * alloc(std::size_t n) + { + if(n != size) // class-specific new called for a derived object + { + return ::operator new(n); + } + else + { +#ifdef BOOST_HAS_THREADS + lightweight_mutex::scoped_lock lock( mutex() ); +#endif + if(block * x = free) + { + free = x->next; + return x; + } + else + { + if(last == items_per_page) + { + page = ::new block[items_per_page]; + last = 0; + } + + return &page[last++]; + } + } + } + + static inline void dealloc(void * pv) + { + if(pv != 0) // 18.4.1.1/13 + { +#ifdef BOOST_HAS_THREADS + lightweight_mutex::scoped_lock lock( mutex() ); +#endif + block * pb = static_cast(pv); + pb->next = free; + free = pb; + } + } + + static inline void dealloc(void * pv, std::size_t n) + { + if(n != size) // class-specific delete called for a derived object + { + ::operator delete(pv); + } + else if(pv != 0) // 18.4.1.1/13 + { +#ifdef BOOST_HAS_THREADS + lightweight_mutex::scoped_lock lock( mutex() ); +#endif + block * pb = static_cast(pv); + pb->next = free; + free = pb; + } + } +}; + +#ifdef BOOST_HAS_THREADS + +template + lightweight_mutex * allocator_impl::mutex_init = &allocator_impl::mutex(); + +#endif + +template + freeblock * allocator_impl::free = 0; + +template + freeblock * allocator_impl::page = 0; + +template + unsigned allocator_impl::last = allocator_impl::items_per_page; + +template +struct quick_allocator: public allocator_impl< sizeof(T), boost::alignment_of::value > +{ +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_QUICK_ALLOCATOR_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/shared_array_nmt.hpp b/include/boost/smart_ptr/detail/shared_array_nmt.hpp new file mode 100644 index 0000000..450c9bc --- /dev/null +++ b/include/boost/smart_ptr/detail/shared_array_nmt.hpp @@ -0,0 +1,151 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED + +// +// detail/shared_array_nmt.hpp - shared_array.hpp without member templates +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. +// + +#include +#include +#include +#include + +#include // for std::ptrdiff_t +#include // for std::swap +#include // for std::less +#include // for std::bad_alloc + +namespace boost +{ + +template class shared_array +{ +private: + + typedef detail::atomic_count count_type; + +public: + + typedef T element_type; + + explicit shared_array(T * p = 0): px(p) + { +#ifndef BOOST_NO_EXCEPTIONS + + try // prevent leak if new throws + { + pn = new count_type(1); + } + catch(...) + { + boost::checked_array_delete(p); + throw; + } + +#else + + pn = new count_type(1); + + if(pn == 0) + { + boost::checked_array_delete(p); + boost::throw_exception(std::bad_alloc()); + } + +#endif + } + + ~shared_array() + { + if(--*pn == 0) + { + boost::checked_array_delete(px); + delete pn; + } + } + + shared_array(shared_array const & r) : px(r.px) // never throws + { + pn = r.pn; + ++*pn; + } + + shared_array & operator=(shared_array const & r) + { + shared_array(r).swap(*this); + return *this; + } + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + shared_array(p).swap(*this); + } + + T * get() const // never throws + { + return px; + } + + T & operator[](std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT(px != 0); + BOOST_ASSERT(i >= 0); + return px[i]; + } + + long use_count() const // never throws + { + return *pn; + } + + bool unique() const // never throws + { + return *pn == 1; + } + + void swap(shared_array & other) // never throws + { + std::swap(px, other.px); + std::swap(pn, other.pn); + } + +private: + + T * px; // contained pointer + count_type * pn; // ptr to reference counter + +}; // shared_array + +template inline bool operator==(shared_array const & a, shared_array const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_array const & a, shared_array const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_array const & a, shared_array const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_array & a, shared_array & b) +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_ARRAY_NMT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp new file mode 100644 index 0000000..4943e37 --- /dev/null +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -0,0 +1,444 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SHARED_COUNT_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. +// Copyright 2004-2005 Peter Dimov +// +// 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) +// + +#ifdef __BORLANDC__ +# pragma warn -8027 // Functions containing try are not expanded inline +#endif + +#include +#include +#include +#include +#include +#include +#include +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +#include // std::auto_ptr +#include // std::less +#include // std::bad_alloc + +namespace boost +{ + +namespace detail +{ + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +int const shared_count_id = 0x2C35F101; +int const weak_count_id = 0x298C38A4; + +#endif + +struct sp_nothrow_tag {}; + +class weak_count; + +class shared_count +{ +private: + + 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 explicit shared_count( Y * p ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_impl_p( p ); + } + catch(...) + { + boost::checked_delete( p ); + throw; + } + +#else + + pi_ = new sp_counted_impl_p( p ); + + if( pi_ == 0 ) + { + boost::checked_delete( p ); + boost::throw_exception( std::bad_alloc() ); + } + +#endif + } + +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) + template shared_count( Y * p, D d ): pi_(0) +#else + template shared_count( P p, D d ): pi_(0) +#endif +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) + typedef Y* P; +#endif +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_impl_pd(p, d); + } + catch(...) + { + d(p); // delete p + throw; + } + +#else + + pi_ = new sp_counted_impl_pd(p, d); + + if(pi_ == 0) + { + d(p); // delete p + boost::throw_exception(std::bad_alloc()); + } + +#endif + } + + template shared_count( P p, D d, A a ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + typedef sp_counted_impl_pda impl_type; + typedef typename A::template rebind< impl_type >::other A2; + + A2 a2( a ); + +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); + } + catch(...) + { + d( p ); + + if( pi_ != 0 ) + { + a2.deallocate( static_cast< impl_type* >( pi_ ), 1 ); + } + + throw; + } + +#else + + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + + if( pi_ != 0 ) + { + new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); + } + else + { + d( p ); + boost::throw_exception( std::bad_alloc() ); + } + +#endif + } + +#ifndef BOOST_NO_AUTO_PTR + + // auto_ptr is special cased to provide the strong guarantee + + template + explicit shared_count( std::auto_ptr & r ): pi_( new sp_counted_impl_p( r.get() ) ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifdef BOOST_NO_EXCEPTIONS + + if( pi_ == 0 ) + { + boost::throw_exception(std::bad_alloc()); + } + +#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(); + } + +#if defined( BOOST_HAS_RVALUE_REFS ) + + shared_count(shared_count && r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + r.pi_ = 0; + } + +#endif + + explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 + shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this 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; + } + + bool empty() const // nothrow + { + return pi_ == 0; + } + + 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()( a.pi_, b.pi_ ); + } + + void * get_deleter( sp_typeinfo const & ti ) const + { + return pi_? pi_->get_deleter( ti ): 0; + } +}; + + +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_(weak_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_(weak_count_id) +#endif + { + if(pi_ != 0) pi_->weak_add_ref(); + } + +// Move support + +#if defined( BOOST_HAS_RVALUE_REFS ) + + weak_count(weak_count && r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + r.pi_ = 0; + } + +#endif + + ~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 != 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 != 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; + } + + bool empty() const // nothrow + { + return pi_ == 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()(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() ) + { + boost::throw_exception( boost::bad_weak_ptr() ); + } +} + +inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif +{ + if( pi_ != 0 && !pi_->add_ref_lock() ) + { + pi_ = 0; + } +} + +} // namespace detail + +} // namespace boost + +#ifdef __BORLANDC__ +# pragma warn .8027 // Functions containing try are not expanded inline +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/shared_ptr_nmt.hpp b/include/boost/smart_ptr/detail/shared_ptr_nmt.hpp new file mode 100644 index 0000000..afc1ec0 --- /dev/null +++ b/include/boost/smart_ptr/detail/shared_ptr_nmt.hpp @@ -0,0 +1,182 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED + +// +// detail/shared_ptr_nmt.hpp - shared_ptr.hpp without member templates +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include +#include +#include +#include + +#ifndef BOOST_NO_AUTO_PTR +# include // for std::auto_ptr +#endif + +#include // for std::swap +#include // for std::less +#include // for std::bad_alloc + +namespace boost +{ + +template class shared_ptr +{ +private: + + typedef detail::atomic_count count_type; + +public: + + typedef T element_type; + typedef T value_type; + + explicit shared_ptr(T * p = 0): px(p) + { +#ifndef BOOST_NO_EXCEPTIONS + + try // prevent leak if new throws + { + pn = new count_type(1); + } + catch(...) + { + boost::checked_delete(p); + throw; + } + +#else + + pn = new count_type(1); + + if(pn == 0) + { + boost::checked_delete(p); + boost::throw_exception(std::bad_alloc()); + } + +#endif + } + + ~shared_ptr() + { + if(--*pn == 0) + { + boost::checked_delete(px); + delete pn; + } + } + + shared_ptr(shared_ptr const & r): px(r.px) // never throws + { + pn = r.pn; + ++*pn; + } + + shared_ptr & operator=(shared_ptr const & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#ifndef BOOST_NO_AUTO_PTR + + explicit shared_ptr(std::auto_ptr & r) + { + pn = new count_type(1); // may throw + px = r.release(); // fix: moved here to stop leak if new throws + } + + shared_ptr & operator=(std::auto_ptr & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#endif + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + shared_ptr(p).swap(*this); + } + + T & operator*() const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator->() const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + long use_count() const // never throws + { + return *pn; + } + + bool unique() const // never throws + { + return *pn == 1; + } + + void swap(shared_ptr & other) // never throws + { + std::swap(px, other.px); + std::swap(pn, other.pn); + } + +private: + + T * px; // contained pointer + count_type * pn; // ptr to reference counter +}; + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_ptr & a, shared_ptr & b) +{ + a.swap(b); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_PTR_NMT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_convertible.hpp b/include/boost/smart_ptr/detail/sp_convertible.hpp new file mode 100644 index 0000000..66e5ec7 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_convertible.hpp @@ -0,0 +1,76 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_CONVERTIBLE_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_CONVERTIBLE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_convertible.hpp +// +// Copyright 2008 Peter Dimov +// +// 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 + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && defined( BOOST_NO_SFINAE ) +# define BOOST_SP_NO_SP_CONVERTIBLE +#endif + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ < 303 ) +# define BOOST_SP_NO_SP_CONVERTIBLE +#endif + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && defined( __BORLANDC__ ) && ( __BORLANDC__ <= 0x610 ) +# define BOOST_SP_NO_SP_CONVERTIBLE +#endif + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + +namespace boost +{ + +namespace detail +{ + +template< class Y, class T > struct sp_convertible +{ + typedef char (&yes) [1]; + typedef char (&no) [2]; + + static yes f( T* ); + static no f( ... ); + + enum _vt { value = sizeof( f( static_cast(0) ) ) == sizeof(yes) }; +}; + +struct sp_empty +{ +}; + +template< bool > struct sp_enable_if_convertible_impl; + +template<> struct sp_enable_if_convertible_impl +{ + typedef sp_empty type; +}; + +template<> struct sp_enable_if_convertible_impl +{ +}; + +template< class Y, class T > struct sp_enable_if_convertible: public sp_enable_if_convertible_impl< sp_convertible< Y, T >::value > +{ +}; + +} // namespace detail + +} // namespace boost + +#endif // !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_CONVERTIBLE_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base.hpp b/include/boost/smart_ptr/detail/sp_counted_base.hpp new file mode 100644 index 0000000..cab45cc --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base.hpp @@ -0,0 +1,70 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base.hpp +// +// Copyright 2005, 2006 Peter Dimov +// +// 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 +#include + +#if defined( BOOST_SP_DISABLE_THREADS ) +# include + +#elif defined( BOOST_SP_USE_SPINLOCK ) +# include + +#elif defined( BOOST_SP_USE_PTHREADS ) +# include + +#elif defined( BOOST_DISABLE_THREADS ) && !defined( BOOST_SP_ENABLE_THREADS ) && !defined( BOOST_DISABLE_WIN32 ) +# include + +#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) +# include + +#elif defined( __GNUC__ ) && defined( __ia64__ ) && !defined( __INTEL_COMPILER ) +# include + +#elif defined(__HP_aCC) && defined(__ia64) +# include + +#elif defined( __MWERKS__ ) && defined( __POWERPC__ ) +# include + +#elif defined( __GNUC__ ) && ( defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc ) ) +# include + +#elif defined( __GNUC__ ) && ( defined( __mips__ ) || defined( _mips ) ) +# include + +#elif defined( BOOST_SP_HAS_SYNC ) +# include + +#elif defined(__GNUC__) && ( defined( __sparcv9 ) || ( defined( __sparcv8 ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 402 ) ) ) +# include + +#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined(__CYGWIN__) +# include + +#elif !defined( BOOST_HAS_THREADS ) +# include + +#else +# include + +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp new file mode 100644 index 0000000..dffd995 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp @@ -0,0 +1,150 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_ACC_IA64_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_ACC_IA64_HPP_INCLUDED + +// +// detail/sp_counted_base_acc_ia64.hpp - aC++ on HP-UX IA64 +// +// Copyright 2007 Baruch Zilber +// Copyright 2007 Boris Gubenko +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// + +#include +#include + +namespace boost +{ + +namespace detail +{ + +inline void atomic_increment( int * pw ) +{ + // ++*pw; + + _Asm_fetchadd(_FASZ_W, _SEM_REL, pw, +1, _LDHINT_NONE); +} + +inline int atomic_decrement( int * pw ) +{ + // return --*pw; + + int r = static_cast(_Asm_fetchadd(_FASZ_W, _SEM_REL, pw, -1, _LDHINT_NONE)); + if (1 == r) + { + _Asm_mf(); + } + + return r - 1; +} + +inline int atomic_conditional_increment( int * pw ) +{ + // if( *pw != 0 ) ++*pw; + // return *pw; + + int v = *pw; + + for (;;) + { + if (0 == v) + { + return 0; + } + + _Asm_mov_to_ar(_AREG_CCV, + v, + (_UP_CALL_FENCE | _UP_SYS_FENCE | _DOWN_CALL_FENCE | _DOWN_SYS_FENCE)); + int r = static_cast(_Asm_cmpxchg(_SZ_W, _SEM_ACQ, pw, v + 1, _LDHINT_NONE)); + if (r == v) + { + return r + 1; + } + + v = r; + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); // TODO use ld.acq here + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_ACC_IA64_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp new file mode 100644 index 0000000..51ac56a --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp @@ -0,0 +1,170 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_PPC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_PPC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_cw_ppc.hpp - CodeWarrior on PowerPC +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline void atomic_increment( register long * pw ) +{ + register int a; + + asm + { +loop: + + lwarx a, 0, pw + addi a, a, 1 + stwcx. a, 0, pw + bne- loop + } +} + +inline long atomic_decrement( register long * pw ) +{ + register int a; + + asm + { + sync + +loop: + + lwarx a, 0, pw + addi a, a, -1 + stwcx. a, 0, pw + bne- loop + + isync + } + + return a; +} + +inline long atomic_conditional_increment( register long * pw ) +{ + register int a; + + asm + { +loop: + + lwarx a, 0, pw + cmpwi a, 0 + beq store + + addi a, a, 1 + +store: + + stwcx. a, 0, pw + bne- loop + } + + return a; +} + +class sp_counted_base +{ +private: + + 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) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_PPC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp new file mode 100644 index 0000000..1234e78 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp @@ -0,0 +1,158 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_X86_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_X86_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_cw_x86.hpp - CodeWarrion on 486+ +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// Copyright 2005 Rene Rivera +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline int atomic_exchange_and_add( int * pw, int dv ) +{ + // int r = *pw; + // *pw += dv; + // return r; + + asm + { + mov esi, [pw] + mov eax, dv + lock xadd dword ptr [esi], eax + } +} + +inline void atomic_increment( int * pw ) +{ + //atomic_exchange_and_add( pw, 1 ); + + asm + { + mov esi, [pw] + lock inc dword ptr [esi] + } +} + +inline int atomic_conditional_increment( int * pw ) +{ + // int rv = *pw; + // if( rv != 0 ) ++*pw; + // return rv; + + asm + { + mov esi, [pw] + mov eax, dword ptr [esi] + L0: + test eax, eax + je L1 + mov ebx, eax + inc ebx + lock cmpxchg dword ptr [esi], ebx + jne L0 + L1: + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CW_X86_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp new file mode 100644 index 0000000..d122a49 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp @@ -0,0 +1,157 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_IA64_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_IA64_HPP_INCLUDED + +// +// detail/sp_counted_base_gcc_ia64.hpp - g++ on IA64 +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2006 Peter Dimov +// Copyright 2005 Ben Hutchings +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline void atomic_increment( int * pw ) +{ + // ++*pw; + + int tmp; + + // No barrier is required here but fetchadd always has an acquire or + // release barrier associated with it. We choose release as it should be + // cheaper. + __asm__ ("fetchadd4.rel %0=%1,1" : + "=r"(tmp), "=m"(*pw) : + "m"( *pw )); +} + +inline int atomic_decrement( int * pw ) +{ + // return --*pw; + + int rv; + + __asm__ (" fetchadd4.rel %0=%1,-1 ;; \n" + " cmp.eq p7,p0=1,%0 ;; \n" + "(p7) ld4.acq %0=%1 " : + "=&r"(rv), "=m"(*pw) : + "m"( *pw ) : + "p7"); + + return rv; +} + +inline int atomic_conditional_increment( int * pw ) +{ + // if( *pw != 0 ) ++*pw; + // return *pw; + + int rv, tmp, tmp2; + + __asm__ ("0: ld4 %0=%3 ;; \n" + " cmp.eq p7,p0=0,%0 ;; \n" + "(p7) br.cond.spnt 1f \n" + " mov ar.ccv=%0 \n" + " add %1=1,%0 ;; \n" + " cmpxchg4.acq %2=%3,%1,ar.ccv ;; \n" + " cmp.ne p7,p0=%0,%2 ;; \n" + "(p7) br.cond.spnt 0b \n" + " mov %0=%1 ;; \n" + "1:" : + "=&r"(rv), "=&r"(tmp), "=&r"(tmp2), "=m"(*pw) : + "m"( *pw ) : + "ar.ccv", "p7"); + + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); // TODO use ld.acq here + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_IA64_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp new file mode 100644 index 0000000..0c69b0b --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp @@ -0,0 +1,172 @@ +#ifndef BOOST_DETAIL_SP_COUNTED_BASE_GCC_MIPS_HPP_INCLUDED +#define BOOST_DETAIL_SP_COUNTED_BASE_GCC_MIPS_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_gcc_mips.hpp - g++ on MIPS +// +// Copyright (c) 2009, Spirent Communications, Inc. +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline void atomic_increment( int * pw ) +{ + // ++*pw; + + int tmp; + + __asm__ __volatile__ + ( + "0:\n\t" + "ll %0, %1\n\t" + "addiu %0, 1\n\t" + "sc %0, %1\n\t" + "beqz %0, 0b": + "=&r"( tmp ), "=m"( *pw ): + "m"( *pw ) + ); +} + +inline int atomic_decrement( int * pw ) +{ + // return --*pw; + + int rv, tmp; + + __asm__ __volatile__ + ( + "0:\n\t" + "ll %1, %2\n\t" + "addiu %0, %1, -1\n\t" + "sc %0, %2\n\t" + "beqz %0, 0b\n\t" + "addiu %0, %1, -1": + "=&r"( rv ), "=&r"( tmp ), "=m"( *pw ): + "m"( *pw ): + "memory" + ); + + return rv; +} + +inline int atomic_conditional_increment( int * pw ) +{ + // if( *pw != 0 ) ++*pw; + // return *pw; + + int rv, tmp; + + __asm__ __volatile__ + ( + "0:\n\t" + "ll %0, %2\n\t" + "beqz %0, 1f\n\t" + "addiu %1, %0, 1\n\t" + "sc %1, %2\n\t" + "beqz %1, 0b\n\t" + "addiu %0, %0, 1\n\t" + "1:": + "=&r"( rv ), "=&r"( tmp ), "=m"( *pw ): + "m"( *pw ): + "memory" + ); + + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SP_COUNTED_BASE_GCC_MIPS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp new file mode 100644 index 0000000..7f5c414 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp @@ -0,0 +1,181 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_PPC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_PPC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_gcc_ppc.hpp - g++ on PowerPC +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline void atomic_increment( int * pw ) +{ + // ++*pw; + + int tmp; + + __asm__ + ( + "0:\n\t" + "lwarx %1, 0, %2\n\t" + "addi %1, %1, 1\n\t" + "stwcx. %1, 0, %2\n\t" + "bne- 0b": + + "=m"( *pw ), "=&b"( tmp ): + "r"( pw ), "m"( *pw ): + "cc" + ); +} + +inline int atomic_decrement( int * pw ) +{ + // return --*pw; + + int rv; + + __asm__ __volatile__ + ( + "sync\n\t" + "0:\n\t" + "lwarx %1, 0, %2\n\t" + "addi %1, %1, -1\n\t" + "stwcx. %1, 0, %2\n\t" + "bne- 0b\n\t" + "isync": + + "=m"( *pw ), "=&b"( rv ): + "r"( pw ), "m"( *pw ): + "memory", "cc" + ); + + return rv; +} + +inline int atomic_conditional_increment( int * pw ) +{ + // if( *pw != 0 ) ++*pw; + // return *pw; + + int rv; + + __asm__ + ( + "0:\n\t" + "lwarx %1, 0, %2\n\t" + "cmpwi %1, 0\n\t" + "beq 1f\n\t" + "addi %1, %1, 1\n\t" + "1:\n\t" + "stwcx. %1, 0, %2\n\t" + "bne- 0b": + + "=m"( *pw ), "=&b"( rv ): + "r"( pw ), "m"( *pw ): + "cc" + ); + + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_PPC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp new file mode 100644 index 0000000..8af6f0a --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp @@ -0,0 +1,166 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_SPARC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_SPARC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_counted_base_gcc_sparc.hpp - g++ on Sparc V8+ +// +// Copyright (c) 2006 Piotr Wyderski +// Copyright (c) 2006 Tomas Puverle +// Copyright (c) 2006 Peter Dimov +// +// 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 +// +// Thanks to Michael van der Westhuizen + +#include +#include // int32_t + +namespace boost +{ + +namespace detail +{ + +inline int32_t compare_and_swap( int32_t * dest_, int32_t compare_, int32_t swap_ ) +{ + __asm__ __volatile__( "cas %0, %2, %1" + : "+m" (*dest_), "+r" (swap_) + : "r" (compare_) + : "memory" ); + + return swap_; +} + +inline int32_t atomic_fetch_and_add( int32_t * pw, int32_t dv ) +{ + // long r = *pw; + // *pw += dv; + // return r; + + for( ;; ) + { + int32_t r = *pw; + + if( __builtin_expect((compare_and_swap(pw, r, r + dv) == r), 1) ) + { + return r; + } + } +} + +inline void atomic_increment( int32_t * pw ) +{ + atomic_fetch_and_add( pw, 1 ); +} + +inline int32_t atomic_decrement( int32_t * pw ) +{ + return atomic_fetch_and_add( pw, -1 ); +} + +inline int32_t atomic_conditional_increment( int32_t * pw ) +{ + // long r = *pw; + // if( r != 0 ) ++*pw; + // return r; + + for( ;; ) + { + int32_t r = *pw; + + if( r == 0 ) + { + return r; + } + + if( __builtin_expect( ( compare_and_swap( pw, r, r + 1 ) == r ), 1 ) ) + { + return r; + } + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int32_t use_count_; // #shared + int32_t weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return const_cast< int32_t const volatile & >( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_SPARC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp new file mode 100644 index 0000000..4d7fa8d --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp @@ -0,0 +1,173 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_X86_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_X86_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_gcc_x86.hpp - g++ on 486+ or AMD64 +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include + +namespace boost +{ + +namespace detail +{ + +inline int atomic_exchange_and_add( int * pw, int dv ) +{ + // int r = *pw; + // *pw += dv; + // return r; + + int r; + + __asm__ __volatile__ + ( + "lock\n\t" + "xadd %1, %0": + "=m"( *pw ), "=r"( r ): // outputs (%0, %1) + "m"( *pw ), "1"( dv ): // inputs (%2, %3 == %1) + "memory", "cc" // clobbers + ); + + return r; +} + +inline void atomic_increment( int * pw ) +{ + //atomic_exchange_and_add( pw, 1 ); + + __asm__ + ( + "lock\n\t" + "incl %0": + "=m"( *pw ): // output (%0) + "m"( *pw ): // input (%1) + "cc" // clobbers + ); +} + +inline int atomic_conditional_increment( int * pw ) +{ + // int rv = *pw; + // if( rv != 0 ) ++*pw; + // return rv; + + int rv, tmp; + + __asm__ + ( + "movl %0, %%eax\n\t" + "0:\n\t" + "test %%eax, %%eax\n\t" + "je 1f\n\t" + "movl %%eax, %2\n\t" + "incl %2\n\t" + "lock\n\t" + "cmpxchgl %2, %0\n\t" + "jne 0b\n\t" + "1:": + "=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2) + "m"( *pw ): // input (%3) + "cc" // clobbers + ); + + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_GCC_X86_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp new file mode 100644 index 0000000..dfd70e7 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp @@ -0,0 +1,107 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_NT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_NT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_nt.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class sp_counted_base +{ +private: + + 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) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + ++use_count_; + } + + bool add_ref_lock() // true on success + { + if( use_count_ == 0 ) return false; + ++use_count_; + return true; + } + + void release() // nothrow + { + if( --use_count_ == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + ++weak_count_; + } + + void weak_release() // nothrow + { + if( --weak_count_ == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return use_count_; + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_NT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp new file mode 100644 index 0000000..3c56fec --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp @@ -0,0 +1,135 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_pt.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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 +#include + +namespace boost +{ + +namespace detail +{ + +class sp_counted_base +{ +private: + + 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) + + mutable pthread_mutex_t m_; + +public: + + sp_counted_base(): use_count_( 1 ), weak_count_( 1 ) + { +// HPUX 10.20 / DCE has a nonstandard pthread_mutex_init + +#if defined(__hpux) && defined(_DECTHREADS_) + pthread_mutex_init( &m_, pthread_mutexattr_default ); +#else + pthread_mutex_init( &m_, 0 ); +#endif + } + + virtual ~sp_counted_base() // nothrow + { + pthread_mutex_destroy( &m_ ); + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + + virtual void dispose() = 0; // nothrow + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + pthread_mutex_lock( &m_ ); + ++use_count_; + pthread_mutex_unlock( &m_ ); + } + + bool add_ref_lock() // true on success + { + pthread_mutex_lock( &m_ ); + bool r = use_count_ == 0? false: ( ++use_count_, true ); + pthread_mutex_unlock( &m_ ); + return r; + } + + void release() // nothrow + { + pthread_mutex_lock( &m_ ); + long new_use_count = --use_count_; + pthread_mutex_unlock( &m_ ); + + if( new_use_count == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + pthread_mutex_lock( &m_ ); + ++weak_count_; + pthread_mutex_unlock( &m_ ); + } + + void weak_release() // nothrow + { + pthread_mutex_lock( &m_ ); + long new_weak_count = --weak_count_; + pthread_mutex_unlock( &m_ ); + + if( new_weak_count == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + pthread_mutex_lock( &m_ ); + long r = use_count_; + pthread_mutex_unlock( &m_ ); + + return r; + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp new file mode 100644 index 0000000..d1b6bec --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp @@ -0,0 +1,113 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SOLARIS_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SOLARIS_HPP_INCLUDED + +// +// detail/sp_counted_base_solaris.hpp +// based on: detail/sp_counted_base_w32.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// Copyright 2006 Michael van der Westhuizen +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include +#include + +namespace boost +{ + +namespace detail +{ + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + uint32_t use_count_; // #shared + uint32_t weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_inc_32( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + for( ;; ) + { + uint32_t tmp = static_cast< uint32_t const volatile& >( use_count_ ); + if( tmp == 0 ) return false; + if( atomic_cas_32( &use_count_, tmp, tmp + 1 ) == tmp ) return true; + } + } + + void release() // nothrow + { + if( atomic_dec_32_nv( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_inc_32( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_dec_32_nv( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SOLARIS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp new file mode 100644 index 0000000..bbd11e6 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp @@ -0,0 +1,131 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_spin.hpp - spinlock pool atomic emulation +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2008 Peter Dimov +// +// 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 +#include + +namespace boost +{ + +namespace detail +{ + +inline int atomic_exchange_and_add( int * pw, int dv ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + + int r = *pw; + *pw += dv; + return r; +} + +inline void atomic_increment( int * pw ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + ++*pw; +} + +inline int atomic_conditional_increment( int * pw ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + + int rv = *pw; + if( rv != 0 ) ++*pw; + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + spinlock_pool<1>::scoped_lock lock( &use_count_ ); + return use_count_; + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp new file mode 100644 index 0000000..41f654e --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp @@ -0,0 +1,155 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SYNC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SYNC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_counted_base_sync.hpp - g++ 4.1+ __sync intrinsics +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include + +#if defined( __ia64__ ) && defined( __INTEL_COMPILER ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#if INT_MAX >= 2147483647 + +typedef int sp_int32_t; + +#else + +typedef long sp_int32_t; + +#endif + +inline void atomic_increment( sp_int32_t * pw ) +{ + __sync_fetch_and_add( pw, 1 ); +} + +inline sp_int32_t atomic_decrement( sp_int32_t * pw ) +{ + return __sync_fetch_and_add( pw, -1 ); +} + +inline sp_int32_t atomic_conditional_increment( sp_int32_t * pw ) +{ + // long r = *pw; + // if( r != 0 ) ++*pw; + // return r; + + sp_int32_t r = *pw; + + for( ;; ) + { + if( r == 0 ) + { + return r; + } + + sp_int32_t r2 = __sync_val_compare_and_swap( pw, r, r + 1 ); + + if( r2 == r ) + { + return r; + } + else + { + r = r2; + } + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + sp_int32_t use_count_; // #shared + sp_int32_t weak_count_; // #weak + (#shared != 0) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return const_cast< sp_int32_t const volatile & >( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_SYNC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp new file mode 100644 index 0000000..06aa456 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp @@ -0,0 +1,130 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_w32.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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) +// +// +// Lock-free algorithm by Alexander Terekhov +// +// Thanks to Ben Hitchings for the #weak + (#shared != 0) +// formulation +// + +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +class sp_counted_base +{ +private: + + 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) + +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 + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + BOOST_INTERLOCKED_INCREMENT( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + for( ;; ) + { + long tmp = static_cast< long const volatile& >( use_count_ ); + if( tmp == 0 ) return false; + +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, == 1200 ) + + // work around a code generation bug + + long tmp2 = tmp + 1; + if( BOOST_INTERLOCKED_COMPARE_EXCHANGE( &use_count_, tmp2, tmp ) == tmp2 - 1 ) return true; + +#else + + if( BOOST_INTERLOCKED_COMPARE_EXCHANGE( &use_count_, tmp + 1, tmp ) == tmp ) return true; + +#endif + } + } + + void release() // nothrow + { + if( BOOST_INTERLOCKED_DECREMENT( &use_count_ ) == 0 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + BOOST_INTERLOCKED_INCREMENT( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( BOOST_INTERLOCKED_DECREMENT( &weak_count_ ) == 0 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return static_cast( use_count_ ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp new file mode 100644 index 0000000..397421a --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -0,0 +1,231 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_impl.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// 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 + +#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 +#include + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) +#include +#endif + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) +#include // std::allocator +#endif + +#include // std::size_t + +namespace boost +{ + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +void sp_scalar_constructor_hook( void * px, std::size_t size, void * pn ); +void sp_scalar_destructor_hook( void * px, std::size_t size, void * pn ); + +#endif + +namespace detail +{ + +template class sp_counted_impl_p: public sp_counted_base +{ +private: + + X * px_; + + sp_counted_impl_p( sp_counted_impl_p const & ); + sp_counted_impl_p & operator= ( sp_counted_impl_p const & ); + + typedef sp_counted_impl_p this_type; + +public: + + explicit sp_counted_impl_p( X * px ): px_( px ) + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_constructor_hook( px, sizeof(X), this ); +#endif + } + + virtual void dispose() // nothrow + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_destructor_hook( px_, sizeof(X), this ); +#endif + boost::checked_delete( px_ ); + } + + virtual void * get_deleter( detail::sp_typeinfo const & ) + { + return 0; + } + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) + + void * operator new( std::size_t ) + { + return std::allocator().allocate( 1, static_cast(0) ); + } + + void operator delete( void * p ) + { + std::allocator().deallocate( static_cast(p), 1 ); + } + +#endif + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) + + void * operator new( std::size_t ) + { + return quick_allocator::alloc(); + } + + void operator delete( void * p ) + { + quick_allocator::dealloc( p ); + } + +#endif +}; + +// +// Borland's Codeguard trips up over the -Vx- option here: +// +#ifdef __CODEGUARD__ +# pragma option push -Vx- +#endif + +template class sp_counted_impl_pd: public sp_counted_base +{ +private: + + P ptr; // copy constructor must not throw + D del; // copy constructor must not throw + + sp_counted_impl_pd( sp_counted_impl_pd const & ); + sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); + + typedef sp_counted_impl_pd this_type; + +public: + + // pre: d(p) must not throw + + sp_counted_impl_pd( P p, D d ): ptr(p), del(d) + { + } + + virtual void dispose() // nothrow + { + del( ptr ); + } + + virtual void * get_deleter( detail::sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast( del ): 0; + } + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) + + void * operator new( std::size_t ) + { + return std::allocator().allocate( 1, static_cast(0) ); + } + + void operator delete( void * p ) + { + std::allocator().deallocate( static_cast(p), 1 ); + } + +#endif + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) + + void * operator new( std::size_t ) + { + return quick_allocator::alloc(); + } + + void operator delete( void * p ) + { + quick_allocator::dealloc( p ); + } + +#endif +}; + +template class sp_counted_impl_pda: public sp_counted_base +{ +private: + + P p_; // copy constructor must not throw + D d_; // copy constructor must not throw + A a_; // copy constructor must not throw + + sp_counted_impl_pda( sp_counted_impl_pda const & ); + sp_counted_impl_pda & operator= ( sp_counted_impl_pda const & ); + + typedef sp_counted_impl_pda this_type; + +public: + + // pre: d( p ) must not throw + + sp_counted_impl_pda( P p, D d, A a ): p_( p ), d_( d ), a_( a ) + { + } + + virtual void dispose() // nothrow + { + d_( p_ ); + } + + virtual void destroy() // nothrow + { + typedef typename A::template rebind< this_type >::other A2; + + A2 a2( a_ ); + + this->~this_type(); + a2.deallocate( this, 1 ); + } + + virtual void * get_deleter( detail::sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID( D )? &reinterpret_cast( d_ ): 0; + } +}; + +#ifdef __CODEGUARD__ +# pragma option pop +#endif + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_has_sync.hpp b/include/boost/smart_ptr/detail/sp_has_sync.hpp new file mode 100644 index 0000000..cb0282d --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_has_sync.hpp @@ -0,0 +1,49 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_HAS_SYNC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_HAS_SYNC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/smart_ptr/detail/sp_has_sync.hpp +// +// Copyright (c) 2008, 2009 Peter Dimov +// +// 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) +// +// Defines the BOOST_SP_HAS_SYNC macro if the __sync_* intrinsics +// are available. +// + +#if defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + +#define BOOST_SP_HAS_SYNC + +#if defined( __arm__ ) || defined( __armel__ ) +#undef BOOST_SP_HAS_SYNC +#endif + +#if defined( __hppa ) || defined( __hppa__ ) +#undef BOOST_SP_HAS_SYNC +#endif + +#if defined( __m68k__ ) +#undef BOOST_SP_HAS_SYNC +#endif + +#if defined( __sparc__ ) +#undef BOOST_SP_HAS_SYNC +#endif + +#if defined( __INTEL_COMPILER ) && !defined( __ia64__ ) +#undef BOOST_SP_HAS_SYNC +#endif + +#endif // __GNUC__ * 100 + __GNUC_MINOR__ >= 401 + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_HAS_SYNC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock.hpp b/include/boost/smart_ptr/detail/spinlock.hpp new file mode 100644 index 0000000..1640a38 --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock.hpp @@ -0,0 +1,53 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/spinlock.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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) +// +// struct spinlock +// { +// void lock(); +// bool try_lock(); +// void unlock(); +// +// class scoped_lock; +// }; +// +// #define BOOST_DETAIL_SPINLOCK_INIT +// + +#include +#include + +#if defined(__GNUC__) && defined( __arm__ ) && !defined( __thumb__ ) +# include + +#elif defined( BOOST_SP_HAS_SYNC ) +# include + +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include + +#elif defined(BOOST_HAS_PTHREADS) +# include + +#elif !defined(BOOST_HAS_THREADS) +# include + +#else +# error Unrecognized threading platform +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_gcc_arm.hpp b/include/boost/smart_ptr/detail/spinlock_gcc_arm.hpp new file mode 100644 index 0000000..ba6c511 --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_gcc_arm.hpp @@ -0,0 +1,85 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + int v_; + +public: + + bool try_lock() + { + int r; + + __asm__ __volatile__( + "swp %0, %1, [%2]": + "=&r"( r ): // outputs + "r"( 1 ), "r"( &v_ ): // inputs + "memory", "cc" ); + + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + __asm__ __volatile__( "" ::: "memory" ); + *const_cast< int volatile* >( &v_ ) = 0; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_nt.hpp b/include/boost/smart_ptr/detail/spinlock_nt.hpp new file mode 100644 index 0000000..1f399d0 --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_nt.hpp @@ -0,0 +1,89 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_NT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_NT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + bool locked_; + +public: + + inline bool try_lock() + { + if( locked_ ) + { + return false; + } + else + { + locked_ = true; + return true; + } + } + + inline void lock() + { + BOOST_ASSERT( !locked_ ); + locked_ = true; + } + + inline void unlock() + { + BOOST_ASSERT( locked_ ); + locked_ = false; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT { false } + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_NT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_pool.hpp b/include/boost/smart_ptr/detail/spinlock_pool.hpp new file mode 100644 index 0000000..0e2e08a --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_pool.hpp @@ -0,0 +1,87 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_POOL_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_POOL_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/spinlock_pool.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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) +// +// spinlock_pool<0> is reserved for atomic<>, when/if it arrives +// spinlock_pool<1> is reserved for shared_ptr reference counts +// spinlock_pool<2> is reserved for shared_ptr atomic access +// + +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template< int I > class spinlock_pool +{ +private: + + static spinlock pool_[ 41 ]; + +public: + + static spinlock & spinlock_for( void const * pv ) + { + std::size_t i = reinterpret_cast< std::size_t >( pv ) % 41; + return pool_[ i ]; + } + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( void const * pv ): sp_( spinlock_for( pv ) ) + { + sp_.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +template< int I > spinlock spinlock_pool< I >::pool_[ 41 ] = +{ + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT +}; + +} // namespace detail +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_POOL_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_pt.hpp b/include/boost/smart_ptr/detail/spinlock_pt.hpp new file mode 100644 index 0000000..f9cabfc --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_pt.hpp @@ -0,0 +1,79 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_PT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_PT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + pthread_mutex_t v_; + +public: + + bool try_lock() + { + return pthread_mutex_trylock( &v_ ) == 0; + } + + void lock() + { + pthread_mutex_lock( &v_ ); + } + + void unlock() + { + pthread_mutex_unlock( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT { PTHREAD_MUTEX_INITIALIZER } + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_PT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_sync.hpp b/include/boost/smart_ptr/detail/spinlock_sync.hpp new file mode 100644 index 0000000..a7145c5 --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_sync.hpp @@ -0,0 +1,87 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +#if defined( __ia64__ ) && defined( __INTEL_COMPILER ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + int v_; + +public: + + bool try_lock() + { + int r = __sync_lock_test_and_set( &v_, 1 ); + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + __sync_lock_release( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/spinlock_w32.hpp b/include/boost/smart_ptr/detail/spinlock_w32.hpp new file mode 100644 index 0000000..fb97629 --- /dev/null +++ b/include/boost/smart_ptr/detail/spinlock_w32.hpp @@ -0,0 +1,113 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_W32_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SPINLOCK_W32_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +// BOOST_COMPILER_FENCE + +#if defined(__INTEL_COMPILER) + +#define BOOST_COMPILER_FENCE __memory_barrier(); + +#elif defined( _MSC_VER ) && _MSC_VER >= 1310 + +extern "C" void _ReadWriteBarrier(); +#pragma intrinsic( _ReadWriteBarrier ) + +#define BOOST_COMPILER_FENCE _ReadWriteBarrier(); + +#elif defined(__GNUC__) + +#define BOOST_COMPILER_FENCE __asm__ __volatile__( "" : : : "memory" ); + +#else + +#define BOOST_COMPILER_FENCE + +#endif + +// + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + long v_; + +public: + + bool try_lock() + { + long r = BOOST_INTERLOCKED_EXCHANGE( &v_, 1 ); + + BOOST_COMPILER_FENCE + + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + BOOST_COMPILER_FENCE + *const_cast< long volatile* >( &v_ ) = 0; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SPINLOCK_W32_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/yield_k.hpp b/include/boost/smart_ptr/detail/yield_k.hpp new file mode 100644 index 0000000..a956cc0 --- /dev/null +++ b/include/boost/smart_ptr/detail/yield_k.hpp @@ -0,0 +1,149 @@ +#ifndef BOOST_SMART_PTR_DETAIL_YIELD_K_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_YIELD_K_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// yield_k.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// void yield( unsigned k ); +// +// Typical use: +// +// for( unsigned k = 0; !try_lock(); ++k ) yield( k ); +// +// 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_SMT_PAUSE + +#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) + +extern "C" void _mm_pause(); +#pragma intrinsic( _mm_pause ) + +#define BOOST_SMT_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#endif + +// + +#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined( __CYGWIN__ ) + +#if defined( BOOST_USE_WINDOWS_H ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#if !defined( BOOST_USE_WINDOWS_H ) + extern "C" void __stdcall Sleep( unsigned ms ); +#endif + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_SMT_PAUSE ) + else if( k < 16 ) + { + BOOST_SMT_PAUSE + } +#endif + else if( k < 32 ) + { + Sleep( 0 ); + } + else + { + Sleep( 1 ); + } +} + +} // namespace detail + +} // namespace boost + +#elif defined( BOOST_HAS_PTHREADS ) + +#include +#include + +namespace boost +{ + +namespace detail +{ + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_SMT_PAUSE ) + else if( k < 16 ) + { + BOOST_SMT_PAUSE + } +#endif + else if( k < 32 || k & 1 ) + { + sched_yield(); + } + else + { + // g++ -Wextra warns on {} or {0} + struct timespec rqtp = { 0, 0 }; + + // POSIX says that timespec has tv_sec and tv_nsec + // But it doesn't guarantee order or placement + + rqtp.tv_sec = 0; + rqtp.tv_nsec = 1000; + + nanosleep( &rqtp, 0 ); + } +} + +} // namespace detail + +} // namespace boost + +#else + +namespace boost +{ + +namespace detail +{ + +inline void yield( unsigned ) +{ +} + +} // namespace detail + +} // namespace boost + +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_YIELD_K_HPP_INCLUDED diff --git a/include/boost/smart_ptr/enable_shared_from_this.hpp b/include/boost/smart_ptr/enable_shared_from_this.hpp new file mode 100644 index 0000000..f7b1445 --- /dev/null +++ b/include/boost/smart_ptr/enable_shared_from_this.hpp @@ -0,0 +1,79 @@ +#ifndef BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED +#define BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + +// +// enable_shared_from_this.hpp +// +// Copyright 2002, 2009 Peter Dimov +// +// 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 +// +// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html +// + +#include +#include +#include +#include + +namespace boost +{ + +template class enable_shared_from_this +{ +protected: + + enable_shared_from_this() + { + } + + enable_shared_from_this(enable_shared_from_this const &) + { + } + + enable_shared_from_this & operator=(enable_shared_from_this const &) + { + return *this; + } + + ~enable_shared_from_this() + { + } + +public: + + shared_ptr shared_from_this() + { + shared_ptr p( weak_this_ ); + BOOST_ASSERT( p.get() == this ); + return p; + } + + shared_ptr shared_from_this() const + { + shared_ptr p( weak_this_ ); + BOOST_ASSERT( p.get() == this ); + return p; + } + +public: // actually private, but avoids compiler template friendship issues + + // Note: invoked automatically by shared_ptr; do not call + template void _internal_accept_owner( shared_ptr const * ppx, Y * py ) const + { + if( weak_this_.expired() ) + { + weak_this_ = shared_ptr( *ppx, py ); + } + } + +private: + + mutable weak_ptr weak_this_; +}; + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED diff --git a/include/boost/smart_ptr/enable_shared_from_this2.hpp b/include/boost/smart_ptr/enable_shared_from_this2.hpp new file mode 100644 index 0000000..a5bfcff --- /dev/null +++ b/include/boost/smart_ptr/enable_shared_from_this2.hpp @@ -0,0 +1,132 @@ +#ifndef BOOST_ENABLE_SHARED_FROM_THIS2_HPP_INCLUDED +#define BOOST_ENABLE_SHARED_FROM_THIS2_HPP_INCLUDED + +// +// enable_shared_from_this2.hpp +// +// Copyright 2002, 2009 Peter Dimov +// Copyright 2008 Frank Mori Hess +// +// 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 +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +class esft2_deleter_wrapper +{ +private: + + shared_ptr deleter_; + +public: + + esft2_deleter_wrapper() + { + } + + template< class T > void set_deleter( shared_ptr const & deleter ) + { + deleter_ = deleter; + } + + template< class T> void operator()( T* ) + { + BOOST_ASSERT( deleter_.use_count() <= 1 ); + deleter_.reset(); + } +}; + +} // namespace detail + +template< class T > class enable_shared_from_this2 +{ +protected: + + enable_shared_from_this2() + { + } + + enable_shared_from_this2( enable_shared_from_this2 const & ) + { + } + + enable_shared_from_this2 & operator=( enable_shared_from_this2 const & ) + { + return *this; + } + + ~enable_shared_from_this2() + { + BOOST_ASSERT( shared_this_.use_count() <= 1 ); // make sure no dangling shared_ptr objects exist + } + +private: + + mutable weak_ptr weak_this_; + mutable shared_ptr shared_this_; + +public: + + shared_ptr shared_from_this() + { + init_weak_once(); + return shared_ptr( weak_this_ ); + } + + shared_ptr shared_from_this() const + { + init_weak_once(); + return shared_ptr( weak_this_ ); + } + +private: + + void init_weak_once() const + { + if( weak_this_._empty() ) + { + shared_this_.reset( static_cast< T* >( 0 ), detail::esft2_deleter_wrapper() ); + weak_this_ = shared_this_; + } + } + +public: // actually private, but avoids compiler template friendship issues + + // Note: invoked automatically by shared_ptr; do not call + template void _internal_accept_owner( shared_ptr * ppx, Y * py ) const + { + BOOST_ASSERT( ppx != 0 ); + + if( weak_this_.use_count() == 0 ) + { + weak_this_ = shared_ptr( *ppx, py ); + } + else if( shared_this_.use_count() != 0 ) + { + BOOST_ASSERT( ppx->unique() ); // no weak_ptrs should exist either, but there's no way to check that + + detail::esft2_deleter_wrapper * pd = boost::get_deleter( shared_this_ ); + BOOST_ASSERT( pd != 0 ); + + pd->set_deleter( *ppx ); + + ppx->reset( shared_this_, ppx->get() ); + shared_this_.reset(); + } + } +}; + +} // namespace boost + +#endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS2_HPP_INCLUDED diff --git a/include/boost/smart_ptr/intrusive_ptr.hpp b/include/boost/smart_ptr/intrusive_ptr.hpp new file mode 100644 index 0000000..6927a59 --- /dev/null +++ b/include/boost/smart_ptr/intrusive_ptr.hpp @@ -0,0 +1,299 @@ +#ifndef BOOST_SMART_PTR_INTRUSIVE_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_INTRUSIVE_PTR_HPP_INCLUDED + +// +// intrusive_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation. +// + +#include + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +#include +#include +#include + +#include // for std::less + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) +#include // for std::basic_ostream +#else +#include +#endif +#endif + + +namespace boost +{ + +// +// intrusive_ptr +// +// A smart pointer that uses intrusive reference counting. +// +// Relies on unqualified calls to +// +// void intrusive_ptr_add_ref(T * p); +// void intrusive_ptr_release(T * p); +// +// (p != 0) +// +// The object is responsible for destroying itself. +// + +template class intrusive_ptr +{ +private: + + typedef intrusive_ptr this_type; + +public: + + typedef T element_type; + + intrusive_ptr(): px( 0 ) + { + } + + intrusive_ptr( T * p, bool add_ref = true ): px( p ) + { + if( px != 0 && add_ref ) intrusive_ptr_add_ref( px ); + } + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + intrusive_ptr( intrusive_ptr const & rhs, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + intrusive_ptr( intrusive_ptr const & rhs ) + +#endif + : px( rhs.get() ) + { + if( px != 0 ) intrusive_ptr_add_ref( px ); + } + +#endif + + intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px ) + { + if( px != 0 ) intrusive_ptr_add_ref( px ); + } + + ~intrusive_ptr() + { + if( px != 0 ) intrusive_ptr_release( px ); + } + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES) + + template intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + +#endif + +// Move support + +#if defined( BOOST_HAS_RVALUE_REFS ) + + intrusive_ptr(intrusive_ptr && rhs): px( rhs.px ) + { + rhs.px = 0; + } + + intrusive_ptr & operator=(intrusive_ptr && rhs) + { + this_type(std::move(rhs)).swap(*this); + return *this; + } + +#endif + + intrusive_ptr & operator=(intrusive_ptr const & rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + intrusive_ptr & operator=(T * rhs) + { + this_type(rhs).swap(*this); + return *this; + } + + void reset() + { + this_type().swap( *this ); + } + + void reset( T * rhs ) + { + this_type( rhs ).swap( *this ); + } + + T * get() const + { + return px; + } + + T & operator*() const + { + BOOST_ASSERT( px != 0 ); + return *px; + } + + T * operator->() const + { + BOOST_ASSERT( px != 0 ); + return px; + } + +// implicit conversion to "bool" +#include + + void swap(intrusive_ptr & rhs) + { + T * tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + + T * px; +}; + +template inline bool operator==(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator==(intrusive_ptr const & a, U * b) +{ + return a.get() == b; +} + +template inline bool operator!=(intrusive_ptr const & a, U * b) +{ + return a.get() != b; +} + +template inline bool operator==(T * a, intrusive_ptr const & b) +{ + return a == b.get(); +} + +template inline bool operator!=(T * a, intrusive_ptr const & b) +{ + return a != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return a.get() != b.get(); +} + +#endif + +template inline bool operator<(intrusive_ptr const & a, intrusive_ptr const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(intrusive_ptr & lhs, intrusive_ptr & rhs) +{ + lhs.swap(rhs); +} + +// mem_fn support + +template T * get_pointer(intrusive_ptr const & p) +{ + return p.get(); +} + +template intrusive_ptr static_pointer_cast(intrusive_ptr const & p) +{ + return static_cast(p.get()); +} + +template intrusive_ptr const_pointer_cast(intrusive_ptr const & p) +{ + return const_cast(p.get()); +} + +template intrusive_ptr dynamic_pointer_cast(intrusive_ptr const & p) +{ + return dynamic_cast(p.get()); +} + +// operator<< + +#if !defined(BOOST_NO_IOSTREAM) + +#if defined(BOOST_NO_TEMPLATED_IOSTREAMS) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + +template std::ostream & operator<< (std::ostream & os, intrusive_ptr const & p) +{ + os << p.get(); + return os; +} + +#else + +// in STLport's no-iostreams mode no iostream symbols can be used +#ifndef _STLP_NO_IOSTREAMS + +# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300 && __SGI_STL_PORT) +// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL +using std::basic_ostream; +template basic_ostream & operator<< (basic_ostream & os, intrusive_ptr const & p) +# else +template std::basic_ostream & operator<< (std::basic_ostream & os, intrusive_ptr const & p) +# endif +{ + os << p.get(); + return os; +} + +#endif // _STLP_NO_IOSTREAMS + +#endif // __GNUC__ < 3 + +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_SMART_PTR_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr/make_shared.hpp b/include/boost/smart_ptr/make_shared.hpp new file mode 100644 index 0000000..7e1e793 --- /dev/null +++ b/include/boost/smart_ptr/make_shared.hpp @@ -0,0 +1,504 @@ +#ifndef BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED + +// make_shared.hpp +// +// Copyright (c) 2007, 2008 Peter Dimov +// +// 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 +// +// See http://www.boost.org/libs/smart_ptr/make_shared.html +// for documentation. + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template< std::size_t N, std::size_t A > struct sp_aligned_storage +{ + union type + { + char data_[ N ]; + typename boost::type_with_alignment< A >::type align_; + }; +}; + +template< class T > class sp_ms_deleter +{ +private: + + typedef typename sp_aligned_storage< sizeof( T ), ::boost::alignment_of< T >::value >::type storage_type; + + bool initialized_; + storage_type storage_; + +private: + + void destroy() + { + if( initialized_ ) + { + reinterpret_cast< T* >( storage_.data_ )->~T(); + initialized_ = false; + } + } + +public: + + sp_ms_deleter(): initialized_( false ) + { + } + + // optimization: do not copy storage_ + sp_ms_deleter( sp_ms_deleter const & ): initialized_( false ) + { + } + + ~sp_ms_deleter() + { + destroy(); + } + + void operator()( T * ) + { + destroy(); + } + + void * address() + { + return storage_.data_; + } + + void set_initialized() + { + initialized_ = true; + } +}; + +template< class T > T forward( T t ) +{ + return t; +} + +} // namespace detail + +// Zero-argument versions +// +// Used even when variadic templates are available because of the new T() vs new T issue + +template< class T > boost::shared_ptr< T > make_shared() +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T(); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A > boost::shared_ptr< T > allocate_shared( A const & a ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T(); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#if defined( BOOST_HAS_VARIADIC_TMPL ) && defined( BOOST_HAS_RVALUE_REFS ) + +// Variadic templates, rvalue reference + +template< class T, class... Args > boost::shared_ptr< T > make_shared( Args && ... args ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( detail::forward( args )... ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class... Args > boost::shared_ptr< T > allocate_shared( A const & a, Args && ... args ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( detail::forward( args )... ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#else + +// C++03 version + +template< class T, class A1 > +boost::shared_ptr< T > make_shared( A1 const & a1 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > +boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >() ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > +boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), detail::sp_ms_deleter< T >(), a ); + + detail::sp_ms_deleter< T > * pd = boost::get_deleter< detail::sp_ms_deleter< T > >( pt ); + + void * pv = pd->address(); + + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#endif + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED diff --git a/include/boost/smart_ptr/scoped_array.hpp b/include/boost/smart_ptr/scoped_array.hpp new file mode 100644 index 0000000..483460f --- /dev/null +++ b/include/boost/smart_ptr/scoped_array.hpp @@ -0,0 +1,107 @@ +#ifndef BOOST_SMART_PTR_SCOPED_ARRAY_HPP_INCLUDED +#define BOOST_SMART_PTR_SCOPED_ARRAY_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// http://www.boost.org/libs/smart_ptr/scoped_array.htm +// + +#include +#include +#include // in case ptrdiff_t not in std + +#include + +#include // for std::ptrdiff_t + +namespace boost +{ + +// Debug hooks + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +void sp_array_constructor_hook(void * p); +void sp_array_destructor_hook(void * p); + +#endif + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). Use shared_array or std::vector if your needs are more complex. + +template class scoped_array // noncopyable +{ +private: + + T * px; + + scoped_array(scoped_array const &); + scoped_array & operator=(scoped_array const &); + + typedef scoped_array this_type; + + void operator==( scoped_array const& ) const; + void operator!=( scoped_array const& ) const; + +public: + + typedef T element_type; + + explicit scoped_array( T * p = 0 ) : px( p ) // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_array_constructor_hook( px ); +#endif + } + + ~scoped_array() // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_array_destructor_hook( px ); +#endif + boost::checked_array_delete( px ); + } + + void reset(T * p = 0) // never throws + { + BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors + this_type(p).swap(*this); + } + + T & operator[](std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT( px != 0 ); + BOOST_ASSERT( i >= 0 ); + return px[i]; + } + + T * get() const // never throws + { + return px; + } + +// implicit conversion to "bool" +#include + + void swap(scoped_array & b) // never throws + { + T * tmp = b.px; + b.px = px; + px = tmp; + } +}; + +template inline void swap(scoped_array & a, scoped_array & b) // never throws +{ + a.swap(b); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_SCOPED_ARRAY_HPP_INCLUDED diff --git a/include/boost/smart_ptr/scoped_ptr.hpp b/include/boost/smart_ptr/scoped_ptr.hpp new file mode 100644 index 0000000..df479e5 --- /dev/null +++ b/include/boost/smart_ptr/scoped_ptr.hpp @@ -0,0 +1,131 @@ +#ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm +// + +#include +#include +#include + +#ifndef BOOST_NO_AUTO_PTR +# include // for std::auto_ptr +#endif + +namespace boost +{ + +// Debug hooks + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +void sp_scalar_constructor_hook(void * p); +void sp_scalar_destructor_hook(void * p); + +#endif + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +template class scoped_ptr // noncopyable +{ +private: + + T * px; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + typedef scoped_ptr this_type; + + void operator==( scoped_ptr const& ) const; + void operator!=( scoped_ptr const& ) const; + +public: + + typedef T element_type; + + explicit scoped_ptr( T * p = 0 ): px( p ) // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_constructor_hook( px ); +#endif + } + +#ifndef BOOST_NO_AUTO_PTR + + explicit scoped_ptr( std::auto_ptr p ): px( p.release() ) // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_constructor_hook( px ); +#endif + } + +#endif + + ~scoped_ptr() // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_destructor_hook( px ); +#endif + boost::checked_delete( px ); + } + + void reset(T * p = 0) // never throws + { + BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors + this_type(p).swap(*this); + } + + T & operator*() const // never throws + { + BOOST_ASSERT( px != 0 ); + return *px; + } + + T * operator->() const // never throws + { + BOOST_ASSERT( px != 0 ); + return px; + } + + T * get() const // never throws + { + return px; + } + +// implicit conversion to "bool" +#include + + void swap(scoped_ptr & b) // never throws + { + T * tmp = b.px; + b.px = px; + px = tmp; + } +}; + +template inline void swap(scoped_ptr & a, scoped_ptr & b) // never throws +{ + a.swap(b); +} + +// get_pointer(p) is a generic way to say p.get() + +template inline T * get_pointer(scoped_ptr const & p) +{ + return p.get(); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr/shared_array.hpp b/include/boost/smart_ptr/shared_array.hpp new file mode 100644 index 0000000..1f50403 --- /dev/null +++ b/include/boost/smart_ptr/shared_array.hpp @@ -0,0 +1,147 @@ +#ifndef BOOST_SMART_PTR_SHARED_ARRAY_HPP_INCLUDED +#define BOOST_SMART_PTR_SHARED_ARRAY_HPP_INCLUDED + +// +// shared_array.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_array.htm for documentation. +// + +#include // for broken compiler workarounds + +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) +#include +#else + +#include // TR1 cyclic inclusion fix + +#include +#include + +#include +#include + +#include // for std::ptrdiff_t +#include // for std::swap +#include // for std::less + +namespace boost +{ + +// +// shared_array +// +// shared_array extends shared_ptr to arrays. +// The array pointed to is deleted when the last shared_array pointing to it +// is destroyed or reset. +// + +template class shared_array +{ +private: + + // Borland 5.5.1 specific workarounds + typedef checked_array_deleter deleter; + typedef shared_array this_type; + +public: + + typedef T element_type; + + explicit shared_array(T * p = 0): px(p), pn(p, deleter()) + { + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_array will release p by calling d(p) + // + + template shared_array(T * p, D d): px(p), pn(p, d) + { + } + +// generated copy constructor, assignment, destructor are fine + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + this_type(p).swap(*this); + } + + template void reset(T * p, D d) + { + this_type(p, d).swap(*this); + } + + T & operator[] (std::ptrdiff_t i) const // never throws + { + BOOST_ASSERT(px != 0); + BOOST_ASSERT(i >= 0); + return px[i]; + } + + T * get() const // never throws + { + return px; + } + +// implicit conversion to "bool" +#include + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + void swap(shared_array & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + +private: + + T * px; // contained pointer + detail::shared_count pn; // reference counter + +}; // shared_array + +template inline bool operator==(shared_array const & a, shared_array const & b) // never throws +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_array const & a, shared_array const & b) // never throws +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_array const & a, shared_array const & b) // never throws +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_array & a, shared_array & b) // never throws +{ + a.swap(b); +} + +} // namespace boost + +#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) + +#endif // #ifndef BOOST_SMART_PTR_SHARED_ARRAY_HPP_INCLUDED diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp new file mode 100644 index 0000000..1b367f0 --- /dev/null +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -0,0 +1,701 @@ +#ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED + +// +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001-2008 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include // for broken compiler workarounds + +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) +#include +#else + +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +#include // std::auto_ptr + +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) +#include +#include +#endif + +#include // for std::swap +#include // for std::less +#include // for std::bad_cast + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) +#include // for std::basic_ostream +#else +#include +#endif +#endif + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +namespace boost +{ + +template class shared_ptr; +template class weak_ptr; +template class enable_shared_from_this; +template class enable_shared_from_this2; + +namespace detail +{ + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct polymorphic_cast_tag {}; + +template struct shared_ptr_traits +{ + typedef T & reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +#endif + +// enable_shared_from_this support + +template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) +{ + if( pe != 0 ) + { + pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); + } +} + +template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr * ppx, Y const * py, boost::enable_shared_from_this2< T > const * pe ) +{ + if( pe != 0 ) + { + pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); + } +} + +#ifdef _MANAGED + +// Avoid C4793, ... causes native code generation + +struct sp_any_pointer +{ + template sp_any_pointer( T* ) {} +}; + +inline void sp_enable_shared_from_this( sp_any_pointer, sp_any_pointer, sp_any_pointer ) +{ +} + +#else // _MANAGED + +inline void sp_enable_shared_from_this( ... ) +{ +} + +#endif // _MANAGED + +#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_AUTO_PTR ) + +// rvalue auto_ptr support based on a technique by Dave Abrahams + +template< class T, class R > struct sp_enable_if_auto_ptr +{ +}; + +template< class T, class R > struct sp_enable_if_auto_ptr< std::auto_ptr< T >, R > +{ + typedef R type; +}; + +#endif + +} // namespace detail + + +// +// shared_ptr +// +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. +// + +template class shared_ptr +{ +private: + + // Borland 5.5.1 specific workaround + typedef shared_ptr this_type; + +public: + + typedef T element_type; + typedef T value_type; + typedef T * pointer; + typedef typename boost::detail::shared_ptr_traits::reference reference; + + shared_ptr(): px(0), pn() // never throws in 1.30+ + { + } + + template + explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete + { + boost::detail::sp_enable_shared_from_this( this, p, p ); + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr(Y * p, D d): px(p), pn(p, d) + { + boost::detail::sp_enable_shared_from_this( this, p, p ); + } + + // As above, but with allocator. A's copy constructor shall not throw. + + template shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) + { + boost::detail::sp_enable_shared_from_this( this, p, p ); + } + +// generated copy constructor, destructor are fine + + template + explicit shared_ptr(weak_ptr const & r): pn(r.pn) // may throw + { + // it is now safe to copy r.px, as pn(r.pn) did not throw + px = r.px; + } + + template + shared_ptr( weak_ptr const & r, boost::detail::sp_nothrow_tag ): px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) // never throws + { + if( !pn.empty() ) + { + px = r.px; + } + } + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + shared_ptr( shared_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + shared_ptr( shared_ptr const & r ) + +#endif + : px( r.px ), pn( r.pn ) // never throws + { + } + + // aliasing + template< class Y > + shared_ptr( shared_ptr const & r, T * p ): px( p ), pn( r.pn ) // never throws + { + } + + template + shared_ptr(shared_ptr const & r, boost::detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, boost::detail::const_cast_tag): px(const_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, boost::detail::dynamic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) // need to allocate new counter -- the cast failed + { + pn = boost::detail::shared_count(); + } + } + + template + shared_ptr(shared_ptr const & r, boost::detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) + { + boost::throw_exception(std::bad_cast()); + } + } + +#ifndef BOOST_NO_AUTO_PTR + + template + explicit shared_ptr(std::auto_ptr & r): px(r.get()), pn() + { + Y * tmp = r.get(); + pn = boost::detail::shared_count(r); + boost::detail::sp_enable_shared_from_this( this, tmp, tmp ); + } + +#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + + template + explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_auto_ptr::type = 0 ): px( r.get() ), pn() + { + typename Ap::element_type * tmp = r.get(); + pn = boost::detail::shared_count( r ); + boost::detail::sp_enable_shared_from_this( this, tmp, tmp ); + } + + +#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // BOOST_NO_AUTO_PTR + + // assignment + + shared_ptr & operator=( shared_ptr const & r ) // never throws + { + this_type(r).swap(*this); + return *this; + } + +#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1400) + + template + shared_ptr & operator=(shared_ptr const & r) // never throws + { + this_type(r).swap(*this); + return *this; + } + +#endif + +#ifndef BOOST_NO_AUTO_PTR + + template + shared_ptr & operator=( std::auto_ptr & r ) + { + this_type(r).swap(*this); + return *this; + } + +#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + + template + typename boost::detail::sp_enable_if_auto_ptr< Ap, shared_ptr & >::type operator=( Ap r ) + { + this_type( r ).swap( *this ); + return *this; + } + + +#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // BOOST_NO_AUTO_PTR + +// Move support + +#if defined( BOOST_HAS_RVALUE_REFS ) + + shared_ptr( shared_ptr && r ): px( r.px ), pn() // never throws + { + pn.swap( r.pn ); + r.px = 0; + } + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + shared_ptr( shared_ptr && r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + shared_ptr( shared_ptr && r ) + +#endif + : px( r.px ), pn() // never throws + { + pn.swap( r.pn ); + r.px = 0; + } + + shared_ptr & operator=( shared_ptr && r ) // never throws + { + this_type( std::move( r ) ).swap( *this ); + return *this; + } + + template + shared_ptr & operator=( shared_ptr && r ) // never throws + { + this_type( std::move( r ) ).swap( *this ); + return *this; + } + +#endif + + void reset() // never throws in 1.30+ + { + this_type().swap(*this); + } + + template void reset(Y * p) // Y must be complete + { + BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors + this_type(p).swap(*this); + } + + template void reset( Y * p, D d ) + { + this_type( p, d ).swap( *this ); + } + + template void reset( Y * p, D d, A a ) + { + this_type( p, d, a ).swap( *this ); + } + + template void reset( shared_ptr const & r, T * p ) + { + this_type( r, p ).swap( *this ); + } + + reference operator* () const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator-> () const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + +// implicit conversion to "bool" +#include + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + void swap(shared_ptr & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + template bool _internal_less(shared_ptr const & rhs) const + { + return pn < rhs.pn; + } + + void * _internal_get_deleter( detail::sp_typeinfo const & ti ) const + { + return pn.get_deleter( ti ); + } + + bool _internal_equiv( shared_ptr const & r ) const + { + return px == r.px && pn == r.pn; + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class shared_ptr; + template friend class weak_ptr; + + +#endif + + T * px; // contained pointer + boost::detail::shared_count pn; // reference counter + +}; // shared_ptr + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +#endif + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) +{ + return a._internal_less(b); +} + +template inline void swap(shared_ptr & a, shared_ptr & b) +{ + a.swap(b); +} + +template shared_ptr static_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::static_cast_tag()); +} + +template shared_ptr const_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::const_cast_tag()); +} + +template shared_ptr dynamic_pointer_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::dynamic_cast_tag()); +} + +// shared_*_cast names are deprecated. Use *_pointer_cast instead. + +template shared_ptr shared_static_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::static_cast_tag()); +} + +template shared_ptr shared_dynamic_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::dynamic_cast_tag()); +} + +template shared_ptr shared_polymorphic_cast(shared_ptr const & r) +{ + return shared_ptr(r, boost::detail::polymorphic_cast_tag()); +} + +template shared_ptr shared_polymorphic_downcast(shared_ptr const & r) +{ + BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); + return shared_static_cast(r); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr const & p) +{ + return p.get(); +} + +// operator<< + +#if !defined(BOOST_NO_IOSTREAM) + +#if defined(BOOST_NO_TEMPLATED_IOSTREAMS) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + +template std::ostream & operator<< (std::ostream & os, shared_ptr const & p) +{ + os << p.get(); + return os; +} + +#else + +// in STLport's no-iostreams mode no iostream symbols can be used +#ifndef _STLP_NO_IOSTREAMS + +# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300 && __SGI_STL_PORT) +// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL +using std::basic_ostream; +template basic_ostream & operator<< (basic_ostream & os, shared_ptr const & p) +# else +template std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) +# endif +{ + os << p.get(); + return os; +} + +#endif // _STLP_NO_IOSTREAMS + +#endif // __GNUC__ < 3 + +#endif // !defined(BOOST_NO_IOSTREAM) + +// get_deleter + +#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ + ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ + ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) + +// g++ 2.9x doesn't allow static_cast(void *) +// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it + +template D * get_deleter(shared_ptr const & p) +{ + void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); + return const_cast(static_cast(q)); +} + +#else + +template D * get_deleter(shared_ptr const & p) +{ + return static_cast(p._internal_get_deleter(BOOST_SP_TYPEID(D))); +} + +#endif + +// atomic access + +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) + +template inline bool atomic_is_lock_free( shared_ptr const * /*p*/ ) +{ + return false; +} + +template shared_ptr atomic_load( shared_ptr const * p ) +{ + boost::detail::spinlock_pool<2>::scoped_lock lock( p ); + return *p; +} + +template inline shared_ptr atomic_load_explicit( shared_ptr const * p, memory_order /*mo*/ ) +{ + return atomic_load( p ); +} + +template void atomic_store( shared_ptr * p, shared_ptr r ) +{ + boost::detail::spinlock_pool<2>::scoped_lock lock( p ); + p->swap( r ); +} + +template inline void atomic_store_explicit( shared_ptr * p, shared_ptr r, memory_order /*mo*/ ) +{ + atomic_store( p, r ); // std::move( r ) +} + +template shared_ptr atomic_exchange( shared_ptr * p, shared_ptr r ) +{ + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); + + sp.lock(); + p->swap( r ); + sp.unlock(); + + return r; // return std::move( r ) +} + +template shared_ptr atomic_exchange_explicit( shared_ptr * p, shared_ptr r, memory_order /*mo*/ ) +{ + return atomic_exchange( p, r ); // std::move( r ) +} + +template bool atomic_compare_exchange( shared_ptr * p, shared_ptr * v, shared_ptr w ) +{ + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); + + sp.lock(); + + if( p->_internal_equiv( *v ) ) + { + p->swap( w ); + + sp.unlock(); + + return true; + } + else + { + shared_ptr tmp( *p ); + + sp.unlock(); + + tmp.swap( *v ); + return false; + } +} + +template inline bool atomic_compare_exchange_explicit( shared_ptr * p, shared_ptr * v, shared_ptr w, memory_order /*success*/, memory_order /*failure*/ ) +{ + return atomic_compare_exchange( p, v, w ); // std::move( w ) +} + +#endif + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) + +#endif // #ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED diff --git a/include/boost/smart_ptr/weak_ptr.hpp b/include/boost/smart_ptr/weak_ptr.hpp new file mode 100644 index 0000000..621c433 --- /dev/null +++ b/include/boost/smart_ptr/weak_ptr.hpp @@ -0,0 +1,230 @@ +#ifndef BOOST_SMART_PTR_WEAK_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_WEAK_PTR_HPP_INCLUDED + +// +// weak_ptr.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov +// +// 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) +// +// See http://www.boost.org/libs/smart_ptr/weak_ptr.htm for documentation. +// + +#include // boost.TR1 include order fix +#include +#include + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +namespace boost +{ + +template class weak_ptr +{ +private: + + // Borland 5.5.1 specific workarounds + typedef weak_ptr this_type; + +public: + + typedef T element_type; + + weak_ptr(): px(0), pn() // never throws in 1.30+ + { + } + +// generated copy constructor, assignment, destructor are fine + + +// +// The "obvious" converting constructor implementation: +// +// template +// weak_ptr(weak_ptr const & r): px(r.px), pn(r.pn) // never throws +// { +// } +// +// has a serious problem. +// +// r.px may already have been invalidated. The px(r.px) +// conversion may require access to *r.px (virtual inheritance). +// +// It is not possible to avoid spurious access violations since +// in multithreaded programs r.px may be invalidated at any point. +// + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + weak_ptr( weak_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + weak_ptr( weak_ptr const & r ) + +#endif + : px(r.lock().get()), pn(r.pn) // never throws + { + } + +#if defined( BOOST_HAS_RVALUE_REFS ) + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + weak_ptr( weak_ptr && r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + weak_ptr( weak_ptr && r ) + +#endif + : px(r.lock().get()), pn(std::move(r.pn)) // never throws + { + r.px = 0; + } + + // for better efficiency in the T == Y case + weak_ptr( weak_ptr && r ): px( r.px ), pn(std::move(r.pn)) // never throws + { + r.px = 0; + } + + // for better efficiency in the T == Y case + weak_ptr & operator=( weak_ptr && r ) // never throws + { + this_type( std::move( r ) ).swap( *this ); + return *this; + } + + +#endif + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + weak_ptr( shared_ptr const & r, typename detail::sp_enable_if_convertible::type = detail::sp_empty() ) + +#else + + weak_ptr( shared_ptr const & r ) + +#endif + : px( r.px ), pn( r.pn ) // never throws + { + } + +#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300) + + template + weak_ptr & operator=(weak_ptr const & r) // never throws + { + px = r.lock().get(); + pn = r.pn; + return *this; + } + +#if defined( BOOST_HAS_RVALUE_REFS ) + + template + weak_ptr & operator=(weak_ptr && r) + { + this_type( std::move( r ) ).swap( *this ); + return *this; + } + +#endif + + template + weak_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; + return *this; + } + +#endif + + shared_ptr lock() const // never throws + { + return shared_ptr( *this, boost::detail::sp_nothrow_tag() ); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + bool expired() const // never throws + { + return pn.use_count() == 0; + } + + bool _empty() const // extension, not in std::weak_ptr + { + return pn.empty(); + } + + void reset() // never throws in 1.30+ + { + this_type().swap(*this); + } + + void swap(this_type & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + void _internal_assign(T * px2, boost::detail::shared_count const & pn2) + { + px = px2; + pn = pn2; + } + + template bool _internal_less(weak_ptr const & rhs) const + { + return pn < rhs.pn; + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class weak_ptr; + template friend class shared_ptr; + +#endif + + T * px; // contained pointer + boost::detail::weak_count pn; // reference counter + +}; // weak_ptr + +template inline bool operator<(weak_ptr const & a, weak_ptr const & b) +{ + return a._internal_less(b); +} + +template void swap(weak_ptr & a, weak_ptr & b) +{ + a.swap(b); +} + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_SMART_PTR_WEAK_PTR_HPP_INCLUDED diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp new file mode 100644 index 0000000..dd26869 --- /dev/null +++ b/include/boost/weak_ptr.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_WEAK_PTR_HPP_INCLUDED +#define BOOST_WEAK_PTR_HPP_INCLUDED + +// +// weak_ptr.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov +// +// 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 +// +// See http://www.boost.org/libs/smart_ptr/weak_ptr.htm for documentation. +// + +#include + +#endif // #ifndef BOOST_WEAK_PTR_HPP_INCLUDED diff --git a/index.html b/index.html new file mode 100644 index 0000000..c7f709c --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + + +Automatic redirection failed, please go to +smart_ptr.htm. + + + diff --git a/intrusive_ptr.html b/intrusive_ptr.html new file mode 100644 index 0000000..16097dd --- /dev/null +++ b/intrusive_ptr.html @@ -0,0 +1,297 @@ + + + + intrusive_ptr + + + +

boost.png (6897 bytes)intrusive_ptr class template

+

+ Introduction
+ Synopsis
+ Members
+ Free Functions
+

+

Introduction

+

The intrusive_ptr class template stores a pointer to an object with an + embedded reference count. Every new intrusive_ptr instance increments + the reference count by using an unqualified call to the function intrusive_ptr_add_ref, + passing it the pointer as an argument. Similarly, when an intrusive_ptr + is destroyed, it calls intrusive_ptr_release; this function is + responsible for destroying the object when its reference count drops to zero. + The user is expected to provide suitable definitions of these two functions. On + 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.

+

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*.

+

The main reasons to use intrusive_ptr are:

+
    +
  • + Some existing frameworks or OSes provide objects with embedded reference + counts; +
  • + The memory footprint of intrusive_ptr + is the same as the corresponding raw pointer; +
  • + intrusive_ptr<T> can be constructed from an arbitrary + raw pointer of type T *.
+

As a general rule, if it isn't obvious whether intrusive_ptr better + fits your needs than shared_ptr, try a shared_ptr-based + design first.

+

Synopsis

+
namespace boost {
+
+  template<class T> class intrusive_ptr {
+
+    public:
+
+      typedef T element_type;
+
+      intrusive_ptr(); // never throws
+      intrusive_ptr(T * p, bool add_ref = true);
+
+      intrusive_ptr(intrusive_ptr const & r);
+      template<class Y> intrusive_ptr(intrusive_ptr<Y> const & r);
+
+      ~intrusive_ptr();
+
+      intrusive_ptr & operator=(intrusive_ptr const & r);
+      template<class Y> intrusive_ptr & operator=(intrusive_ptr<Y> const & r);
+      intrusive_ptr & operator=(T * r);
+
+      void reset();
+      void reset(T * r);
+
+      T & operator*() const; // never throws
+      T * operator->() const; // never throws
+      T * get() const; // never throws
+
+      operator unspecified-bool-type() const; // never throws
+
+      void swap(intrusive_ptr & b); // never throws
+  };
+
+  template<class T, class U>
+    bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+  template<class T, class U>
+    bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+  template<class T>
+    bool operator==(intrusive_ptr<T> const & a, T * b); // never throws
+
+  template<class T>
+    bool operator!=(intrusive_ptr<T> const & a, T * b); // never throws
+
+  template<class T>
+    bool operator==(T * a, intrusive_ptr<T> const & b); // never throws
+
+  template<class T>
+    bool operator!=(T * a, intrusive_ptr<T> const & b); // never throws
+
+  template<class T, class U>
+    bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+  template<class T> void swap(intrusive_ptr<T> & a, intrusive_ptr<T> & b); // never throws
+
+  template<class T> T * get_pointer(intrusive_ptr<T> const & p); // never throws
+
+  template<class T, class U>
+    intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r); // never throws
+
+  template<class T, class U>
+    intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const & r); // never throws
+
+  template<class T, class U>
+    intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & r); // never throws
+
+  template<class E, class T, class Y>
+    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, intrusive_ptr<Y> const & p);
+
+}
+

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

+
intrusive_ptr(); // never throws
+
+

Postconditions: get() == 0.

+

Throws: nothing.

+
+
intrusive_ptr(T * p, bool add_ref = true);
+
+

Effects: if(p != 0 && add_ref) intrusive_ptr_add_ref(p);.

+

Postconditions: get() == p.

+
+
intrusive_ptr(intrusive_ptr const & r);
+template<class Y> intrusive_ptr(intrusive_ptr<Y> const & r);
+
+

Effects: if(r.get() != 0) intrusive_ptr_add_ref(r.get());.

+

Postconditions: get() == r.get().

+
+

destructor

+
~intrusive_ptr();
+
+

Effects: if(get() != 0) intrusive_ptr_release(get());.

+
+

assignment

+
intrusive_ptr & operator=(intrusive_ptr const & r);
+template<class Y> intrusive_ptr & operator=(intrusive_ptr<Y> const & r);
+intrusive_ptr & operator=(T * r);
+
+

Effects: Equivalent to intrusive_ptr(r).swap(*this).

+

Returns: *this.

+
+

reset

+
void reset();
+
+

Effects: Equivalent to intrusive_ptr().swap(*this).

+
+
void reset(T * r);
+
+

Effects: Equivalent to intrusive_ptr(r).swap(*this).

+
+

indirection

+
T & operator*() const; // never throws
+
+

Requirements: get() != 0.

+

Returns: *get().

+

Throws: nothing.

+
+
T * operator->() const; // never throws
+
+

Requirements: get() != 0.

+

Returns: get().

+

Throws: nothing.

+
+

get

+
T * get() const; // never throws
+
+

Returns: the stored pointer.

+

Throws: nothing.

+
+

conversions

+
operator unspecified-bool-type () const; // never throws
+
+

Returns: an unspecified value that, when used in boolean contexts, is + equivalent to get() != 0.

+

Throws: nothing.

+

Notes: This conversion operator allows intrusive_ptr objects to be + used in boolean contexts, like if (p && p->valid()) {}. + The actual target type is typically a pointer to a member function, avoiding + many of the implicit conversion pitfalls.

+
+

swap

+
void swap(intrusive_ptr & b); // never throws
+
+

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+
+

Free Functions

+

comparison

+
template<class T, class U>
+  bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+

Returns: a.get() == b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+

Returns: a.get() != b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator==(intrusive_ptr<T> const & a, U * b); // never throws
+
+

Returns: a.get() == b.

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator!=(intrusive_ptr<T> const & a, U * b); // never throws
+
+

Returns: a.get() != b.

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator==(T * a, intrusive_ptr<U> const & b); // never throws
+
+

Returns: a == b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator!=(T * a, intrusive_ptr<U> const & b); // never throws
+
+

Returns: a != b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b); // never throws
+
+

Returns: std::less<T *>()(a.get(), b.get()).

+

Throws: nothing.

+

Notes: Allows intrusive_ptr objects to be used as keys + in associative containers.

+
+

swap

+
template<class T>
+  void swap(intrusive_ptr<T> & a, intrusive_ptr<T> & b); // never throws
+
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

Notes: Matches the interface of std::swap. Provided as an aid to + generic programming.

+
+

get_pointer

+
template<class T>
+  T * get_pointer(intrusive_ptr<T> const & p); // never throws
+
+

Returns: p.get().

+

Throws: nothing.

+

Notes: Provided as an aid to generic programming. Used by + mem_fn.

+
+

static_pointer_cast

+
template<class T, class U>
+  intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r); // never throws
+
+

Returns: intrusive_ptr<T>(static_cast<T*>(r.get())).

+

Throws: nothing.

+
+

const_pointer_cast

+
template<class T, class U>
+  intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const & r); // never throws
+
+

Returns: intrusive_ptr<T>(const_cast<T*>(r.get())).

+

Throws: nothing.

+
+

dynamic_pointer_cast

+
template<class T, class U>
+  intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & r);
+
+

Returns: intrusive_ptr<T>(dynamic_cast<T*>(r.get())).

+

Throws: nothing.

+
+

operator<<

+
template<class E, class T, class Y>
+    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, intrusive_ptr<Y> const & p);
+
+

Effects: os << p.get();.

+

Returns: os.

+
+
+

+ $Date$

+

+ Copyright © 2003-2005 Peter Dimov. 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/make_shared.html b/make_shared.html new file mode 100644 index 0000000..e47fe2a --- /dev/null +++ b/make_shared.html @@ -0,0 +1,119 @@ + + + + make_shared and allocate_shared + + + +

boost.png (6897 bytes)make_shared and allocate_shared function templates

+

Introduction
+ Synopsis
+ Free Functions
+ Example
+

Introduction

+

Consistent use of shared_ptr + can eliminate the need to use an explicit delete, + but alone it provides no support in avoiding explicit new. + There have been repeated requests from users for a factory function that creates + an object of a given type and returns a shared_ptr to it. + Besides convenience and style, such a function is also exception safe and + considerably faster because it can use a single allocation for both the object + and its corresponding control block, eliminating a significant portion of + shared_ptr's construction overhead. + This eliminates one of the major efficiency complaints about shared_ptr. +

+

The header file <boost/make_shared.hpp> provides a family of overloaded function templates, + make_shared and allocate_shared, to address this need. + make_shared uses the global operator new to allocate memory, + whereas allocate_shared uses an user-supplied allocator, allowing finer control.

+

+ The rationale for choosing the name make_shared is that the expression + make_shared<Widget>() can be read aloud and conveys the intended meaning.

+

Synopsis

+
namespace boost {
+
+  template<typename T> class shared_ptr;
+
+  template<typename T>
+    shared_ptr<T> make_shared();
+
+  template<typename T, typename A>
+    shared_ptr<T> allocate_shared( A const & );
+
+#if defined( BOOST_HAS_VARIADIC_TMPL ) && defined( BOOST_HAS_RVALUE_REFS )	// C++0x prototypes
+
+  template<typename T, typename... Args>
+    shared_ptr<T> make_shared( Args && ... args );
+
+  template<typename T, typename A, typename... Args>
+    shared_ptr<T> allocate_shared( A const & a, Args && ... args );
+
+#else // no C++0X support
+
+  template<typename T, typename Arg1 >
+    shared_ptr<T> make_shared( Arg1 const & arg1 );
+  template<typename T, typename Arg1, typename Arg2 >
+    shared_ptr<T> make_shared( Arg1 const & arg1, Arg2 const & arg2 );
+// ...
+  template<typename T, typename Arg1, typename Arg2, ..., typename ArgN >
+    shared_ptr<T> make_shared( Arg1 const & arg1, Arg2 const & arg2, ..., ArgN const & argN );
+
+  template<typename T, typename A, typename Arg1 >
+    shared_ptr<T> allocate_shared( A const & a, Arg1 const & arg1 );
+  template<typename T, typename A, typename Arg1, typename Arg2 >
+    shared_ptr<T> allocate_shared( Arg1 const & arg1, Arg2 const & arg2 );
+// ...
+  template<typename T, typename A, typename Arg1, typename Arg2, ..., typename ArgN >
+    shared_ptr<T> allocate_shared( A const & a, Arg1 const & arg1, Arg2 const & arg2, ..., ArgN const & argN );
+
+#endif
+}
+

Free Functions

+
template<class T, class... Args>
+    shared_ptr<T> make_shared( Args && ... args );
+template<class T, class A, class... Args>
+    shared_ptr<T> allocate_shared( A const & a, Args && ... args );
+
+

Requires: The expression new( pv ) T( std::forward<Args>(args)... ), + where pv is a void* pointing to storage suitable + to hold an object of type T, + shall be well-formed. A shall be an Allocator, + as described in section 20.1.5 (Allocator requirements) of the C++ Standard. + The copy constructor and destructor of A shall not throw.

+

Effects: Allocates memory suitable for an object of type T + and constructs an object in it via the placement new expression new( pv ) T() + or new( pv ) T( std::forward<Args>(args)... ). + allocate_shared uses a copy of a to allocate memory. + If an exception is thrown, has no effect.

+

Returns: A shared_ptr instance that stores and owns the address + of the newly constructed object of type T.

+

Postconditions: get() != 0 && use_count() == 1.

+

Throws: bad_alloc, or an exception thrown from A::allocate + or the constructor of T.

+

Notes: This implementation allocates the memory required for the + returned shared_ptr and an object of type T in a single + allocation. This provides efficiency equivalent to an intrusive smart pointer.

+

The prototypes shown above are used if your compiler supports rvalue references + and variadic templates. They perfectly forward the args parameters to + the constructors of T.

+

Otherwise, the implementation will fall back on + forwarding the arguments to the constructors of T as const references. + If you need to pass a non-const reference to a constructor of T, + you may do so by wrapping the parameter in a call to boost::ref. + In addition, you will be + limited to a maximum of 9 arguments (not counting the allocator argument of + allocate_shared).

+
+

Example

+
boost::shared_ptr<std::string> x = boost::make_shared<std::string>("hello, world!");
+std::cout << *x;
+
+

+ $Date: 2008-05-19 15:42:39 -0400 (Mon, 19 May 2008) $

+

Copyright 2008 Peter Dimov. Copyright 2008 Frank Mori Hess. + 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/msvcspeed.gif b/msvcspeed.gif new file mode 100644 index 0000000..56295ee Binary files /dev/null and b/msvcspeed.gif differ diff --git a/pointer_cast.html b/pointer_cast.html new file mode 100644 index 0000000..8f14795 --- /dev/null +++ b/pointer_cast.html @@ -0,0 +1,105 @@ + + + + pointer_cast.hpp + + +

C++ BoostPointer + cast functions

+

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast + boost::reinterpret_pointer_cast boost::const_pointer_cast) + provide a way to write generic pointer castings for raw pointers. The functions + are defined in boost/pointer_cast.hpp.

+

There is test/example code in pointer_cast_test.cpp.

+

Rationale

+

Boost smart pointers usually overload those functions to provide a mechanism to + emulate pointers casts. For example, boost::shared_ptr<...> implements + a static pointer cast this way:

+
+template<class T, class U>
+    shared_ptr<T> static_pointer_cast(shared_ptr<U> const &r);
+
+

Pointer cast functions from boost/pointer_cast.hpp + are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, + boost::reinterpret_pointer_cast and boost::const_pointer_cast + for raw pointers. This way when developing pointer type independent classes, + for example, memory managers or shared memory compatible classes, the same code + can be used for raw and smart pointers.

+

Synopsis

+
+
+namespace boost {
+
+template<class T, class U>
+inline T* static_pointer_cast(U *ptr)
+  { return static_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* dynamic_pointer_cast(U *ptr)
+  { return dynamic_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* const_pointer_cast(U *ptr)
+  { return const_cast<T*>(ptr); }
+
+template<class T, class U>
+inline T* reinterpret_pointer_cast(U *ptr)
+  { return reinterpret_cast<T*>(ptr); }
+  
+} // namespace boost
+
+
+

As you can see from the above synopsis, the pointer cast functions are just + wrappers around standard C++ cast operators.

+

Example

+
+
+#include <boost/pointer_cast.hpp>
+#include <boost/shared_ptr.hpp>
+
+class base
+{
+public:
+
+   virtual ~base()
+   {
+   }
+};
+
+class derived: public base
+{
+};
+
+template <class BasePtr>
+void check_if_it_is_derived(const BasePtr &ptr)
+{
+   assert(boost::dynamic_pointer_cast<derived>(ptr) != 0);
+}
+
+int main()
+{
+   // Create a raw and a shared_ptr
+
+   base *ptr = new derived;
+   boost::shared_ptr<base> sptr(new derived);
+   
+   // Check that base pointer points actually to derived class
+
+   check_if_it_is_derived(ptr);
+   check_if_it_is_derived(sptr);
+   
+   // Ok!
+   
+   delete ptr;
+   return 0;
+}
+
+

The example demonstrates how the generic pointer casts help us create pointer + independent code.

+
+

Revised: $Date$

+

Copyright 2005 Ion Gaztañaga. Use, modification, and distribution are subject to + the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

+ + diff --git a/pointer_to_other.html b/pointer_to_other.html new file mode 100644 index 0000000..e6b138c --- /dev/null +++ b/pointer_to_other.html @@ -0,0 +1,108 @@ + + + + pointer_to_other.hpp + + + +

boost.png (6897 bytes)Header + boost/pointer_to_other.hpp

+

+ The pointer to other utility provides a way, given a source pointer type, + to obtain a pointer of the same type to another pointee type. The utility is + defined in boost/pointer_to_other.hpp.

+

There is test/example code in pointer_to_other_test.cpp.

+

Contents

+ +

Rationale

+

When building pointer independent classes, like memory managers, allocators, or + containers, there is often a need to define pointers generically, so that if a + template parameter represents a pointer (for example, a raw or smart pointer to + an int), we can define another pointer of the same type to another pointee (a + raw or smart pointer to a float.)

+
template <class IntPtr>
+class FloatPointerHolder
+{   
+   // Let's define a pointer to a float
+   typedef typename boost::pointer_to_other
+      <IntPtr, float>::type float_ptr_t;
+   float_ptr_t float_ptr;
+};
+

Synopsis

+
+namespace boost {
+
+template<class T, class U>
+   struct pointer_to_other;
+
+template<class T, class U, template <class> class Sp>
+   struct pointer_to_other< Sp<T>, U >
+{
+   typedef Sp<U> type;
+};
+
+template<class T, class T2, class U,
+        template <class, class> class Sp>
+   struct pointer_to_other< Sp<T, T2>, U >
+{
+   typedef Sp<U, T2> type;
+};
+
+template<class T, class T2, class T3, class U,
+        template <class, class, class> class Sp>
+struct pointer_to_other< Sp<T, T2, T3>, U >
+{
+   typedef Sp<U, T2, T3> type;
+};
+
+template<class T, class U>
+struct pointer_to_other< T*, U > 
+{
+   typedef U* type;
+};
+
+} // namespace boost
+

If these definitions are not correct for a specific smart pointer, we can define + a specialization of pointer_to_other.

+

Example

+
// Let's define a memory allocator that can
+// work with raw and smart pointers
+
+#include <boost/pointer_to_other.hpp>
+
+template <class VoidPtr>
+class memory_allocator
+{
+   // Predefine a memory_block 
+   struct block;
+
+   // Define a pointer to a memory_block from a void pointer
+   // If VoidPtr is void *, block_ptr_t is block*
+   // If VoidPtr is smart_ptr<void>, block_ptr_t is smart_ptr<block>
+   typedef typename boost::pointer_to_other      
+            <VoidPtr, block>::type block_ptr_t;
+            
+   struct block
+   {
+      std::size_t size;
+      block_ptr_t next_block;
+   };
+
+   block_ptr_t free_blocks;
+};
+

As we can see, using pointer_to_other we can create pointer independent code.

+
+

Last revised: $Date$

+

Copyright 2005, 2006 Ion Gaztañaga and Peter Dimov. Use, modification, + and distribution are subject to the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or a + copy at < http://www.boost.org/LICENSE_1_0.txt>.)

+ + diff --git a/scoped_array.htm b/scoped_array.htm new file mode 100644 index 0000000..2d03509 --- /dev/null +++ b/scoped_array.htm @@ -0,0 +1,116 @@ + + + + scoped_array + + + +

boost.png (6897 bytes)scoped_array class template

+

The scoped_array class template stores a pointer to a dynamically + allocated array. (Dynamically allocated arrays are allocated with the C++ new[] + expression.) The array pointed to is guaranteed to be deleted, either on + destruction of the scoped_array, or via an explicit reset.

+

The scoped_array template is a simple solution for simple needs. It + supplies a basic "resource acquisition is initialization" facility, without + shared-ownership or transfer-of-ownership semantics. Both its name and + enforcement of semantics (by being + noncopyable) signal its intent to retain ownership solely within the + current scope. Because it is noncopyable, + it is safer than shared_array for pointers which should not be copied.

+

Because scoped_array is so simple, in its usual implementation every + operation is as fast as a built-in array pointer and it has no more space + overhead that a built-in array pointer.

+

It cannot be used in C++ standard library containers. See + shared_array if scoped_array does not meet your needs.

+

It cannot correctly hold a pointer to a single object. See scoped_ptr + for that usage.

+

A std::vector is an alternative to a scoped_array that is a bit + heavier duty but far more flexible. A boost::array is an alternative + that does not use dynamic allocation.

+

The class template is parameterized on T, the type of the object pointed + to. T must meet the smart pointer + common requirements.

+

Synopsis

+
namespace boost {
+
+  template<class T> class scoped_array : noncopyable {
+
+    public:
+      typedef T element_type;
+
+      explicit scoped_array(T * p = 0); // never throws
+      ~scoped_array(); // never throws
+
+      void reset(T * p = 0); // never throws
+
+      T & operator[](std::ptrdiff_t i) const; // never throws
+      T * get() const; // never throws
+     
+      operator unspecified-bool-type() const; // never throws
+
+      void swap(scoped_array & b); // never throws
+  };
+
+  template<class T> void swap(scoped_array<T> & a, scoped_array<T> & b); // never throws
+
+}
+

Members

+

+ element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

constructors

+
explicit scoped_array(T * p = 0); // never throws
+

Constructs a scoped_array, storing a copy of p, which must have + been allocated via a C++ new[] expression or be 0. T is not + required be a complete type. See the smart pointer + common requirements.

+

destructor

+
~scoped_array(); // never throws
+

Deletes the array pointed to by the stored pointer. Note that delete[] on + a pointer with a value of 0 is harmless. The guarantee that this does not throw + exceptions depends on the requirement that the deleted array's objects' + destructors do not throw exceptions. See the smart pointer + common requirements.

+

reset

+
void reset(T * p = 0); // never throws
+

+ Deletes the array pointed to by the stored pointer and then stores a copy of p, + which must have been allocated via a C++ new[] expression or be 0. The + guarantee that this does not throw exceptions depends on the requirement that + the deleted array's objects' destructors do not throw exceptions. See the smart + pointer common requirements.

+

subscripting

+
T & operator[](std::ptrdiff_t i) const; // never throws
+

Returns a reference to element i of the array pointed to by the stored + pointer. Behavior is undefined and almost certainly undesirable if the stored + pointer is 0, or if i is less than 0 or is greater than or equal to the + number of elements in the array.

+

get

+
T * get() const; // never throws
+

Returns the stored pointer. T need not be a complete type. See the smart + pointer common requirements.

+

conversions

+
operator unspecified-bool-type () const; // never throws
+

Returns an unspecified value that, when used in boolean contexts, is equivalent + to get() != 0.

+

swap

+
void swap(scoped_array & b); // never throws
+

Exchanges the contents of the two smart pointers. T need not be a + complete type. See the smart pointer common + requirements.

+

Free Functions

+

swap

+
template<class T> void swap(scoped_array<T> & a, scoped_array<T> & b); // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. + Provided as an aid to generic programming.

+
+

Revised + 09 January 2003

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Copyright 2002-2005 Peter Dimov. 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/scoped_ptr.htm b/scoped_ptr.htm new file mode 100644 index 0000000..fc5785c --- /dev/null +++ b/scoped_ptr.htm @@ -0,0 +1,181 @@ + + + + scoped_ptr + + + +

boost.png (6897 bytes)scoped_ptr class template

+

The scoped_ptr class template stores a pointer to a dynamically allocated + object. (Dynamically allocated objects are allocated with the C++ new expression.) + The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, + or via an explicit reset. See the example.

+

The scoped_ptr template is a simple solution for simple needs. It + supplies a basic "resource acquisition is initialization" facility, without + shared-ownership or transfer-of-ownership semantics. Both its name and + enforcement of semantics (by being + noncopyable) signal its intent to retain ownership solely within the + current scope. Because it is noncopyable, + it is safer than shared_ptr or std::auto_ptr for pointers which + should not be copied.

+

Because scoped_ptr is simple, in its usual implementation every operation + is as fast as for a built-in pointer and it has no more space overhead that a + built-in pointer.

+

scoped_ptr cannot be used in C++ Standard Library containers. + Use shared_ptr if you need a smart pointer + that can.

+

scoped_ptr cannot correctly hold a pointer to a dynamically + allocated array. See scoped_array for + that usage.

+

The class template is parameterized on T, the type of the object pointed + to. T must meet the smart pointer + common requirements.

+

Synopsis

+
namespace boost {
+
+  template<class T> class scoped_ptr : noncopyable {
+
+   public:
+     typedef T element_type;
+
+     explicit scoped_ptr(T * p = 0); // never throws
+     ~scoped_ptr(); // never throws
+
+     void reset(T * p = 0); // never throws
+
+     T & operator*() const; // never throws
+     T * operator->() const; // never throws
+     T * get() const; // never throws
+     
+     operator unspecified-bool-type() const; // never throws
+
+     void swap(scoped_ptr & b); // never throws
+  };
+
+  template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
+
+}
+

Members

+

element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

constructors

+
explicit scoped_ptr(T * p = 0); // never throws
+

Constructs a scoped_ptr, storing a copy of p, which must have been + allocated via a C++ new expression or be 0. T is not required be + a complete type. See the smart pointer common + requirements.

+

destructor

+
~scoped_ptr(); // never throws
+

Destroys the object pointed to by the stored pointer, if any, as if by using delete + this->get().

+

+ The guarantee that this does not throw exceptions depends on the requirement + that the deleted object's destructor does not throw exceptions. See the smart + pointer common requirements.

+

reset

+
void reset(T * p = 0); // never throws
+

+ Deletes the object pointed to by the stored pointer and then stores a copy of + p, which must have been allocated via a C++ new expression or be 0. The + guarantee that this does not throw exceptions depends on the requirement that + the deleted object's destructor does not throw exceptions. See the smart + pointer common requirements.

+

indirection

+
T & operator*() const; // never throws
+

Returns a reference to the object pointed to by the stored pointer. Behavior is + undefined if the stored pointer is 0.

+
T * operator->() const; // never throws
+

Returns the stored pointer. Behavior is undefined if the stored pointer is 0.

+

get

+
T * get() const; // never throws
+

Returns the stored pointer. T need not be a complete type. See the smart + pointer common requirements.

+

conversions

+
operator unspecified-bool-type () const; // never throws
+

Returns an unspecified value that, when used in boolean contexts, is equivalent + to get() != 0.

+

swap

+
void swap(scoped_ptr & b); // never throws
+

Exchanges the contents of the two smart pointers. T need not be a + complete type. See the smart pointer common + requirements.

+

Free Functions

+

swap

+
template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. + Provided as an aid to generic programming.

+

Example

+

Here's an example that uses scoped_ptr.

+
+
#include <boost/scoped_ptr.hpp>
+#include <iostream>
+
+struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
+
+class MyClass {
+    boost::scoped_ptr<int> ptr;
+  public:
+    MyClass() : ptr(new int) { *ptr = 0; }
+    int add_one() { return ++*ptr; }
+};
+
+int main()
+{
+    boost::scoped_ptr<Shoe> x(new Shoe);
+    MyClass my_instance;
+    std::cout << my_instance.add_one() << '\n';
+    std::cout << my_instance.add_one() << '\n';
+}
+
+

The example program produces the beginning of a child's nursery rhyme:

+
+
1
+2
+Buckle my shoe
+
+

Rationale

+

The primary reason to use scoped_ptr rather than auto_ptr is to + let readers of your code know that you intend "resource acquisition is + initialization" to be applied only for the current scope, and have no intent to + transfer ownership.

+

A secondary reason to use scoped_ptr is to prevent a later maintenance + programmer from adding a function that transfers ownership by returning the auto_ptr, + because the maintenance programmer saw auto_ptr, and assumed ownership + could safely be transferred.

+

Think of bool vs int. We all know that under the covers bool + is usually just an int. Indeed, some argued against including bool + in the C++ standard because of that. But by coding bool rather than int, + you tell your readers what your intent is. Same with scoped_ptr; by + using it you are signaling intent.

+

It has been suggested that scoped_ptr<T> is equivalent to std::auto_ptr<T> + const. Ed Brey pointed out, however, that reset will not work on + a std::auto_ptr<T> const.

+

Handle/Body Idiom

+

One common usage of scoped_ptr is to implement a handle/body (also called + pimpl) idiom which avoids exposing the body (implementation) in the header + file.

+

The scoped_ptr_example_test.cpp + sample program includes a header file, scoped_ptr_example.hpp, + which uses a scoped_ptr<> to an incomplete type to hide the + implementation. The instantiation of member functions which require a complete + type occurs in the scoped_ptr_example.cpp + implementation file.

+

Frequently Asked Questions

+

Q. Why doesn't scoped_ptr have a release() member?
+ A. When reading source code, it is valuable to be able to draw + conclusions about program behavior based on the types being used. If scoped_ptr + had a release() member, it would become possible to transfer ownership of the + held pointer, weakening its role as a way of limiting resource lifetime to a + given context. Use std::auto_ptr where transfer of ownership + is required. (supplied by Dave Abrahams)

+
+

Revised + 09 January 2003

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Copyright 2002-2005 Peter Dimov. 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/shared_array.htm b/shared_array.htm new file mode 100644 index 0000000..320a54a --- /dev/null +++ b/shared_array.htm @@ -0,0 +1,185 @@ + + + + shared_array + + + +

boost.png (6897 bytes)shared_array class template

+

The shared_array class template stores a pointer to a dynamically + allocated array. (Dynamically allocated array are allocated with the C++ new[] + expression.) The object pointed to is guaranteed to be deleted when the last shared_array + pointing to it is destroyed or reset.

+

Every shared_array meets the CopyConstructible and Assignable + requirements of the C++ Standard Library, and so can be used in standard + library containers. Comparison operators are supplied so that shared_array + works with the standard library's associative containers.

+

Normally, a shared_array cannot correctly hold a pointer to an object + that has been allocated with the non-array form of new. See + shared_ptr for that usage.

+

Because the implementation uses reference counting, cycles of shared_array + instances will not be reclaimed. For example, if main() holds a shared_array + to A, which directly or indirectly holds a shared_array back to A, + A's use count will be 2. Destruction of the original shared_array + will leave A dangling with a use count of 1.

+

A shared_ptr to a std::vector is an alternative to a shared_array + that is a bit heavier duty but far more flexible.

+

The class template is parameterized on T, the type of the object pointed + to. T must meet the smart pointer + common requirements.

+

Synopsis

+
namespace boost {
+
+  template<class T> class shared_array {
+
+    public:
+      typedef T element_type;
+
+      explicit shared_array(T * p = 0);
+      template<class D> shared_array(T * p, D d);
+      ~shared_array(); // never throws
+
+      shared_array(shared_array const & r); // never throws
+
+      shared_array & operator=(shared_array const & r); // never throws
+
+      void reset(T * p = 0);
+      template<class D> void reset(T * p, D d);
+
+      T & operator[](std::ptrdiff_t i) const; // never throws
+      T * get() const; // never throws
+
+      bool unique() const; // never throws
+      long use_count() const; // never throws
+
+      operator unspecified-bool-type() const; // never throws
+
+      void swap(shared_array<T> & b); // never throws
+  };
+
+  template<class T>
+    bool operator==(shared_array<T> const & a, shared_array<T> const & b); // never throws
+  template<class T>
+    bool operator!=(shared_array<T> const & a, shared_array<T> const & b); // never throws
+  template<class T>
+    bool operator<(shared_array<T> const & a, shared_array<T> const & b); // never throws
+
+  template<class T> void swap(shared_array<T> & a, shared_array<T> & b); // never throws
+
+}
+

Members

+

element_type

+
typedef T element_type;
+

Provides the type of the stored pointer.

+

constructors

+
explicit shared_array(T * p = 0);
+

Constructs a shared_array, storing a copy of p, which must be a + pointer to an array that was allocated via a C++ new[] expression or be + 0. Afterwards, the use count is 1 (even if p == 0; see + ~shared_array). The only exception which may be thrown by this + constructor is std::bad_alloc. If an exception is thrown, delete[] p + is called.

+
template<class D> shared_array(T * p, D d);
+

Constructs a shared_array, storing a copy of p and of d. + Afterwards, the use count is 1. D's copy + constructor and destructor must not throw. When the the time comes to delete + the array pointed to by p, the object d is used in the statement d(p). + Invoking the object d with parameter p in this way must not + throw. The only exception which may be thrown by this constructor is std::bad_alloc. + If an exception is thrown, d(p) is called.

+
shared_array(shared_array const & r); // never throws
+

Constructs a shared_array, as if by storing a copy of the pointer stored + in r. Afterwards, the use count for all copies + is 1 more than the initial use count.

+

destructor

+
~shared_array(); // never throws
+

Decrements the use count. Then, if the use count is 0, + deletes the array pointed to by the stored pointer. Note that delete[] on + a pointer with a value of 0 is harmless. T need not be a complete type. + The guarantee that this does not throw exceptions depends on the requirement + that the deleted object's destructor does not throw exceptions. See the smart + pointer common requirements.

+

assignment

+
shared_array & operator=(shared_array const & r); // never throws
+

Constructs a new shared_array as described above, + then replaces this shared_array with the new one, destroying the + replaced object.

+

reset

+
void reset(T * p = 0);
+

Constructs a new shared_array as described above, + then replaces this shared_array with the new one, destroying the + replaced object. The only exception which may be thrown is std::bad_alloc. + If an exception is thrown, delete[] p is called.

+
template<class D> void reset(T * p, D d);
+

Constructs a new shared_array as described above, + then replaces this shared_array with the new one, destroying the + replaced object. D's copy constructor must not throw. The only exception + which may be thrown is std::bad_alloc. If an exception is thrown, d(p) + is called.

+

indexing

+
T & operator[](std::ptrdiff_t i) const; // never throws
+

Returns a reference to element i of the array pointed to by the stored + pointer. Behavior is undefined and almost certainly undesirable if the stored + pointer is 0, or if i is less than 0 or is greater than or equal to the + number of elements in the array.

+

get

+
T * get() const; // never throws
+

Returns the stored pointer. T need not be a complete type. See the smart + pointer common requirements.

+

unique

+
bool unique() const; // never throws
+

Returns true if no other shared_array is sharing ownership of the stored + pointer, false otherwise. T need not be a complete type. See the smart + pointer common requirements.

+

use_count

+
long use_count() const; // never throws
+

Returns the number of shared_array objects sharing ownership of the + stored pointer. T need not be a complete type. See the smart pointer + common requirements.

+

Because use_count is not necessarily efficient to implement for + implementations of shared_array that do not use an explicit reference + count, it might be removed from some future version. Thus it should be used for + debugging purposes only, and not production code.

+

conversions

+
operator unspecified-bool-type () const; // never throws
+

Returns an unspecified value that, when used in boolean contexts, is equivalent + to get() != 0.

+

swap

+
void swap(shared_ptr & b); // never throws
+

Exchanges the contents of the two smart pointers. T need not be a + complete type. See the smart pointer common + requirements.

+

Free Functions

+

comparison

+
template<class T>
+  bool operator==(shared_array<T> const & a, shared_array<T> const & b); // never throws
+template<class T>
+  bool operator!=(shared_array<T> const & a, shared_array<T> const & b); // never throws
+template<class T>
+  bool operator<(shared_array<T> const & a, shared_array<T> const & b); // never throws
+

Compares the stored pointers of the two smart pointers. T need not be a + complete type. See the smart pointer common + requirements.

+

The operator< overload is provided to define an ordering so that shared_array + objects can be used in associative containers such as std::map. The + implementation uses std::less<T *> to perform the comparison. This + ensures that the comparison is handled correctly, since the standard mandates + that relational operations on pointers are unspecified (5.9 [expr.rel] + paragraph 2) but std::less<> on pointers is well-defined (20.3.3 + [lib.comparisons] paragraph 8).

+

swap

+
template<class T>
+  void swap(shared_array<T> & a, shared_array<T> & b) // never throws
+

Equivalent to a.swap(b). Matches the interface of std::swap. + Provided as an aid to generic programming.

+
+

Revised + + 09 January 2003

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Copyright 2002-2005 Peter Dimov. 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/shared_ptr.htm b/shared_ptr.htm new file mode 100644 index 0000000..77e1fa8 --- /dev/null +++ b/shared_ptr.htm @@ -0,0 +1,722 @@ + + + + shared_ptr + + + +

boost.png (6897 bytes)shared_ptr class template

+

Introduction
+ Best Practices
+ Synopsis
+ Members
+ Free Functions
+ Example
+ Handle/Body Idiom
+ Thread Safety
+ Frequently Asked Questions
+ Smart Pointer Timings
+ Programming Techniques

+

Introduction

+

The shared_ptr class template stores a pointer to a dynamically allocated + object, typically with a C++ new-expression. The object pointed to is + guaranteed to be deleted when the last shared_ptr pointing to it is + destroyed or reset. See the example.

+

Every shared_ptr meets the CopyConstructible and Assignable + requirements of the C++ Standard Library, and so can be used in standard + library containers. Comparison operators are supplied so that shared_ptr + works with the standard library's associative containers.

+

Normally, a shared_ptr cannot correctly hold a pointer to a dynamically + allocated array. See shared_array for + that usage.

+

Because the implementation uses reference counting, cycles of shared_ptr instances + will not be reclaimed. For example, if main() holds a shared_ptr to + A, which directly or indirectly holds a shared_ptr back to A, + A's use count will be 2. Destruction of the original shared_ptr will + leave A dangling with a use count of 1. Use weak_ptr + to "break cycles."

+

The class template is parameterized on T, the type of the object pointed + to. shared_ptr and most of its member functions place no + requirements on T; it is allowed to be an incomplete type, or + void. Member functions that do place additional requirements (constructors, + reset) are explicitly documented below.

+

shared_ptr<T> can be implicitly converted to shared_ptr<U> + whenever T* can be implicitly converted to U*. + In particular, shared_ptr<T> is implicitly convertible + to shared_ptr<T const>, to shared_ptr<U> + where U is an accessible base of T, and to + shared_ptr<void>.

+

shared_ptr is now part of TR1, the first C++ + Library Technical Report. The latest draft of TR1 is available + at the following location:

+

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1745.pdf + (1.36Mb PDF)

+

This implementation conforms to the TR1 specification, with the only exception + that it resides in namespace boost instead of std::tr1.

+

Best Practices

+

A simple guideline that nearly eliminates the possibility of memory leaks is: + always use a named smart pointer variable to hold the result of new. + Every occurence of the new keyword in the code should have the + form:

+
shared_ptr<T> p(new Y);
+

It is, of course, acceptable to use another smart pointer in place of shared_ptr + above; having T and Y be the same type, or + passing arguments to Y's constructor is also OK.

+

If you observe this guideline, it naturally follows that you will have no + explicit deletes; try/catch constructs will + be rare.

+

Avoid using unnamed shared_ptr temporaries to save typing; to + see why this is dangerous, consider this example:

+
void f(shared_ptr<int>, int);
+int g();
+
+void ok()
+{
+    shared_ptr<int> p(new int(2));
+    f(p, g());
+}
+
+void bad()
+{
+    f(shared_ptr<int>(new int(2)), g());
+}
+
+

The function ok follows the guideline to the letter, whereas + bad constructs the temporary shared_ptr in place, + admitting the possibility of a memory leak. Since function arguments are + evaluated in unspecified order, it is possible for new int(2) to + be evaluated first, g() second, and we may never get to the + shared_ptr constructor if g throws an exception. + See Herb Sutter's treatment (also + here) of the issue for more information.

+

The exception safety problem described above may also be eliminated by using + the make_shared + or allocate_shared + factory functions defined in boost/make_shared.hpp. These factory functions also provide + an efficiency benefit by consolidating allocations.

+

Synopsis

+
namespace boost {
+
+  class bad_weak_ptr: public std::exception;
+
+  template<class T> class weak_ptr;
+
+  template<class T> class shared_ptr {
+
+    public:
+
+      typedef T element_type;
+
+      shared_ptr(); // never throws
+      template<class Y> explicit shared_ptr(Y * p);
+      template<class Y, class D> shared_ptr(Y * p, D d);
+      template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
+      ~shared_ptr(); // never throws
+
+      shared_ptr(shared_ptr const & r); // never throws
+      template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
+      template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); // never throws
+      template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);
+      template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r);
+
+      shared_ptr & operator=(shared_ptr const & r); // never throws
+      template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
+      template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
+
+      void reset(); // never throws
+      template<class Y> void reset(Y * p);
+      template<class Y, class D> void reset(Y * p, D d);
+      template<class Y, class D, class A> void reset(Y * p, D d, A a);
+      template<class Y> void reset(shared_ptr<Y> const & r, T * p); // never throws
+
+      T & operator*() const; // never throws
+      T * operator->() const; // never throws
+      T * get() const; // never throws
+
+      bool unique() const; // never throws
+      long use_count() const; // never throws
+
+      operator unspecified-bool-type() const; // never throws
+
+      void swap(shared_ptr & b); // never throws
+  };
+
+  template<class T, class U>
+    bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+  template<class T, class U>
+    bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+  template<class T, class U>
+    bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+  template<class T> void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
+
+  template<class T> T * get_pointer(shared_ptr<T> const & p); // never throws
+
+  template<class T, class U>
+    shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws
+
+  template<class T, class U>
+    shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r); // never throws
+
+  template<class T, class U>
+    shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r); // never throws
+
+  template<class E, class T, class Y>
+    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);
+
+  template<class D, class T>
+    D * get_deleter(shared_ptr<T> const & p);
+}
+

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

+
shared_ptr(); // never throws
+
+

Effects: Constructs an empty shared_ptr.

+

Postconditions: use_count() == 0 && get() == 0.

+

Throws: nothing.

+
+

[The nothrow guarantee is important, since reset() is specified + in terms of the default constructor; this implies that the constructor must not + allocate memory.]

+
template<class Y> explicit shared_ptr(Y * p);
+
+

Requirements: p must be convertible to T *. Y + must be a complete type. The expression delete p must be + well-formed, must not invoke undefined behavior, and must not throw exceptions. +

+

Effects: Constructs a shared_ptr that owns the pointer p.

+

Postconditions: use_count() == 1 && get() == p.

+

Throws: std::bad_alloc, or an implementation-defined + exception when a resource other than memory could not be obtained.

+

Exception safety: If an exception is thrown, delete p is + called.

+

Notes: p must be a pointer to an object that was + allocated via a C++ new expression or be 0. The postcondition that + use count is 1 holds even if p is 0; invoking delete + on a pointer that has a value of 0 is harmless.

+
+

[This constructor has been changed to a template in order to remember the actual + pointer type passed. The destructor will call delete with the + same pointer, complete with its original type, even when T does + not have a virtual destructor, or is void.

+

The optional intrusive counting support has been dropped as it exposes too much + implementation details and doesn't interact well with weak_ptr. + The current implementation uses a different mechanism, + enable_shared_from_this, to solve the "shared_ptr from + this" problem.]

+ +
template<class Y, class D> shared_ptr(Y * p, D d);
+template<class Y, class D, class A> shared_ptr(Y * p, D d, A a);
+
+

Requirements: p must be convertible to T *. D + must be CopyConstructible. The copy constructor and destructor + of D must not throw. The expression d(p) must be + well-formed, must not invoke undefined behavior, and must not throw exceptions. + A must be an Allocator, as described in section 20.1.5 (Allocator + requirements) of the C++ Standard. +

+

Effects: Constructs a shared_ptr that owns the pointer + p and the deleter d. The second constructor allocates + memory using a copy of a.

+

Postconditions: use_count() == 1 && get() == p.

+

Throws: std::bad_alloc, or an implementation-defined + exception when a resource other than memory could not be obtained.

+

Exception safety: If an exception is thrown, d(p) is called.

+

Notes: When the the time comes to delete the object pointed to by p, + the stored copy of d is invoked with the stored copy of p + as an argument.

+
+

[Custom deallocators allow a factory function returning a shared_ptr + to insulate the user from its memory allocation strategy. Since the deallocator + is not part of the type, changing the allocation strategy does not break source + or binary compatibility, and does not require a client recompilation. For + example, a "no-op" deallocator is useful when returning a shared_ptr + to a statically allocated object, and other variations allow a shared_ptr + to be used as a wrapper for another smart pointer, easing interoperability.

+

The support for custom deallocators does not impose significant overhead. Other + shared_ptr features still require a deallocator to be kept.

+

The requirement that the copy constructor of D does not throw comes from + the pass by value. If the copy constructor throws, the pointer is leaked. + Removing the requirement requires a pass by (const) reference.

+

The main problem with pass by reference lies in its interaction with rvalues. A + const reference may still cause a copy, and will require a const operator(). A + non-const reference won't bind to an rvalue at all. A good solution to this + problem is the rvalue reference proposed in + N1377/N1385.]

+
shared_ptr(shared_ptr const & r); // never throws
+template<class Y> shared_ptr(shared_ptr<Y> const & r); // never throws
+
+

Effects: If r is empty, constructs an empty shared_ptr; + otherwise, constructs a shared_ptr that shares ownership with r.

+

Postconditions: get() == r.get() && use_count() == + r.use_count().

+

Throws: nothing.

+
+
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); // never throws
+
+

Effects: constructs a shared_ptr that shares ownership with + r and stores p.

+

Postconditions: get() == p && use_count() == r.use_count().

+

Throws: nothing.

+
+
template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);
+
+

Effects: Constructs a shared_ptr that shares ownership with + r and stores a copy of the pointer stored in r.

+

Postconditions: use_count() == r.use_count().

+

Throws: bad_weak_ptr when r.use_count() == 0.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+
+
template<class Y> shared_ptr(std::auto_ptr<Y> & r);
+
+

Effects: Constructs a shared_ptr, as if by storing a copy of r.release().

+

Postconditions: use_count() == 1.

+

Throws: std::bad_alloc, or an implementation-defined + exception when a resource other than memory could not be obtained.

+

Exception safety: If an exception is thrown, the constructor has no + effect.

+
+

[This constructor takes a the source auto_ptr by reference and + not by value, and cannot accept auto_ptr temporaries. This is + by design, as the constructor offers the strong guarantee; an rvalue reference + would solve this problem, too.]

+

destructor

+
~shared_ptr(); // never throws
+
+

Effects:

+
    +
  • + If *this is empty, or shares ownership with + another shared_ptr instance (use_count() > 1), + there are no side effects. +
  • + Otherwise, if *this owns a pointer p + and a deleter d, d(p) + is called. +
  • + Otherwise, *this owns a pointer p, + and delete p is called.
+

Throws: nothing.

+
+

assignment

+
shared_ptr & operator=(shared_ptr const & r); // never throws
+template<class Y> shared_ptr & operator=(shared_ptr<Y> const & r); // never throws
+template<class Y> shared_ptr & operator=(std::auto_ptr<Y> & r);
+
+

Effects: Equivalent to shared_ptr(r).swap(*this).

+

Returns: *this.

+

Notes: The use count updates caused by the temporary object construction + and destruction are not considered observable side effects, and the + implementation is free to meet the effects (and the implied guarantees) via + different means, without creating a temporary. In particular, in the example:

+
shared_ptr<int> p(new int);
+shared_ptr<void> q(p);
+p = p;
+q = p;
+
+

both assignments may be no-ops.

+
+

reset

+
void reset(); // never throws
+
+

Effects: Equivalent to shared_ptr().swap(*this).

+
+
template<class Y> void reset(Y * p);
+
+

Effects: Equivalent to shared_ptr(p).swap(*this).

+
+
template<class Y, class D> void reset(Y * p, D d);
+
+

Effects: Equivalent to shared_ptr(p, d).swap(*this).

+
+
template<class Y, class D, class A> void reset(Y * p, D d, A a);
+
+

Effects: Equivalent to shared_ptr(p, d, a).swap(*this).

+
+
template<class Y> void reset(shared_ptr<Y> const & r, T * p); // never throws
+
+

Effects: Equivalent to shared_ptr(r, p).swap(*this).

+
+

indirection

+
T & operator*() const; // never throws
+
+

Requirements: The stored pointer must not be 0.

+

Returns: a reference to the object pointed to by the stored pointer.

+

Throws: nothing.

+
+
T * operator->() const; // never throws
+
+

Requirements: The stored pointer must not be 0.

+

Returns: the stored pointer.

+

Throws: nothing.

+
+

get

+
T * get() const; // never throws
+
+

Returns: the stored pointer.

+

Throws: nothing.

+
+

unique

+
bool unique() const; // never throws
+
+

Returns: use_count() == 1.

+

Throws: nothing.

+

Notes: unique() may be faster than use_count(). + If you are using unique() to implement copy on write, do not rely + on a specific value when the stored pointer is zero.

+
+

use_count

+
long use_count() const; // never throws
+
+

Returns: the number of shared_ptr objects, *this included, + that share ownership with *this, or 0 when *this + is empty.

+

Throws: nothing.

+

Notes: use_count() is not necessarily efficient. Use only + for debugging and testing purposes, not for production code.

+
+

conversions

+
operator unspecified-bool-type () const; // never throws
+
+

Returns: an unspecified value that, when used in boolean contexts, is + equivalent to get() != 0.

+

Throws: nothing.

+

Notes: This conversion operator allows shared_ptr objects to be + used in boolean contexts, like if (p && p->valid()) {}. + The actual target type is typically a pointer to a member function, avoiding + many of the implicit conversion pitfalls.

+
+

[The conversion to bool is not merely syntactic sugar. It allows shared_ptrs + to be declared in conditions when using dynamic_pointer_cast + or weak_ptr::lock.]

+

swap

+
void swap(shared_ptr & b); // never throws
+
+

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+
+

Free Functions

+

comparison

+
template<class T, class U>
+  bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+

Returns: a.get() == b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+

Returns: a.get() != b.get().

+

Throws: nothing.

+
+
template<class T, class U>
+  bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b); // never throws
+
+

Returns: an unspecified value such that

+
    +
  • + operator< is a strict weak ordering as described in section 25.3 [lib.alg.sorting] + of the C++ standard; +
  • + under the equivalence relation defined by operator<, !(a + < b) && !(b < a), two shared_ptr instances + are equivalent if and only if they share ownership or are both empty.
+

Throws: nothing.

+

Notes: Allows shared_ptr objects to be used as keys in + associative containers.

+
+

[Operator< has been preferred over a std::less + specialization for consistency and legality reasons, as std::less + is required to return the results of operator<, and many + standard algorithms use operator< instead of std::less + for comparisons when a predicate is not supplied. Composite objects, like std::pair, + also implement their operator< in terms of their contained + subobjects' operator<.

+

The rest of the comparison operators are omitted by design.]

+

swap

+
template<class T>
+  void swap(shared_ptr<T> & a, shared_ptr<T> & b); // never throws
+
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

Notes: Matches the interface of std::swap. Provided as an aid to + generic programming.

+
+

[swap is defined in the same namespace as shared_ptr + as this is currently the only legal way to supply a swap function + that has a chance to be used by the standard library.]

+

get_pointer

+
template<class T>
+  T * get_pointer(shared_ptr<T> const & p); // never throws
+
+

Returns: p.get().

+

Throws: nothing.

+

Notes: Provided as an aid to generic programming. Used by + mem_fn.

+
+

static_pointer_cast

+
template<class T, class U>
+  shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r); // never throws
+
+

Requires: The expression static_cast<T*>(r.get()) + must be well-formed.

+

Returns: If r is empty, an empty shared_ptr<T>; + otherwise, a shared_ptr<T> object that stores a copy of + static_cast<T*>(r.get()) and shares ownership with r.

+

Throws: nothing.

+

Notes: the seemingly equivalent expression

+

shared_ptr<T>(static_cast<T*>(r.get()))

+

will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

const_pointer_cast

+
template<class T, class U>
+  shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r); // never throws
+
+

Requires: The expression const_cast<T*>(r.get()) + must be well-formed.

+

Returns: If r is empty, an empty shared_ptr<T>; + otherwise, a shared_ptr<T> object that stores a copy of + const_cast<T*>(r.get()) and shares ownership with r.

+

Throws: nothing.

+

Notes: the seemingly equivalent expression

+

shared_ptr<T>(const_cast<T*>(r.get()))

+

will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

dynamic_pointer_cast

+
template<class T, class U>
+  shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r);
+
+

Requires: The expression dynamic_cast<T*>(r.get()) + must be well-formed and its behavior defined.

+

Returns:

+
    +
  • + When dynamic_cast<T*>(r.get()) returns a nonzero value, a + shared_ptr<T> object that stores a copy of it and shares + ownership with r; +
  • + Otherwise, an empty shared_ptr<T> object.
+

Throws: nothing.

+

Notes: the seemingly equivalent expression

+

shared_ptr<T>(dynamic_cast<T*>(r.get()))

+

will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

operator<<

+
template<class E, class T, class Y>
+    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p);
+
+

Effects: os << p.get();.

+

Returns: os.

+
+

get_deleter

+
template<class D, class T>
+    D * get_deleter(shared_ptr<T> const & p);
+
+

Returns: If *this owns a deleter d + of type (cv-unqualified) D, returns &d; + otherwise returns 0.

+

Throws: nothing.

+
+

Example

+

See shared_ptr_example.cpp for a + complete example program. The program builds a std::vector and std::set + of shared_ptr objects.

+

Note that after the containers have been populated, some of the shared_ptr + objects will have a use count of 1 rather than a use count of 2, since the set + is a std::set rather than a std::multiset, and thus does not + contain duplicate entries. Furthermore, the use count may be even higher at + various times while push_back and insert container operations are + performed. More complicated yet, the container operations may throw exceptions + under a variety of circumstances. Getting the memory management and exception + handling in this example right without a smart pointer would be a nightmare.

+

Handle/Body Idiom

+

One common usage of shared_ptr is to implement a handle/body (also called + pimpl) idiom which avoids exposing the body (implementation) in the header + file.

+

The shared_ptr_example2_test.cpp + sample program includes a header file, shared_ptr_example2.hpp, + which uses a shared_ptr<> to an incomplete type to hide the + implementation. The instantiation of member functions which require a complete + type occurs in the shared_ptr_example2.cpp + implementation file. Note that there is no need for an explicit destructor. + Unlike ~scoped_ptr, ~shared_ptr does not require that T be a complete + type.

+

Thread Safety

+

shared_ptr objects offer the same level of thread safety as + built-in types. A shared_ptr instance can be "read" (accessed + using only const operations) simultaneously by multiple threads. Different shared_ptr + instances can be "written to" (accessed using mutable operations such as operator= + or reset) simultaneosly by multiple threads (even + when these instances are copies, and share the same reference count + underneath.)

+

Any other simultaneous accesses result in undefined behavior.

+

Examples:

+
shared_ptr<int> p(new int(42));
+
+//--- Example 1 ---
+
+// thread A
+shared_ptr<int> p2(p); // reads p
+
+// thread B
+shared_ptr<int> p3(p); // OK, multiple reads are safe
+
+//--- Example 2 ---
+
+// thread A
+p.reset(new int(1912)); // writes p
+
+// thread B
+p2.reset(); // OK, writes p2
+
+//--- Example 3 ---
+
+// thread A
+p = p3; // reads p3, writes p
+
+// thread B
+p3.reset(); // writes p3; undefined, simultaneous read/write
+
+//--- Example 4 ---
+
+// thread A
+p3 = p2; // reads p2, writes p3
+
+// thread B
+// p2 goes out of scope: undefined, the destructor is considered a "write access"
+
+//--- Example 5 ---
+
+// thread A
+p3.reset(new int(1));
+
+// thread B
+p3.reset(new int(2)); // undefined, multiple writes
+
+

 

+

Starting with Boost release 1.33.0, shared_ptr uses a lock-free + implementation on the following platforms:

+
    +
  • + GNU GCC on x86 or x86-64; +
  • + GNU GCC on IA64; +
  • + Metrowerks CodeWarrior on PowerPC; +
  • + GNU GCC on PowerPC; +
  • + Windows.
+

If your program is single-threaded and does not link to any libraries that might + have used shared_ptr in its default configuration, you can + #define the macro BOOST_SP_DISABLE_THREADS on a + project-wide basis to switch to ordinary non-atomic reference count updates.

+

(Defining BOOST_SP_DISABLE_THREADS in some, but not all, + translation units is technically a violation of the One Definition Rule and + undefined behavior. Nevertheless, the implementation attempts to do its best to + accommodate the request to use non-atomic updates in those translation units. + No guarantees, though.)

+

You can define the macro BOOST_SP_USE_PTHREADS to turn off the + lock-free platform-specific implementation and fall back to the generic pthread_mutex_t-based + code.

+

Frequently Asked Questions

+

Q. There are several variations of shared pointers, with different + tradeoffs; why does the smart pointer library supply only a single + implementation? It would be useful to be able to experiment with each type so + as to find the most suitable for the job at hand?

+

+ A. An important goal of shared_ptr is to provide a + standard shared-ownership pointer. Having a single pointer type is important + for stable library interfaces, since different shared pointers typically cannot + interoperate, i.e. a reference counted pointer (used by library A) cannot share + ownership with a linked pointer (used by library B.)
+

+

Q. Why doesn't shared_ptr have template parameters supplying + traits or policies to allow extensive user customization?

+

+ A. Parameterization discourages users. The shared_ptr template is + carefully crafted to meet common needs without extensive parameterization. Some + day a highly configurable smart pointer may be invented that is also very easy + to use and very hard to misuse. Until then, shared_ptr is the smart + pointer of choice for a wide range of applications. (Those interested in policy + based smart pointers should read + Modern C++ Design by Andrei Alexandrescu.)
+

+

Q. I am not convinced. Default parameters can be used where appropriate + to hide the complexity. Again, why not policies?

+

+ A. Template parameters affect the type. See the answer to the first + question above.
+

+

Q. Why doesn't shared_ptr use a linked list implementation?

+

+ A. A linked list implementation does not offer enough advantages to + offset the added cost of an extra pointer. See timings + page. In addition, it is expensive to make a linked list implementation thread + safe.
+

+

Q. Why doesn't shared_ptr (or any of the other Boost smart + pointers) supply an automatic conversion to T*?

+

+ A. Automatic conversion is believed to be too error prone.
+

+

Q. Why does shared_ptr supply use_count()?

+

+ A. As an aid to writing test cases and debugging displays. One of the + progenitors had use_count(), and it was useful in tracking down bugs in a + complex project that turned out to have cyclic-dependencies.
+

+

Q. Why doesn't shared_ptr specify complexity requirements?

+

+ A. Because complexity requirements limit implementors and complicate the + specification without apparent benefit to shared_ptr users. For example, + error-checking implementations might become non-conforming if they had to meet + stringent complexity requirements.
+

+

Q. Why doesn't shared_ptr provide a release() function?

+

+ A. shared_ptr cannot give away ownership unless it's unique() + because the other copy will still destroy the object.

+

Consider:

+
shared_ptr<int> a(new int);
+shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
+
+int * p = a.release();
+
+// Who owns p now? b will still call delete on it in its destructor.
+
+

Furthermore, the pointer returned by release() would be difficult + to deallocate reliably, as the source shared_ptr could have been created + with a custom deleter.
+

+

Q. Why is operator->() const, but its return value is a + non-const pointer to the element type?

+

+ A. Shallow copy pointers, including raw pointers, typically don't + propagate constness. It makes little sense for them to do so, as you can always + obtain a non-const pointer from a const one and then proceed to modify the + object through it.shared_ptr is "as close to raw pointers as possible + but no closer".
+
+

+
+

+ $Date$

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Copyright 2002-2005 Peter Dimov. 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/smart_ptr.htm b/smart_ptr.htm new file mode 100644 index 0000000..92ad2be --- /dev/null +++ b/smart_ptr.htm @@ -0,0 +1,196 @@ + + + + Smart Pointers + + + +

boost.png (6897 bytes)Smart Pointers

+

Introduction
+ Common Requirements
+ Exception Safety
+ Exception-specifications
+ History and Acknowledgements
+ References

+

Introduction

+

Smart pointers are objects which store pointers to dynamically allocated (heap) + objects. They behave much like built-in C++ pointers except that they + automatically delete the object pointed to at the appropriate time. Smart + pointers are particularly useful in the face of exceptions as they ensure + proper destruction of dynamically allocated objects. They can also be used to + keep track of dynamically allocated objects shared by multiple owners.

+

Conceptually, smart pointers are seen as owning the object pointed to, and thus + responsible for deletion of the object when it is no longer needed.

+

The smart pointer library provides six smart pointer class templates:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
scoped_ptr<boost/scoped_ptr.hpp>Simple sole ownership of single objects. Noncopyable.
scoped_array<boost/scoped_array.hpp>Simple sole ownership of arrays. Noncopyable.
shared_ptr<boost/shared_ptr.hpp>Object ownership shared among multiple pointers.
shared_array<boost/shared_array.hpp>Array ownership shared among multiple pointers.
weak_ptr<boost/weak_ptr.hpp>Non-owning observers of an object owned by shared_ptr.
intrusive_ptr<boost/intrusive_ptr.hpp>Shared ownership of objects with an embedded reference count.
+
+

These templates are designed to complement the std::auto_ptr template.

+

They are examples of the "resource acquisition is initialization" idiom + described in Bjarne Stroustrup's "The C++ Programming Language", 3rd edition, + Section 14.4, Resource Management.

+

Additionally, the smart pointer library provides efficient factory functions + for creating shared_ptr objects:

+
+ + + + + + +
make_shared and allocate_shared<boost/make_shared.hpp>Efficient creation of shared_ptr objects.
+
+

A test program, smart_ptr_test.cpp, is + provided to verify correct operation.

+

A page on compatibility with older versions of + the Boost smart pointer library describes some of the changes since earlier + versions of the smart pointer implementation.

+

A page on smart pointer timings will be of interest + to those curious about performance issues.

+

A page on smart pointer programming techniques lists + some advanced applications of shared_ptr and weak_ptr.

+

Common Requirements

+

These smart pointer class templates have a template parameter, T, which + specifies the type of the object pointed to by the smart pointer. The behavior + of the smart pointer templates is undefined if the destructor or operator delete + for objects of type T throw exceptions.

+

T may be an incomplete type at the point of smart pointer declaration. + Unless otherwise specified, it is required that T be a complete type at + points of smart pointer instantiation. Implementations are required to diagnose + (treat as an error) all violations of this requirement, including deletion of + an incomplete type. See the description of the + checked_delete function template.

+

Note that shared_ptr does not have this restriction, as most of + its member functions do not require T to be a complete type.

+

Rationale

+

The requirements on T are carefully crafted to maximize safety yet allow + handle-body (also called pimpl) and similar idioms. In these idioms a smart + pointer may appear in translation units where T is an incomplete type. + This separates interface from implementation and hides implementation from + translation units which merely use the interface. Examples described in the + documentation for specific smart pointers illustrate use of smart pointers in + these idioms.

+

Note that scoped_ptr requires that T be a complete type at + destruction time, but shared_ptr does not.

+

Exception Safety

+

Several functions in these smart pointer classes are specified as having "no + effect" or "no effect except such-and-such" if an exception is thrown. This + means that when an exception is thrown by an object of one of these classes, + the entire program state remains the same as it was prior to the function call + which resulted in the exception being thrown. This amounts to a guarantee that + there are no detectable side effects. Other functions never throw exceptions. + The only exception ever thrown by functions which do throw (assuming T meets + the common requirements) is std::bad_alloc, + and that is thrown only by functions which are explicitly documented as + possibly throwing std::bad_alloc.

+

Exception-specifications

+

Exception-specifications are not used; see + exception-specification rationale.

+

All the smart pointer templates contain member functions which can never throw + exceptions, because they neither throw exceptions themselves nor call other + functions which may throw exceptions. These members are indicated by a comment: + // never throws. +

+

Functions which destroy objects of the pointed to type are prohibited from + throwing exceptions by the common requirements.

+

History and Acknowledgements

+

January 2002. Peter Dimov reworked all four classes, adding features, fixing + bugs, and splitting them into four separate headers, and added weak_ptr. + See the compatibility page for a summary of the + changes.

+

May 2001. Vladimir Prus suggested requiring a complete type on destruction. + Refinement evolved in discussions including Dave Abrahams, Greg Colvin, Beman + Dawes, Rainer Deyke, Peter Dimov, John Maddock, Vladimir Prus, Shankar Sai, and + others.

+

November 1999. Darin Adler provided operator ==, operator !=, and std::swap + and std::less specializations for shared types.

+

September 1999. Luis Coelho provided shared_ptr::swap and shared_array::swap

+

May 1999. In April and May, 1999, Valentin Bonnard and David Abrahams made a + number of suggestions resulting in numerous improvements.

+

October 1998. Beman Dawes proposed reviving the original semantics under the + names safe_ptr and counted_ptr, meeting of Per Andersson, Matt + Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis, Dietmar Kühl, + Nathan Myers, Chichiang Wan and Judy Ward. During the discussion, the four new + class names were finalized, it was decided that there was no need to exactly + follow the std::auto_ptr interface, and various function signatures and + semantics were finalized.

+

Over the next three months, several implementations were considered for shared_ptr, + and discussed on the boost.org mailing list. + The implementation questions revolved around the reference count which must be + kept, either attached to the pointed to object, or detached elsewhere. Each of + those variants have themselves two major variants: +

    +
  • + Direct detached: the shared_ptr contains a pointer to the object, and a pointer + to the count. +
  • + Indirect detached: the shared_ptr contains a pointer to a helper object, which + in turn contains a pointer to the object and the count. +
  • + Embedded attached: the count is a member of the object pointed to. +
  • + Placement attached: the count is attached via operator new manipulations.
  • +
+

Each implementation technique has advantages and disadvantages. We went so far + as to run various timings of the direct and indirect approaches, and found that + at least on Intel Pentium chips there was very little measurable difference. + Kevlin Henney provided a paper he wrote on "Counted Body Techniques." Dietmar + Kühl suggested an elegant partial template specialization technique to allow + users to choose which implementation they preferred, and that was also + experimented with.

+

But Greg Colvin and Jerry Schwarz argued that "parameterization will discourage + users", and in the end we choose to supply only the direct implementation.

+

Summer, 1994. Greg Colvin proposed to the C++ Standards Committee classes named auto_ptr + and counted_ptr which were very similar to what we now call scoped_ptr + and shared_ptr. [Col-94] In one of the very few + cases where the Library Working Group's recommendations were not followed by + the full committee, counted_ptr was rejected and surprising + transfer-of-ownership semantics were added to auto_ptr.

+

References

+

[Col-94] Gregory Colvin, + Exception Safe Smart Pointers, C++ committee document 94-168/N0555, + July, 1994.

+

[E&D-94] John R. Ellis & David L. Detlefs, + Safe, Efficient Garbage Collection for C++, Usenix Proceedings, + February, 1994. This paper includes an extensive discussion of weak pointers + and an extensive bibliography.

+
+

$Date$

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + 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/smarttest.zip b/smarttest.zip new file mode 100644 index 0000000..2464b10 Binary files /dev/null and b/smarttest.zip differ diff --git a/smarttests.htm b/smarttests.htm new file mode 100644 index 0000000..1833719 --- /dev/null +++ b/smarttests.htm @@ -0,0 +1,543 @@ + + + + + +Smart Pointer Timings + + + + + +

boost.png (6897 bytes)Smart Pointer Timings

+ +

In late January 2000, Mark Borgerding put forward a suggestion to boost for + a new design of smart pointer whereby an intrusive doubly linked list is used + to join together all instances of smart pointers sharing a given raw pointer. + This allowed avoidance of the costly heap allocation of a reference count that + occurred in the initial construction of the then current version of boost::shared_ptr. + Of course, nothing is for free and the benefit here was gained at the expense + of increased size and more costly copy operations. A debate ensued on the boost + mailing list and the tests which this page describes were performed to provide + a guide for current and future investigations into smart pointer implementation + strategies.

+

Thanks are due to Dave Abrahams, +Gavin Collings, +Greg Colvin and +Beman Dawes + for test code and trial implementations, the final version of which can be found + in .zip format here.

+

Description

+

Two tests were run: the first aimed to obtain timings for two basic individual + operations:

+
    +
  1. Initial construction from raw pointer.
  2. +
  3. An amortized copy operation consisting of half an assignment and half a + copy construction - designed to reflect average usage.
  4. +
+

The second attempted to gain more insight into normal usage by timing the fill + and sort algorithms for vectors and lists filled with the various smart pointers.

+

Five smart pointer implementation strategies were tested:

+
    +
  1. Counted pointer using a heap allocated reference count, this is referred + to as simple counted.
  2. +
  3. Counted pointer using a special purpose allocator for the reference count + - special counted.
  4. +
  5. Counted pointer using an intrusive reference count - intrusive.
  6. +
  7. Linked pointer as described above - linked.
  8. +
  9. Cyclic pointer, a counted implementation using a std::deque for allocation + with provision for weak pointers and garbage collection of cycles of pointers + - cyclic.
  10. +
+

on two compilers:

+
    +
  1. MSVC 6.0 service pack 3, using default release optimization mode (/O2 - + optimized for speed, no inlining of functions defined outside a class body + unless specified as inline).
  2. +
  3. gcc 2.95.2 using full optimization (-O3 -DNDEBUG).
  4. +
+

Additionally, generated pointer sizes (taking into account struct alignment) + were compared, as were generated code sizes for MSVC mainly by manual inspection + of generated assembly code - a necessity due to function inlining.

+

All tests were run on a PII-200 running Windows NT version 4.0

+

 

+

Operation Timing Test Results

+

The following graphs show the overall time in nanoseconds to acquire a pointer + (default construction) perform n amortized copy operations on it and finally + release it. The initial allocation time for the contained pointer is not included, + although the time for it's deallocation is. The contained pointer pointed to + a trivial class, but for the inclusion of an intrusive reference count for the + benefit of the intrusive counted shared pointer. A dumb pointer (i.e. a smart + pointer that simply acquires and releases its contained pointer with no extra + overhead) and a raw pointer were also included for comparison.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
   
  MSVC speed graph 
   
 GCC speed graph 
   
+

 

+

Fitting straight lines to the above plots gives the following figures for initialization + and amortized copy operation for the two compilers (times in nanoseconds, errors + at two standard deviations) : -

+

 

+

MSVC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
initialization
+
copy operation
+
simple counted
+
3000 +/- 170104 +/- 31
+
special counted
+
1330 +/- 5085 +/- 9
+
intrusive
+
1000 +/- 2071 +/- 3
linked970 +/- 60136 +/- 10
cyclic1290 +/- 70112 +/- 12
dumb1020 +/- 2010 +/- 4
+
raw
+
1038 +/- 3010 +/- 5
+

 

+

GCC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
initialization
+
copy operation
+
simple counted
+
4620 +/- 150301 +/- 28
+
special counted
+
1990 +/- 40264 +/- 7
+
intrusive
+
1590 +/- 70181 +/- 12
linked1470 +/- 140345 +/- 26
cyclic2180 +/- 100330 +/- 18
dumb1590 +/- 7074 +/- 12
+
raw
+
1430 +/- 6027 +/- 11
+

Note that the above times include a certain amount of loop overhead etc. for + each operation. An estimate of the pure smart pointer operation time 'overhead' + can be obtained by subtracting the dumb or raw figure from the smart pointer + time of interest.

+

Detail

+

The test involved iterating a loop which creates raw pointers. These were then + shared among a varying number (set size) of smart pointers. A range of set sizes + was used and then a line fitted to get a linear relation with number of initializations + and copy-operations. A spreadsheet was used for the line fit, and to produce + the performance graphs above.

+

 

+

Container Test Results

+

To gain some insight in to operation within real life programs, this test was + devised. Smart pointers were used to fill standard containers which were then + sorted.

+

In this case, the contained pointer pointed to a class which initializes a + private data member to a random value in its default constructor. This value + is used subsequently for the sort comparison test. The class also contains an + intrusive reference count for the benefit of the intrusive counted pointer.

+

All times are in seconds for 300,000 contained pointers.

+

GCC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 vectorlist
+
+
+
fill
+
sortfillsort
+
simple counted
+
46.542.4447.093.22
+
special counted
+
14.022.837.283.21
+
intrusive
+
12.151.917.993.08
linked12.462.328.143.27
cyclic22.603.191.633.18
+
raw
+
11.810.2427.510.77
+

 

+

MSVC

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 vectorlist
+
+
+
fill
+
sortfillsort
+
simple counted
+
1.832.371.864.85
+
special counted
+
1.042.351.384.58
+
intrusive
+
1.041.841.164.29
linked1.082.001.214.33
cyclic1.382.841.474.73
+
raw
+
0.670.281.241.81
+

 

+

Code Size

+

The following code sizes were determined by inspection of generated code for + MSVC only. Sizes are given in the form N / M / I where:

+
    +
  • N is the instruction count of the operation
  • +
  • M is the size of the code in bytes
  • +
  • I determines whether generated code was inlined or not I = inline, O = "outline"
  • +
+

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
ptr()
+
ptr(p)ptr(ptr)op=() +
~ptr()
+
+
simple counted
+
38/110/O38/110/O9/23/I22/57/I17/40/I
+
special counted
+
50/141/O50/141/O9/23/I23/64/I13/38/I
+
intrusive
+
1/2/I3/6/I3/6/I6/11/I6/11/I
+
linked
+
5/19/I5/15/I10/30/I27/59/I14/38/I
+

During the code inspection, a couple of minor points were noticed: -

+
    +
  • Function inlining was critical to performance.
  • +
  • For MSVC, at least, a "delete 0" caused execution of 11 assembly + instructions, including a function call. So in cases where performance is + at an absolute premium it can be worth inserting the extra manual test.
  • +
+

 

+

Data Size

+

The following smart pointer sizes were obtained in bytes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
MSVC
+
+
GCC
+
+
simple counted
+
+
8
+
+
8
+
+
special counted
+
+
8
+
+
12
+
+
intrusive
+
+
4
+
+
4
+
+
linked
+
+
12
+
+
12
+
+
cyclic
+
+
8
+
+
8
+
+

 

+

Summary

+

The timing results mainly speak for themselves: clearly an intrusive pointer + outperforms all others and a simple heap based counted pointer has poor performance + relative to other implementations. The selection of an optimal non-intrusive + smart pointer implementation is more application dependent, however. Where small + numbers of copies are expected, it is likely that the linked implementation + will be favoured. Conversely, for larger numbers of copies a counted pointer + with some type of special purpose allocator looks like a win. Other factors + to bear in mind are: -

+
    +
  • Deterministic individual, as opposed to amortized, operation time. This + weighs against any implementation depending on an allocator.
  • +
  • Multithreaded synchronization. This weighs against an implementation which + spreads its information as in the case of linked pointer.
  • +
+
+

Revised 19 August 2001 +

+

© Copyright Gavin Collings 2000. Permission to copy, use, modify, sell +and distribute this document is granted provided this copyright notice appears in all +copies. This document is provided "as is" without express or implied warranty, +and with no claim as to its suitability for any purpose.

+ + diff --git a/sp_techniques.html b/sp_techniques.html new file mode 100644 index 0000000..4b7363b --- /dev/null +++ b/sp_techniques.html @@ -0,0 +1,765 @@ + + + + Smart Pointer Programming Techniques + + + +

boost.png (6897 bytes)Smart Pointer Programming Techniques

+

Using incomplete classes for implementation hiding
+ The "Pimpl" idiom
+ Using abstract classes for implementation hiding
+ Preventing delete px.get()
+ Using a shared_ptr to hold a pointer to an array
+ Encapsulating allocation details, wrapping factory + functions
+ Using a shared_ptr to hold a pointer to a statically + allocated object
+ Using a shared_ptr to hold a pointer to a COM object
+ Using a shared_ptr to hold a pointer to an object + with an embedded reference count
+ Using a shared_ptr to hold another shared + ownership smart pointer
+ Obtaining a shared_ptr from a raw pointer
+ Obtaining a shared_ptr (weak_ptr) + to this in a constructor
+ Obtaining a shared_ptr to this
+ Using shared_ptr as a smart counted handle
+ Using shared_ptr to execute code on block + exit
+ Using shared_ptr<void> to hold an arbitrary + object
+ Associating arbitrary data with heterogeneous shared_ptr + instances
+ Using shared_ptr as a CopyConstructible mutex lock
+ Using shared_ptr to wrap member function calls
+ Delayed deallocation
+ Weak pointers to objects not managed by a shared_ptr
+

+

Using incomplete classes for implementation hiding

+

A proven technique (that works in C, too) for separating interface from + implementation is to use a pointer to an incomplete class as an opaque handle:

+
class FILE;
+
+FILE * fopen(char const * name, char const * mode);
+void fread(FILE * f, void * data, size_t size);
+void fclose(FILE * f);
+
+

It is possible to express the above interface using shared_ptr, + eliminating the need to manually call fclose:

+
class FILE;
+
+shared_ptr<FILE> fopen(char const * name, char const * mode);
+void fread(shared_ptr<FILE> f, void * data, size_t size);
+
+

This technique relies on shared_ptr's ability to execute a custom + deleter, eliminating the explicit call to fclose, and on the fact + that shared_ptr<X> can be copied and destroyed when X + is incomplete.

+

The "Pimpl" idiom

+

A C++ specific variation of the incomplete class pattern is the "Pimpl" idiom. + The incomplete class is not exposed to the user; it is hidden behind a + forwarding facade. shared_ptr can be used to implement a "Pimpl":

+
// file.hpp:
+
+class file
+{
+private:
+
+    class impl;
+    shared_ptr<impl> pimpl_;
+
+public:
+
+    file(char const * name, char const * mode);
+
+    // compiler generated members are fine and useful
+
+    void read(void * data, size_t size);
+};
+
+
// file.cpp:
+
+#include "file.hpp"
+
+class file::impl
+{
+private:
+
+    impl(impl const &);
+    impl & operator=(impl const &);
+
+    // private data
+
+public:
+
+    impl(char const * name, char const * mode) { ... }
+    ~impl() { ... }
+    void read(void * data, size_t size) { ... }
+};
+
+file::file(char const * name, char const * mode): pimpl_(new impl(name, mode))
+{
+}
+
+void file::read(void * data, size_t size)
+{
+    pimpl_->read(data, size);
+}
+
+

The key thing to note here is that the compiler-generated copy constructor, + assignment operator, and destructor all have a sensible meaning. As a result, + file is CopyConstructible and Assignable, + allowing its use in standard containers.

+

Using abstract classes for implementation hiding

+

Another widely used C++ idiom for separating inteface and implementation is to + use abstract base classes and factory functions. The abstract classes are + sometimes called "interfaces" and the pattern is known as "interface-based + programming". Again, shared_ptr can be used as the return type of + the factory functions:

+
// X.hpp:
+
+class X
+{
+public:
+
+    virtual void f() = 0;
+    virtual void g() = 0;
+
+protected:
+
+    ~X() {}
+};
+
+shared_ptr<X> createX();
+
+
-- X.cpp:
+
+class X_impl: public X
+{
+private:
+
+    X_impl(X_impl const &);
+    X_impl & operator=(X_impl const &);
+
+public:
+
+    virtual void f()
+    {
+      // ...
+    }
+
+    virtual void g()
+    {
+      // ...
+    }
+};
+
+shared_ptr<X> createX()
+{
+    shared_ptr<X> px(new X_impl);
+    return px;
+}
+
+

A key property of shared_ptr is that the allocation, construction, deallocation, + and destruction details are captured at the point of construction, inside the + factory function. Note the protected and nonvirtual destructor in the example + above. The client code cannot, and does not need to, delete a pointer to X; + the shared_ptr<X> instance returned from createX + will correctly call ~X_impl.

+

Preventing delete px.get()

+

It is often desirable to prevent client code from deleting a pointer that is + being managed by shared_ptr. The previous technique showed one + possible approach, using a protected destructor. Another alternative is to use + a private deleter:

+
class X
+{
+private:
+
+    ~X();
+
+    class deleter;
+    friend class deleter;
+
+    class deleter
+    {
+    public:
+
+        void operator()(X * p) { delete p; }
+    };
+
+public:
+
+    static shared_ptr<X> create()
+    {
+        shared_ptr<X> px(new X, X::deleter());
+        return px;
+    }
+};
+
+

Using a shared_ptr to hold a pointer to an array

+

A shared_ptr can be used to hold a pointer to an array allocated + with new[]:

+
shared_ptr<X> px(new X[1], checked_array_deleter<X>());
+
+

Note, however, that shared_array is + often preferable, if this is an option. It has an array-specific interface, + without operator* and operator->, and does not + allow pointer conversions.

+

Encapsulating allocation details, wrapping factory + functions

+

shared_ptr can be used in creating C++ wrappers over existing C + style library interfaces that return raw pointers from their factory functions + to encapsulate allocation details. As an example, consider this interface, + where CreateX might allocate X from its own private + heap, ~X may be inaccessible, or X may be incomplete:

+
X * CreateX();
+void DestroyX(X *);
+
+

The only way to reliably destroy a pointer returned by CreateX is + to call DestroyX.

+

Here is how a shared_ptr-based wrapper may look like:

+
shared_ptr<X> createX()
+{
+    shared_ptr<X> px(CreateX(), DestroyX);
+    return px;
+}
+
+

Client code that calls createX still does not need to know how the + object has been allocated, but now the destruction is automatic.

+

Using a shared_ptr to hold a pointer to a statically + allocated object

+

Sometimes it is desirable to create a shared_ptr to an already + existing object, so that the shared_ptr does not attempt to + destroy the object when there are no more references left. As an example, the + factory function:

+
shared_ptr<X> createX();
+
+

in certain situations may need to return a pointer to a statically allocated X + instance.

+

The solution is to use a custom deleter that does nothing:

+
struct null_deleter
+{
+    void operator()(void const *) const
+    {
+    }
+};
+
+static X x;
+
+shared_ptr<X> createX()
+{
+    shared_ptr<X> px(&x, null_deleter());
+    return px;
+}
+
+

The same technique works for any object known to outlive the pointer.

+

Using a shared_ptr to hold a pointer to a COM Object

+

Background: COM objects have an embedded reference count and two member + functions that manipulate it. AddRef() increments the count. Release() + decrements the count and destroys itself when the count drops to zero.

+

It is possible to hold a pointer to a COM object in a shared_ptr:

+
shared_ptr<IWhatever> make_shared_from_COM(IWhatever * p)
+{
+    p->AddRef();
+    shared_ptr<IWhatever> pw(p, mem_fn(&IWhatever::Release));
+    return pw;
+}
+
+

Note, however, that shared_ptr copies created from pw will + not "register" in the embedded count of the COM object; they will share the + single reference created in make_shared_from_COM. Weak pointers + created from pw will be invalidated when the last shared_ptr + is destroyed, regardless of whether the COM object itself is still alive.

+

As explained in the mem_fn documentation, + you need to #define + BOOST_MEM_FN_ENABLE_STDCALL first.

+

Using a shared_ptr to hold a pointer to an object + with an embedded reference count

+

This is a generalization of the above technique. The example assumes that the + object implements the two functions required by intrusive_ptr, + intrusive_ptr_add_ref and intrusive_ptr_release:

+
template<class T> struct intrusive_deleter
+{
+    void operator()(T * p)
+    {
+        if(p) intrusive_ptr_release(p);
+    }
+};
+
+shared_ptr<X> make_shared_from_intrusive(X * p)
+{
+    if(p) intrusive_ptr_add_ref(p);
+    shared_ptr<X> px(p, intrusive_deleter<X>());
+    return px;
+}
+
+

Using a shared_ptr to hold another shared + ownership smart pointer

+

One of the design goals of shared_ptr is to be used in library + interfaces. It is possible to encounter a situation where a library takes a shared_ptr + argument, but the object at hand is being managed by a different reference + counted or linked smart pointer.

+

It is possible to exploit shared_ptr's custom deleter feature to + wrap this existing smart pointer behind a shared_ptr facade:

+
template<class P> struct smart_pointer_deleter
+{
+private:
+
+    P p_;
+
+public:
+
+    smart_pointer_deleter(P const & p): p_(p)
+    {
+    }
+
+    void operator()(void const *)
+    {
+        p_.reset();
+    }
+    
+    P const & get() const
+    {
+        return p_;
+    }
+};
+
+shared_ptr<X> make_shared_from_another(another_ptr<X> qx)
+{
+    shared_ptr<X> px(qx.get(), smart_pointer_deleter< another_ptr<X> >(qx));
+    return px;
+}
+
+

One subtle point is that deleters are not allowed to throw exceptions, and the + above example as written assumes that p_.reset() doesn't throw. If + this is not the case, p_.reset() should be wrapped in a try {} + catch(...) {} block that ignores exceptions. In the (usually + unlikely) event when an exception is thrown and ignored, p_ will + be released when the lifetime of the deleter ends. This happens when all + references, including weak pointers, are destroyed or reset.

+

Another twist is that it is possible, given the above shared_ptr instance, + to recover the original smart pointer, using + get_deleter:

+
void extract_another_from_shared(shared_ptr<X> px)
+{
+    typedef smart_pointer_deleter< another_ptr<X> > deleter;
+
+    if(deleter const * pd = get_deleter<deleter>(px))
+    {
+        another_ptr<X> qx = pd->get();
+    }
+    else
+    {
+        // not one of ours
+    }
+}
+
+

Obtaining a shared_ptr from a raw pointer

+

Sometimes it is necessary to obtain a shared_ptr given a raw + pointer to an object that is already managed by another shared_ptr + instance. Example:

+
void f(X * p)
+{
+    shared_ptr<X> px(???);
+}
+
+

Inside f, we'd like to create a shared_ptr to *p.

+

In the general case, this problem has no solution. One approach is to modify f + to take a shared_ptr, if possible:

+
void f(shared_ptr<X> px);
+
+

The same transformation can be used for nonvirtual member functions, to convert + the implicit this:

+
void X::f(int m);
+
+

would become a free function with a shared_ptr first argument:

+
void f(shared_ptr<X> this_, int m);
+
+

If f cannot be changed, but X uses intrusive counting, + use make_shared_from_intrusive described + above. Or, if it's known that the shared_ptr created in f + will never outlive the object, use a null deleter.

+

Obtaining a shared_ptr (weak_ptr) + to this in a constructor

+

Some designs require objects to register themselves on construction with a + central authority. When the registration routines take a shared_ptr, this leads + to the question how could a constructor obtain a shared_ptr to this:

+
class X
+{
+public:
+
+    X()
+    {
+        shared_ptr<X> this_(???);
+    }
+};
+
+

In the general case, the problem cannot be solved. The X instance + being constructed can be an automatic variable or a static variable; it can be + created on the heap:

+
shared_ptr<X> px(new X);
+

but at construction time, px does not exist yet, and it is + impossible to create another shared_ptr instance that shares + ownership with it.

+

Depending on context, if the inner shared_ptr this_ doesn't + need to keep the object alive, use a null_deleter as explained + here and here. If X is + supposed to always live on the heap, and be managed by a shared_ptr, + use a static factory function:

+
class X
+{
+private:
+
+    X() { ... }
+
+public:
+
+    static shared_ptr<X> create()
+    {
+        shared_ptr<X> px(new X);
+        // use px as 'this_'
+        return px;
+    }
+};
+
+

Obtaining a shared_ptr to this

+

Sometimes it is needed to obtain a shared_ptr from this + in a virtual member function under the assumption that this is + already managed by a shared_ptr. The transformations + described in the previous technique cannot be applied.

+

A typical example:

+
class X
+{
+public:
+
+    virtual void f() = 0;
+
+protected:
+
+    ~X() {}
+};
+
+class Y
+{
+public:
+
+    virtual shared_ptr<X> getX() = 0;
+
+protected:
+
+    ~Y() {}
+};
+
+// --
+
+class impl: public X, public Y
+{
+public:
+
+    impl() { ... }
+
+    virtual void f() { ... }
+
+    virtual shared_ptr<X> getX()
+    {
+        shared_ptr<X> px(???);
+        return px;
+    }
+};
+
+

The solution is to keep a weak pointer to this as a member in impl:

+
class impl: public X, public Y
+{
+private:
+
+    weak_ptr<impl> weak_this;
+
+    impl(impl const &);
+    impl & operator=(impl const &);
+
+    impl() { ... }
+
+public:
+
+    static shared_ptr<impl> create()
+    {
+        shared_ptr<impl> pi(new impl);
+        pi->weak_this = pi;
+        return pi;
+    }
+
+    virtual void f() { ... }
+
+    virtual shared_ptr<X> getX()
+    {
+        shared_ptr<X> px(weak_this);
+        return px;
+    }
+};
+
+

The library now includes a helper class template + enable_shared_from_this that can be used to encapsulate the + solution:

+
class impl: public X, public Y, public enable_shared_from_this<impl>
+{
+public:
+
+    impl(impl const &);
+    impl & operator=(impl const &);
+
+public:
+
+    virtual void f() { ... }
+
+    virtual shared_ptr<X> getX()
+    {
+        return shared_from_this();
+    }
+}
+
+

Note that you no longer need to manually initialize the weak_ptr member + in enable_shared_from_this. + Constructing a shared_ptr to impl takes care of that.

+

Using shared_ptr as a smart counted handle

+

Some library interfaces use opaque handles, a variation of the + incomplete class technique described above. An example:

+
typedef void * HANDLE;
+HANDLE CreateProcess();
+void CloseHandle(HANDLE);
+
+

Instead of a raw pointer, it is possible to use shared_ptr as the + handle and get reference counting and automatic resource management for free:

+
typedef shared_ptr<void> handle;
+
+handle createProcess()
+{
+    shared_ptr<void> pv(CreateProcess(), CloseHandle);
+    return pv;
+}
+
+

Using shared_ptr to execute code on block exit

+

shared_ptr<void> can automatically execute cleanup code when + control leaves a scope.

+
    +
  • + Executing f(p), where p is a pointer:
+
    shared_ptr<void> guard(p, f);
+
+
    +
  • + Executing arbitrary code: f(x, y):
+
    shared_ptr<void> guard(static_cast<void*>(0), bind(f, x, y));
+
+

For a more thorough treatment, see the article "Simplify Your Exception-Safe + Code" by Andrei Alexandrescu and Petru Marginean, available online at + http://www.cuj.com/experts/1812/alexandr.htm?topic=experts.

+

Using shared_ptr<void> to hold an arbitrary + object

+

shared_ptr<void> can act as a generic object pointer similar + to void*. When a shared_ptr<void> instance + constructed as:

+
    shared_ptr<void> pv(new X);
+
+

is destroyed, it will correctly dispose of the X object by + executing ~X.

+

This propery can be used in much the same manner as a raw void* is + used to temporarily strip type information from an object pointer. A shared_ptr<void> + can later be cast back to the correct type by using + static_pointer_cast.

+

Associating arbitrary data with heterogeneous shared_ptr + instances

+

shared_ptr and weak_ptr support operator< + comparisons required by standard associative containers such as std::map. + This can be used to non-intrusively associate arbitrary data with objects + managed by shared_ptr:

+
typedef int Data;
+
+std::map< shared_ptr<void>, Data > userData;
+// or std::map< weak_ptr<void>, Data > userData; to not affect the lifetime
+
+shared_ptr<X> px(new X);
+shared_ptr<int> pi(new int(3));
+
+userData[px] = 42;
+userData[pi] = 91;
+
+

Using shared_ptr as a CopyConstructible mutex lock

+

Sometimes it's necessary to return a mutex lock from a function, and a + noncopyable lock cannot be returned by value. It is possible to use shared_ptr + as a mutex lock:

+
class mutex
+{
+public:
+
+    void lock();
+    void unlock();
+};
+
+shared_ptr<mutex> lock(mutex & m)
+{
+    m.lock();
+    return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock));
+}
+
+

Better yet, the shared_ptr instance acting as a lock can be + encapsulated in a dedicated shared_lock class:

+
class shared_lock
+{
+private:
+
+    shared_ptr<void> pv;
+
+public:
+
+    template<class Mutex> explicit shared_lock(Mutex & m): pv((m.lock(), &m), mem_fn(&Mutex::unlock)) {}
+};
+
+

shared_lock can now be used as:

+
    shared_lock lock(m);
+
+

Note that shared_lock is not templated on the mutex type, thanks to + shared_ptr<void>'s ability to hide type information.

+

Using shared_ptr to wrap member function calls

+

shared_ptr implements the ownership semantics required from the Wrap/CallProxy + scheme described in Bjarne Stroustrup's article "Wrapping C++ Member Function + Calls" (available online at http://www.research.att.com/~bs/wrapper.pdf). + An implementation is given below:

+
template<class T> class pointer
+{
+private:
+
+    T * p_;
+
+public:
+
+    explicit pointer(T * p): p_(p)
+    {
+    }
+
+    shared_ptr<T> operator->() const
+    {
+        p_->prefix();
+        return shared_ptr<T>(p_, mem_fn(&T::suffix));
+    }
+};
+
+class X
+{
+private:
+
+    void prefix();
+    void suffix();
+    friend class pointer<X>;
+    
+public:
+
+    void f();
+    void g();
+};
+
+int main()
+{
+    X x;
+
+    pointer<X> px(&x);
+
+    px->f();
+    px->g();
+}
+
+

Delayed deallocation

+

In some situations, a single px.reset() can trigger an expensive + deallocation in a performance-critical region:

+
class X; // ~X is expensive
+
+class Y
+{
+    shared_ptr<X> px;
+
+public:
+
+    void f()
+    {
+        px.reset();
+    }
+};
+
+

The solution is to postpone the potential deallocation by moving px + to a dedicated free list that can be periodically emptied when performance and + response times are not an issue:

+
vector< shared_ptr<void> > free_list;
+
+class Y
+{
+    shared_ptr<X> px;
+
+public:
+
+    void f()
+    {
+        free_list.push_back(px);
+        px.reset();
+    }
+};
+
+// periodically invoke free_list.clear() when convenient
+
+

Another variation is to move the free list logic to the construction point by + using a delayed deleter:

+
struct delayed_deleter
+{
+    template<class T> void operator()(T * p)
+    {
+        try
+        {
+            shared_ptr<void> pv(p);
+            free_list.push_back(pv);
+        }
+        catch(...)
+        {
+        }
+    }
+};
+
+

Weak pointers to objects not managed by a shared_ptr

+

Make the object hold a shared_ptr to itself, using a null_deleter:

+
class X
+{
+private:
+
+    shared_ptr<X> this_;
+    int i_;
+
+public:
+
+    explicit X(int i): this_(this, null_deleter()), i_(i)
+    {
+    }
+
+    // repeat in all constructors (including the copy constructor!)
+
+    X(X const & rhs): this_(this, null_deleter()), i_(rhs.i_)
+    {
+    }
+
+    // do not forget to not assign this_ in the copy assignment
+
+    X & operator=(X const & rhs)
+    {
+	    i_ = rhs.i_;
+    }
+
+    weak_ptr<X> get_weak_ptr() const { return this_; }
+};
+
+

When the object's lifetime ends, X::this_ will be destroyed, and + all weak pointers will automatically expire.

+
+

$Date$

+

Copyright © 2003 Peter Dimov. 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/src/sp_collector.cpp b/src/sp_collector.cpp new file mode 100644 index 0000000..bb69ae8 --- /dev/null +++ b/src/sp_collector.cpp @@ -0,0 +1,270 @@ +// +// sp_collector.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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) +// + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +#include +#include +#include +#include +#include +#include +#include + +typedef std::map< void const *, std::pair > map_type; + +static map_type & get_map() +{ + static map_type m; + return m; +} + +typedef boost::detail::lightweight_mutex mutex_type; + +static mutex_type & get_mutex() +{ + static mutex_type m; + return m; +} + +static void * init_mutex_before_main = &get_mutex(); + +namespace +{ + class X; + + struct count_layout + { + boost::detail::sp_counted_base * pi; + int id; + }; + + struct shared_ptr_layout + { + X * px; + count_layout pn; + }; +} + +// assume 4 byte alignment for pointers when scanning +size_t const pointer_align = 4; + +typedef std::map map2_type; + +static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2) +{ + unsigned char const * p = static_cast(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout const * q = reinterpret_cast(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0) + { + ++m2[q->pn.pi]; + } + } +} + +typedef std::deque open_type; + +static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open) +{ + unsigned char const * p = static_cast(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout const * q = reinterpret_cast(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0) + { + open.push_back(q->pn.pi); + m2.erase(q->pn.pi); + } + } +} + +static void find_unreachable_objects_impl(map_type const & m, map2_type & m2) +{ + // scan objects for shared_ptr members, compute internal counts + + { + std::cout << "... " << m.size() << " objects in m.\n"; + + for(map_type::const_iterator i = m.begin(); i != m.end(); ++i) + { + boost::detail::sp_counted_base const * p = static_cast(i->first); + + BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map + + m2[ i->first ]; + + scan_and_count(i->second.first, i->second.second, m, m2); + } + + std::cout << "... " << m2.size() << " objects in m2.\n"; + } + + // mark reachable objects + + { + open_type open; + + for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i) + { + boost::detail::sp_counted_base const * p = static_cast(i->first); + if(p->use_count() != i->second) open.push_back(p); + } + + std::cout << "... " << open.size() << " objects in open.\n"; + + for(open_type::iterator j = open.begin(); j != open.end(); ++j) + { + m2.erase(*j); + } + + while(!open.empty()) + { + void const * p = open.front(); + open.pop_front(); + + map_type::const_iterator i = m.find(p); + BOOST_ASSERT(i != m.end()); + + scan_and_mark(i->second.first, i->second.second, m2, open); + } + } + + // m2 now contains the unreachable objects +} + +std::size_t find_unreachable_objects(bool report) +{ + map2_type m2; + +#ifdef BOOST_HAS_THREADS + + // This will work without the #ifdef, but some compilers warn + // that lock is not referenced + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + map_type const & m = get_map(); + + find_unreachable_objects_impl(m, m2); + + if(report) + { + for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) + { + map_type::const_iterator i = m.find(j->first); + BOOST_ASSERT(i != m.end()); + std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n"; + } + } + + return m2.size(); +} + +typedef std::deque< boost::shared_ptr > free_list_type; + +static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free) +{ + unsigned char * p = static_cast(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout * q = reinterpret_cast(p); + + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0) + { + boost::shared_ptr * ppx = reinterpret_cast< boost::shared_ptr * >(p); + free.push_back(*ppx); + ppx->reset(); + } + } +} + +void free_unreachable_objects() +{ + free_list_type free; + + { + map2_type m2; + +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + map_type const & m = get_map(); + + find_unreachable_objects_impl(m, m2); + + for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) + { + map_type::const_iterator i = m.find(j->first); + BOOST_ASSERT(i != m.end()); + scan_and_free(i->second.first, i->second.second, m2, free); + } + } + + std::cout << "... about to free " << free.size() << " objects.\n"; +} + +// debug hooks + +namespace boost +{ + +void sp_scalar_constructor_hook(void *) +{ +} + +void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn) +{ +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + get_map()[pn] = std::make_pair(px, size); +} + +void sp_scalar_destructor_hook(void *) +{ +} + +void sp_scalar_destructor_hook(void *, std::size_t, void * pn) +{ +#ifdef BOOST_HAS_THREADS + + mutex_type::scoped_lock lock(get_mutex()); + +#endif + + get_map().erase(pn); +} + +void sp_array_constructor_hook(void *) +{ +} + +void sp_array_destructor_hook(void *) +{ +} + +} // namespace boost + +#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS) diff --git a/src/sp_debug_hooks.cpp b/src/sp_debug_hooks.cpp new file mode 100644 index 0000000..3193936 --- /dev/null +++ b/src/sp_debug_hooks.cpp @@ -0,0 +1,243 @@ +// +// sp_debug_hooks.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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) +// + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +#include +#include +#include + +int const m = 2; // m * sizeof(int) must be aligned appropriately + +// magic values to mark heap blocks with + +int const allocated_scalar = 0x1234560C; +int const allocated_array = 0x1234560A; +int const adopted_scalar = 0x0567890C; +int const adopted_array = 0x0567890A; +int const deleted = 0x498769DE; + +using namespace std; // for compilers where things aren't in std + +// operator new + +static new_handler get_new_handler() +{ + new_handler p = set_new_handler(0); + set_new_handler(p); + return p; +} + +static void * allocate(size_t n, int mark) +{ + int * pm; + + for(;;) + { + pm = static_cast(malloc(n + m * sizeof(int))); + + if(pm != 0) break; + + if(new_handler pnh = get_new_handler()) + { + pnh(); + } + else + { + return 0; + } + } + + *pm = mark; + + return pm + m; +} + +void * operator new(size_t n) throw(bad_alloc) +{ + void * p = allocate(n, allocated_scalar); + +#if !defined(BOOST_NO_EXCEPTIONS) + + if(p == 0) throw bad_alloc(); + +#endif + + return p; +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void * operator new(size_t n, nothrow_t const &) throw() +{ + return allocate(n, allocated_scalar); +} + +#endif + +void * operator new[](size_t n) throw(bad_alloc) +{ + void * p = allocate(n, allocated_array); + +#if !defined(BOOST_NO_EXCEPTIONS) + + if(p == 0) throw bad_alloc(); + +#endif + + return p; +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void * operator new[](size_t n, nothrow_t const &) throw() +{ + return allocate(n, allocated_array); +} + +#endif + +// debug hooks + +namespace boost +{ + +void sp_scalar_constructor_hook(void * p) +{ + if(p == 0) return; + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm != adopted_scalar); // second smart pointer to the same address + BOOST_ASSERT(*pm != allocated_array); // allocated with new[] + BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new + + *pm = adopted_scalar; +} + +void sp_scalar_constructor_hook(void * px, std::size_t, void *) +{ + sp_scalar_constructor_hook(px); +} + +void sp_scalar_destructor_hook(void * p) +{ + if(p == 0) return; + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm == adopted_scalar); // attempt to destroy nonmanaged block + + *pm = allocated_scalar; +} + +void sp_scalar_destructor_hook(void * px, std::size_t, void *) +{ + sp_scalar_destructor_hook(px); +} + +// It is not possible to handle the array hooks in a portable manner. +// The implementation typically reserves a bit of storage for the number +// of objects in the array, and the argument of the array hook isn't +// equal to the return value of operator new[]. + +void sp_array_constructor_hook(void * /* p */) +{ +/* + if(p == 0) return; + + // adjust p depending on the implementation + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm != adopted_array); // second smart array pointer to the same address + BOOST_ASSERT(*pm != allocated_scalar); // allocated with new + BOOST_ASSERT(*pm == allocated_array); // not allocated with new[] + + *pm = adopted_array; +*/ +} + +void sp_array_destructor_hook(void * /* p */) +{ +/* + if(p == 0) return; + + // adjust p depending on the implementation + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm == adopted_array); // attempt to destroy nonmanaged block + + *pm = allocated_array; +*/ +} + +} // namespace boost + +// operator delete + +void operator delete(void * p) throw() +{ + if(p == 0) return; + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm != deleted); // double delete + BOOST_ASSERT(*pm != adopted_scalar); // delete p.get(); + BOOST_ASSERT(*pm != allocated_array); // allocated with new[] + BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new + + *pm = deleted; + + free(pm); +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void operator delete(void * p, nothrow_t const &) throw() +{ + ::operator delete(p); +} + +#endif + +void operator delete[](void * p) throw() +{ + if(p == 0) return; + + int * pm = static_cast(p); + pm -= m; + + BOOST_ASSERT(*pm != deleted); // double delete + BOOST_ASSERT(*pm != adopted_scalar); // delete p.get(); + BOOST_ASSERT(*pm != allocated_scalar); // allocated with new + BOOST_ASSERT(*pm == allocated_array); // not allocated with new[] + + *pm = deleted; + + free(pm); +} + +#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + +void operator delete[](void * p, nothrow_t const &) throw() +{ + ::operator delete[](p); +} + +#endif + +#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 0000000..db4bfb1 --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,65 @@ +# Boost.SmartPtr Library test Jamfile +# +# Copyright (c) 2003-2007 Peter Dimov +# Copyright (c) 2003 Dave Abrahams +# +# 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) + +# bring in rules for testing +import testing ; + +{ + test-suite "smart_ptr" + : [ run smart_ptr_test.cpp ] + [ run shared_ptr_basic_test.cpp : : : gcc:-Wno-non-virtual-dtor ] + [ run shared_ptr_test.cpp : : : gcc:-Wno-non-virtual-dtor ] + [ run weak_ptr_test.cpp ] + [ run weak_ptr_move_test.cpp ] + [ run shared_from_this_test.cpp : : : gcc:-Wno-non-virtual-dtor ] + [ run get_deleter_test.cpp ] + [ run intrusive_ptr_test.cpp ] + [ run intrusive_ptr_move_test.cpp ] + [ run atomic_count_test.cpp ] + [ run lw_mutex_test.cpp ] + [ compile-fail shared_ptr_assign_fail.cpp ] + [ compile-fail shared_ptr_delete_fail.cpp ] + [ compile-fail shared_ptr_compare_fail.cpp ] + [ run shared_ptr_alloc2_test.cpp ] + [ run pointer_cast_test.cpp ] + [ compile pointer_to_other_test.cpp ] + [ run auto_ptr_rv_test.cpp ] + [ run shared_ptr_alias_test.cpp ] + [ run shared_ptr_rv_test.cpp ] + [ run shared_ptr_move_test.cpp ] + [ compile-fail shared_ptr_pv_fail.cpp ] + [ run sp_unary_addr_test.cpp ] + [ compile-fail scoped_ptr_eq_fail.cpp ] + [ compile-fail scoped_array_eq_fail.cpp ] + [ run esft_regtest.cpp ] + [ run yield_k_test.cpp ] + [ run yield_k_test.cpp : : : multi : yield_k_test.mt ] + [ run spinlock_test.cpp ] + [ run spinlock_try_test.cpp ] + [ run spinlock_try_test.cpp : : : multi : spinlock_try_test.mt ] + [ run spinlock_pool_test.cpp ] + [ run make_shared_test.cpp ] + [ run sp_convertible_test.cpp ] + [ run wp_convertible_test.cpp ] + [ run ip_convertible_test.cpp ] + [ run allocate_shared_test.cpp ] + [ run sp_atomic_test.cpp ] + [ run esft_void_test.cpp ] + [ run esft_second_ptr_test.cpp ] + [ run make_shared_esft_test.cpp ] + [ run allocate_shared_esft_test.cpp ] + [ run sp_recursive_assign_test.cpp ] + [ run sp_recursive_assign2_test.cpp ] + [ run sp_recursive_assign_rv_test.cpp ] + [ run sp_recursive_assign2_rv_test.cpp ] + [ run esft_constructor_test.cpp ] + [ compile-fail auto_ptr_lv_fail.cpp ] + [ run atomic_count_test2.cpp ] + ; +} diff --git a/test/allocate_shared_esft_test.cpp b/test/allocate_shared_esft_test.cpp new file mode 100644 index 0000000..2bb8ccc --- /dev/null +++ b/test/allocate_shared_esft_test.cpp @@ -0,0 +1,264 @@ +// allocate_shared_esft_test.cpp +// +// Copyright 2007-2009 Peter Dimov +// +// 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 +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator() ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/allocate_shared_test.cpp b/test/allocate_shared_test.cpp new file mode 100644 index 0000000..bdae793 --- /dev/null +++ b/test/allocate_shared_test.cpp @@ -0,0 +1,204 @@ +// allocate_shared_test.cpp +// +// Copyright 2007-2009 Peter Dimov +// +// 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 +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + explicit X( int a1 = 0, int a2 = 0, int a3 = 0, int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, int a8 = 0, int a9 = 0 ): v( a1+a2+a3+a4+a5+a6+a7+a8+a9 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::shared_ptr< int > pi = boost::allocate_shared< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::shared_ptr< int > pi = boost::allocate_shared< int >( std::allocator(), 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator() ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8+9 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} diff --git a/test/atomic_count_test.cpp b/test/atomic_count_test.cpp new file mode 100644 index 0000000..ecc24c0 --- /dev/null +++ b/test/atomic_count_test.cpp @@ -0,0 +1,40 @@ +// +// atomic_count_test.cpp +// +// Copyright 2005 Peter Dimov +// +// 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 +#include + +int main() +{ + boost::detail::atomic_count n( 4 ); + + BOOST_TEST( n == 4L ); + + ++n; + + BOOST_TEST( n == 5L ); + BOOST_TEST( --n != 0L ); + + boost::detail::atomic_count m( 0 ); + + BOOST_TEST( m == 0 ); + + ++m; + + BOOST_TEST( m == 1 ); + + ++m; + + BOOST_TEST( m == 2 ); + BOOST_TEST( --m != 0 ); + BOOST_TEST( --m == 0 ); + + return boost::report_errors(); +} diff --git a/test/atomic_count_test2.cpp b/test/atomic_count_test2.cpp new file mode 100644 index 0000000..7e6dd97 --- /dev/null +++ b/test/atomic_count_test2.cpp @@ -0,0 +1,55 @@ +// +// atomic_count_test2.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +int main() +{ + boost::detail::atomic_count n( 4 ); + + BOOST_TEST( n == 4 ); + + BOOST_TEST( ++n == 5 ); + BOOST_TEST( ++n == 6 ); + + BOOST_TEST( n == 6 ); + + BOOST_TEST( --n == 5 ); + BOOST_TEST( --n == 4 ); + + BOOST_TEST( n == 4 ); + + boost::detail::atomic_count m( 0 ); + + BOOST_TEST( m == 0 ); + + BOOST_TEST( ++m == 1 ); + BOOST_TEST( ++m == 2 ); + + BOOST_TEST( m == 2 ); + + BOOST_TEST( --m == 1 ); + BOOST_TEST( --m == 0 ); + + BOOST_TEST( m == 0 ); + + BOOST_TEST( --m == -1 ); + BOOST_TEST( --m == -2 ); + + BOOST_TEST( m == -2 ); + + BOOST_TEST( ++m == -1 ); + BOOST_TEST( ++m == 0 ); + + BOOST_TEST( m == 0 ); + + return boost::report_errors(); +} diff --git a/test/auto_ptr_lv_fail.cpp b/test/auto_ptr_lv_fail.cpp new file mode 100644 index 0000000..b86832e --- /dev/null +++ b/test/auto_ptr_lv_fail.cpp @@ -0,0 +1,32 @@ +#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 +#endif + +// +// auto_ptr_lv_fail.cpp - a negative test for converting an auto_ptr to shared_ptr +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +void f( boost::shared_ptr ) +{ +} + +int main() +{ + std::auto_ptr p; + f( p ); // must fail + return 0; +} diff --git a/test/auto_ptr_rv_test.cpp b/test/auto_ptr_rv_test.cpp new file mode 100644 index 0000000..d13b6ab --- /dev/null +++ b/test/auto_ptr_rv_test.cpp @@ -0,0 +1,111 @@ +// +// auto_ptr_rv_test.cpp +// +// Copyright (c) 2006 Peter Dimov +// +// 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 +#include +#include + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + + static std::auto_ptr create() + { + return std::auto_ptr( new X ); + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +long X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/collector_test.cpp b/test/collector_test.cpp new file mode 100644 index 0000000..062b557 --- /dev/null +++ b/test/collector_test.cpp @@ -0,0 +1,99 @@ +// +// collector_test.cpp +// +// Copyright (c) 2003 Peter Dimov +// +// 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 +#include +#include +#include +#include + +// sp_collector.cpp exported functions + +std::size_t find_unreachable_objects(bool report); +void free_unreachable_objects(); + +struct X +{ + void* fill[32]; + boost::shared_ptr p; +}; + +void report() +{ + std::cout << "Calling find_unreachable_objects:\n"; + + std::clock_t t = std::clock(); + + std::size_t n = find_unreachable_objects(false); + + t = std::clock() - t; + + std::cout << n << " unreachable objects.\n"; + std::cout << " " << static_cast(t) / CLOCKS_PER_SEC << " seconds.\n"; +} + +void free() +{ + std::cout << "Calling free_unreachable_objects:\n"; + + std::clock_t t = std::clock(); + + free_unreachable_objects(); + + t = std::clock() - t; + + std::cout << " " << static_cast(t) / CLOCKS_PER_SEC << " seconds.\n"; +} + +int main() +{ + std::vector< boost::shared_ptr > v1, v2; + + int const n = 256 * 1024; + + std::cout << "Filling v1 and v2\n"; + + for(int i = 0; i < n; ++i) + { + v1.push_back(boost::shared_ptr(new X)); + v2.push_back(boost::shared_ptr(new X)); + } + + report(); + + std::cout << "Creating the cycles\n"; + + for(int i = 0; i < n - 1; ++i) + { + v2[i]->p = v2[i+1]; + } + + v2[n-1]->p = v2[0]; + + report(); + + std::cout << "Resizing v2 to size of 1\n"; + + v2.resize(1); + report(); + + std::cout << "Clearing v2\n"; + + v2.clear(); + report(); + + std::cout << "Clearing v1\n"; + + v1.clear(); + report(); + + free(); + report(); +} diff --git a/test/esft_constructor_test.cpp b/test/esft_constructor_test.cpp new file mode 100644 index 0000000..ced24e2 --- /dev/null +++ b/test/esft_constructor_test.cpp @@ -0,0 +1,169 @@ +// +// esft_constructor_test.cpp +// +// A test for the new enable_shared_from_this support for calling +// shared_from_this from constructors (that is, prior to the +// object's ownership being passed to an external shared_ptr). +// +// Copyright (c) 2008 Frank Mori Hess +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this2< X > +{ +private: + + int destroyed_; + int deleted_; + int expected_; + +private: + + X( X const& ); + X& operator=( X const& ); + +public: + + static int instances; + +public: + + explicit X( int expected, boost::shared_ptr *early_px = 0 ): destroyed_( 0 ), deleted_( 0 ), expected_( expected ) + { + ++instances; + if( early_px ) *early_px = shared_from_this(); + } + + ~X() + { + BOOST_TEST( deleted_ == expected_ ); + BOOST_TEST( destroyed_ == 0 ); + ++destroyed_; + --instances; + } + + typedef void (*deleter_type)( X* ); + + static void deleter( X * px ) + { + ++px->deleted_; + } + + static void deleter2( X * px ) + { + ++px->deleted_; + delete px; + } +}; + +int X::instances = 0; + +template +bool are_shared_owners(const boost::shared_ptr &a, const boost::shared_ptr &b) +{ + return !(a < b) && !(b < a); +} + +struct Y: public boost::enable_shared_from_this2 +{}; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr early_px; + X* x = new X( 1, &early_px ); + BOOST_TEST( early_px.use_count() > 0 ); + BOOST_TEST( boost::get_deleter(early_px) == 0 ); + boost::shared_ptr px( x, &X::deleter2 ); + BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 ); + BOOST_TEST(are_shared_owners(early_px, px)); + px.reset(); + BOOST_TEST( early_px.use_count() == 1 ); + BOOST_TEST( X::instances == 1 ); + // X::deleter_type *pd = boost::get_deleter(early_px); + // BOOST_TEST(pd && *pd == &X::deleter2 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr early_px; + X* x = new X( 1, &early_px ); + boost::weak_ptr early_weak_px = early_px; + early_px.reset(); + BOOST_TEST( !early_weak_px.expired() ); + boost::shared_ptr px( x, &X::deleter2 ); + BOOST_TEST( px.use_count() == 1 ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST(are_shared_owners(early_weak_px.lock(), px)); + px.reset(); + BOOST_TEST( early_weak_px.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr early_px; + X x( 1, &early_px ); + BOOST_TEST( early_px.use_count() > 0 ); + boost::shared_ptr px( &x, &X::deleter ); + BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 ); + early_px.reset(); + BOOST_TEST( px.use_count() == 1 ); + BOOST_TEST( X::instances == 1 ); + px.reset(); + try + { + x.shared_from_this(); + BOOST_ERROR("x did not throw bad_weak_ptr"); + } + catch( const boost::bad_weak_ptr & ) + {} + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::weak_ptr early_weak_px; + { + boost::shared_ptr early_px; + X x( 0, &early_px ); + early_weak_px = early_px; + early_px.reset(); + BOOST_TEST( !early_weak_px.expired() ); + BOOST_TEST( X::instances == 1 ); + } + BOOST_TEST( early_weak_px.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px(new Y()); + Y y(*px); + px.reset(); + try + { + y.shared_from_this(); + } + catch( const boost::bad_weak_ptr & ) + { + BOOST_ERROR("y threw bad_weak_ptr"); + } + } + + return boost::report_errors(); +} diff --git a/test/esft_regtest.cpp b/test/esft_regtest.cpp new file mode 100644 index 0000000..cc180a2 --- /dev/null +++ b/test/esft_regtest.cpp @@ -0,0 +1,221 @@ +// +// esft_regtest.cpp +// +// A regression test for enable_shared_from_this +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this< X > +{ +private: + + int destroyed_; + int deleted_; + int expected_; + +private: + + X( X const& ); + X& operator=( X const& ); + +public: + + static int instances; + +public: + + explicit X( int expected ): destroyed_( 0 ), deleted_( 0 ), expected_( expected ) + { + ++instances; + } + + ~X() + { + BOOST_TEST( deleted_ == expected_ ); + BOOST_TEST( destroyed_ == 0 ); + ++destroyed_; + --instances; + } + + typedef void (*deleter_type)( X* ); + + static void deleter( X * px ) + { + ++px->deleted_; + } + + static void deleter2( X * px ) + { + ++px->deleted_; + delete px; + } +}; + +int X::instances = 0; + +void test() +{ + BOOST_TEST( X::instances == 0 ); + + { + X x( 0 ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + std::auto_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + X x( 1 ); + boost::shared_ptr px( &x, X::deleter ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 1 ), X::deleter2 ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter2 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); +} + +struct V: public boost::enable_shared_from_this +{ + virtual ~V() {} + std::string m_; +}; + +struct V2 +{ + virtual ~V2() {} + std::string m2_; +}; + +struct W: V2, V +{ +}; + +void test2() +{ + boost::shared_ptr p( new W ); +} + +void test3() +{ + V * p = new W; + boost::shared_ptr pv( p ); + BOOST_TEST( pv.get() == p ); + BOOST_TEST( pv.use_count() == 1 ); +} + +struct null_deleter +{ + void operator()( void const* ) const {} +}; + +void test4() +{ + boost::shared_ptr pv( new V ); + boost::shared_ptr pv2( pv.get(), null_deleter() ); + BOOST_TEST( pv2.get() == pv.get() ); + BOOST_TEST( pv2.use_count() == 1 ); +} + +void test5() +{ + V v; + + boost::shared_ptr p1( &v, null_deleter() ); + BOOST_TEST( p1.get() == &v ); + BOOST_TEST( p1.use_count() == 1 ); + + try + { + p1->shared_from_this(); + } + catch( ... ) + { + BOOST_ERROR( "p1->shared_from_this() failed" ); + } + + p1.reset(); + + boost::shared_ptr p2( &v, null_deleter() ); + BOOST_TEST( p2.get() == &v ); + BOOST_TEST( p2.use_count() == 1 ); + + try + { + p2->shared_from_this(); + } + catch( ... ) + { + BOOST_ERROR( "p2->shared_from_this() failed" ); + } +} + +int main() +{ + test(); + test2(); + test3(); + test4(); + test5(); + + return boost::report_errors(); +} diff --git a/test/esft_second_ptr_test.cpp b/test/esft_second_ptr_test.cpp new file mode 100644 index 0000000..0600667 --- /dev/null +++ b/test/esft_second_ptr_test.cpp @@ -0,0 +1,51 @@ +// +// esft_second_ptr_test.cpp +// +// This test has been extracted from a real +// scenario that occurs in Boost.Python +// +// Copyright 2009 Peter Dimov +// +// 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 +#include +#include + +// + +class X: public boost::enable_shared_from_this +{ +}; + +void null_deleter( void const* ) +{ +} + +int main() +{ + boost::shared_ptr px( new X ); + + { + boost::shared_ptr px2( px.get(), null_deleter ); + BOOST_TEST( px == px2 ); + } + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + + return boost::report_errors(); +} diff --git a/test/esft_void_test.cpp b/test/esft_void_test.cpp new file mode 100644 index 0000000..b28c669 --- /dev/null +++ b/test/esft_void_test.cpp @@ -0,0 +1,41 @@ +// +// esft_void_test.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include +#include + +// + +class X: public boost::enable_shared_from_this +{ +}; + +int main() +{ + boost::shared_ptr< void const volatile > pv( new X ); + boost::shared_ptr< void > pv2 = boost::const_pointer_cast< void >( pv ); + boost::shared_ptr< X > px = boost::static_pointer_cast< X >( pv2 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + + return boost::report_errors(); +} diff --git a/test/get_deleter_test.cpp b/test/get_deleter_test.cpp new file mode 100644 index 0000000..8bed379 --- /dev/null +++ b/test/get_deleter_test.cpp @@ -0,0 +1,95 @@ +// +// get_deleter_test.cpp +// +// Copyright (c) 2002 Peter Dimov +// +// 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 +#include + +struct deleter +{ + int data; + + deleter(): data(0) + { + } + + void operator()(void *) + { + BOOST_TEST(data == 17041); + } +}; + +struct deleter2 +{ +}; + +struct X +{ +}; + +int main() +{ + { + boost::shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::shared_ptr p(new X); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + X x; + boost::shared_ptr p(&x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + return boost::report_errors(); +} diff --git a/test/intrusive_ptr_move_test.cpp b/test/intrusive_ptr_move_test.cpp new file mode 100644 index 0000000..b5f0e65 --- /dev/null +++ b/test/intrusive_ptr_move_test.cpp @@ -0,0 +1,184 @@ +#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 + +// +// intrusive_ptr_move_test.cpp +// +// Copyright (c) 2002-2005 Peter Dimov +// +// 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 +#include +#include +#include +#include +#include + +#if defined( BOOST_HAS_RVALUE_REFS ) + +namespace N +{ + +class base +{ +private: + + boost::detail::atomic_count use_count_; + + base(base const &); + base & operator=(base const &); + +protected: + + base(): use_count_(0) + { + ++instances; + } + + virtual ~base() + { + --instances; + } + +public: + + static long instances; + + long use_count() const + { + return use_count_; + } + +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + + inline friend void intrusive_ptr_add_ref(base * p) + { + ++p->use_count_; + } + + inline friend void intrusive_ptr_release(base * p) + { + if(--p->use_count_ == 0) delete p; + } + +#else + + void add_ref() + { + ++use_count_; + } + + void release() + { + if(--use_count_ == 0) delete this; + } + +#endif +}; + +long base::instances = 0; + +} // namespace N + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + +namespace boost +{ + +inline void intrusive_ptr_add_ref(N::base * p) +{ + p->add_ref(); +} + +inline void intrusive_ptr_release(N::base * p) +{ + p->release(); +} + +} // namespace boost + +#endif + +// + +struct X: public virtual N::base +{ +}; + +struct Y: public X +{ +}; + +int main() +{ + BOOST_TEST( N::base::instances == 0 ); + + { + boost::intrusive_ptr p( new X ); + BOOST_TEST( N::base::instances == 1 ); + + boost::intrusive_ptr p2( std::move( p ) ); + BOOST_TEST( N::base::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( N::base::instances == 0 ); + } + + { + boost::intrusive_ptr p( new X ); + BOOST_TEST( N::base::instances == 1 ); + + boost::intrusive_ptr p2; + p2 = std::move( p ); + BOOST_TEST( N::base::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( N::base::instances == 0 ); + } + + { + boost::intrusive_ptr p( new X ); + BOOST_TEST( N::base::instances == 1 ); + + boost::intrusive_ptr p2( new X ); + BOOST_TEST( N::base::instances == 2 ); + p2 = std::move( p ); + BOOST_TEST( N::base::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( N::base::instances == 0 ); + } + + return boost::report_errors(); +} + +#else // !defined( BOOST_HAS_RVALUE_REFS ) + +int main() +{ + return 0; +} + +#endif diff --git a/test/intrusive_ptr_test.cpp b/test/intrusive_ptr_test.cpp new file mode 100644 index 0000000..614a9cb --- /dev/null +++ b/test/intrusive_ptr_test.cpp @@ -0,0 +1,561 @@ +#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 + +// +// intrusive_ptr_test.cpp +// +// Copyright (c) 2002-2005 Peter Dimov +// +// 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 +#include +#include +#include +#include +#include + +// + +namespace N +{ + +class base +{ +private: + + boost::detail::atomic_count use_count_; + + base(base const &); + base & operator=(base const &); + +protected: + + base(): use_count_(0) + { + } + + virtual ~base() + { + } + +public: + + long use_count() const + { + return use_count_; + } + +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + + inline friend void intrusive_ptr_add_ref(base * p) + { + ++p->use_count_; + } + + inline friend void intrusive_ptr_release(base * p) + { + if(--p->use_count_ == 0) delete p; + } + +#else + + void add_ref() + { + ++use_count_; + } + + void release() + { + if(--use_count_ == 0) delete this; + } + +#endif +}; + +} // namespace N + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + +namespace boost +{ + +inline void intrusive_ptr_add_ref(N::base * p) +{ + p->add_ref(); +} + +inline void intrusive_ptr_release(N::base * p) +{ + p->release(); +} + +} // namespace boost + +#endif + +// + +struct X: public virtual N::base +{ +}; + +struct Y: public X +{ +}; + +// + +namespace n_element_type +{ + +void f(X &) +{ +} + +void test() +{ + typedef boost::intrusive_ptr::element_type T; + T t; + f(t); +} + +} // namespace n_element_type + +namespace n_constructors +{ + +void default_constructor() +{ + boost::intrusive_ptr px; + BOOST_TEST(px.get() == 0); +} + +void pointer_constructor() +{ + { + boost::intrusive_ptr px(0); + BOOST_TEST(px.get() == 0); + } + + { + boost::intrusive_ptr px(0, false); + BOOST_TEST(px.get() == 0); + } + + { + X * p = new X; + BOOST_TEST(p->use_count() == 0); + + boost::intrusive_ptr px(p); + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 1); + } + + { + X * p = new X; + BOOST_TEST(p->use_count() == 0); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::intrusive_ptr_add_ref; +#endif + intrusive_ptr_add_ref(p); + BOOST_TEST(p->use_count() == 1); + + boost::intrusive_ptr px(p, false); + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 1); + } +} + +void copy_constructor() +{ + { + boost::intrusive_ptr px; + boost::intrusive_ptr px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::intrusive_ptr py; + boost::intrusive_ptr px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::intrusive_ptr px(0); + boost::intrusive_ptr px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::intrusive_ptr py(0); + boost::intrusive_ptr px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::intrusive_ptr px(0, false); + boost::intrusive_ptr px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::intrusive_ptr py(0, false); + boost::intrusive_ptr px(py); + BOOST_TEST(px.get() == py.get()); + } + + { + boost::intrusive_ptr px(new X); + boost::intrusive_ptr px2(px); + BOOST_TEST(px2.get() == px.get()); + } + + { + boost::intrusive_ptr py(new Y); + boost::intrusive_ptr px(py); + BOOST_TEST(px.get() == py.get()); + } +} + +void test() +{ + default_constructor(); + pointer_constructor(); + copy_constructor(); +} + +} // namespace n_constructors + +namespace n_destructor +{ + +void test() +{ + boost::intrusive_ptr px(new X); + BOOST_TEST(px->use_count() == 1); + + { + boost::intrusive_ptr px2(px); + BOOST_TEST(px->use_count() == 2); + } + + BOOST_TEST(px->use_count() == 1); +} + +} // namespace n_destructor + +namespace n_assignment +{ + +void copy_assignment() +{ +} + +void conversion_assignment() +{ +} + +void pointer_assignment() +{ +} + +void test() +{ + copy_assignment(); + conversion_assignment(); + pointer_assignment(); +} + +} // namespace n_assignment + +namespace n_access +{ + +void test() +{ + { + boost::intrusive_ptr px; + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + boost::intrusive_ptr px(0); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + boost::intrusive_ptr px(new X); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(&*px == px.get()); + BOOST_TEST(px.operator ->() == px.get()); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } +} + +} // namespace n_access + +namespace n_swap +{ + +void test() +{ + { + boost::intrusive_ptr px; + boost::intrusive_ptr px2; + + px.swap(px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + } + + { + X * p = new X; + boost::intrusive_ptr px; + boost::intrusive_ptr px2(p); + boost::intrusive_ptr px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p); + BOOST_TEST(px->use_count() == 2); + BOOST_TEST(px2.get() == 0); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3->use_count() == 2); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == p); + BOOST_TEST(px2->use_count() == 2); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3->use_count() == 2); + } + + { + X * p1 = new X; + X * p2 = new X; + boost::intrusive_ptr px(p1); + boost::intrusive_ptr px2(p2); + boost::intrusive_ptr px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p2); + BOOST_TEST(px->use_count() == 2); + BOOST_TEST(px2.get() == p1); + BOOST_TEST(px2->use_count() == 1); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3->use_count() == 2); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == p1); + BOOST_TEST(px->use_count() == 1); + BOOST_TEST(px2.get() == p2); + BOOST_TEST(px2->use_count() == 2); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3->use_count() == 2); + } +} + +} // namespace n_swap + +namespace n_comparison +{ + +template void test2(boost::intrusive_ptr const & p, boost::intrusive_ptr const & q) +{ + BOOST_TEST((p == q) == (p.get() == q.get())); + BOOST_TEST((p != q) == (p.get() != q.get())); +} + +template void test3(boost::intrusive_ptr const & p, boost::intrusive_ptr const & q) +{ + BOOST_TEST((p == q) == (p.get() == q.get())); + BOOST_TEST((p.get() == q) == (p.get() == q.get())); + BOOST_TEST((p == q.get()) == (p.get() == q.get())); + BOOST_TEST((p != q) == (p.get() != q.get())); + BOOST_TEST((p.get() != q) == (p.get() != q.get())); + BOOST_TEST((p != q.get()) == (p.get() != q.get())); + + // 'less' moved here as a g++ 2.9x parse error workaround + std::less less; + BOOST_TEST((p < q) == less(p.get(), q.get())); +} + +void test() +{ + { + boost::intrusive_ptr px; + test3(px, px); + + boost::intrusive_ptr px2; + test3(px, px2); + + boost::intrusive_ptr px3(px); + test3(px3, px3); + test3(px, px3); + } + + { + boost::intrusive_ptr px; + + boost::intrusive_ptr px2(new X); + test3(px, px2); + test3(px2, px2); + + boost::intrusive_ptr px3(new X); + test3(px2, px3); + + boost::intrusive_ptr px4(px2); + test3(px2, px4); + test3(px4, px4); + } + + { + boost::intrusive_ptr px(new X); + + boost::intrusive_ptr py(new Y); + test2(px, py); + + boost::intrusive_ptr px2(py); + test2(px2, py); + test3(px, px2); + test3(px2, px2); + } +} + +} // namespace n_comparison + +namespace n_static_cast +{ + +void test() +{ +} + +} // namespace n_static_cast + +namespace n_dynamic_cast +{ + +void test() +{ +} + +} // namespace n_dynamic_cast + +namespace n_transitive +{ + +struct X: public N::base +{ + boost::intrusive_ptr next; +}; + +void test() +{ + boost::intrusive_ptr p(new X); + p->next = boost::intrusive_ptr(new X); + BOOST_TEST(!p->next->next); + p = p->next; + BOOST_TEST(!p->next); +} + +} // namespace n_transitive + +namespace n_report_1 +{ + +class foo: public N::base +{ +public: + + foo(): m_self(this) + { + } + + void suicide() + { + m_self = 0; + } + +private: + + boost::intrusive_ptr m_self; +}; + +void test() +{ + foo * foo_ptr = new foo; + foo_ptr->suicide(); +} + +} // namespace n_report_1 + +int main() +{ + n_element_type::test(); + n_constructors::test(); + n_destructor::test(); + n_assignment::test(); + n_access::test(); + n_swap::test(); + n_comparison::test(); + n_static_cast::test(); + n_dynamic_cast::test(); + + n_transitive::test(); + n_report_1::test(); + + return boost::report_errors(); +} diff --git a/test/ip_convertible_test.cpp b/test/ip_convertible_test.cpp new file mode 100644 index 0000000..081f7b0 --- /dev/null +++ b/test/ip_convertible_test.cpp @@ -0,0 +1,54 @@ +#include + +// wp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +// + +struct W +{ +}; + +void intrusive_ptr_add_ref( W* ) +{ +} + +void intrusive_ptr_release( W* ) +{ +} + +struct X: public virtual W +{ +}; + +struct Y: public virtual W +{ +}; + +struct Z: public X +{ +}; + +int f( boost::intrusive_ptr ) +{ + return 1; +} + +int f( boost::intrusive_ptr ) +{ + return 2; +} + +int main() +{ + BOOST_TEST( 1 == f( boost::intrusive_ptr() ) ); + return boost::report_errors(); +} diff --git a/test/lw_mutex_test.cpp b/test/lw_mutex_test.cpp new file mode 100644 index 0000000..a47ac1e --- /dev/null +++ b/test/lw_mutex_test.cpp @@ -0,0 +1,28 @@ +// +// lw_mutex_test.cpp +// +// Copyright 2005 Peter Dimov +// +// 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 + +// Sanity check only + +boost::detail::lightweight_mutex m1; + +int main() +{ + boost::detail::lightweight_mutex::scoped_lock lock1( m1 ); + + boost::detail::lightweight_mutex m2; + boost::detail::lightweight_mutex m3; + + boost::detail::lightweight_mutex::scoped_lock lock2( m2 ); + boost::detail::lightweight_mutex::scoped_lock lock3( m3 ); + + return 0; +} diff --git a/test/make_shared_esft_test.cpp b/test/make_shared_esft_test.cpp new file mode 100644 index 0000000..1956cba --- /dev/null +++ b/test/make_shared_esft_test.cpp @@ -0,0 +1,263 @@ +// make_shared_esft_test.cpp +// +// Copyright 2007-2009 Peter Dimov +// +// 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 +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/make_shared_test.cpp b/test/make_shared_test.cpp new file mode 100644 index 0000000..9ebc3fa --- /dev/null +++ b/test/make_shared_test.cpp @@ -0,0 +1,204 @@ +// make_shared_test.cpp +// +// Copyright 2007-2009 Peter Dimov +// +// 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 +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + explicit X( int a1 = 0, int a2 = 0, int a3 = 0, int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, int a8 = 0, int a9 = 0 ): v( a1+a2+a3+a4+a5+a6+a7+a8+a9 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::shared_ptr< int > pi = boost::make_shared< int >(); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::shared_ptr< int > pi = boost::make_shared< int >( 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > pi = boost::make_shared< X >(); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4, 5 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4, 5, 6 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8+9 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} diff --git a/test/pointer_cast_test.cpp b/test/pointer_cast_test.cpp new file mode 100644 index 0000000..6e4620c --- /dev/null +++ b/test/pointer_cast_test.cpp @@ -0,0 +1,126 @@ +// +// pointer_cast_test.cpp - a test for boost/pointer_cast.hpp +// +// Copyright (c) 2005 Ion Gaztanaga +// Copyright (c) 2005 Peter Dimov +// +// 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 + +#include +#include +#include + +#include + +namespace +{ + +// Let's create these inheritance relationship: +// +// base base2 +// | | +// derived +// | +// derived_derived +// + +class base +{ + public: + virtual ~base(){} + int filler [5]; +}; + +class base2 +{ +public: + + virtual ~base2(){} + int filler [5]; +}; + +class derived + : public base, public base2 +{ + int filler [5]; +}; + +class derived_derived + : public derived +{ + int filler [5]; +}; + +// And now some simple check functions + +template +bool check_dynamic_pointer_cast(const BasePtr &ptr) +{ + //Check that dynamic_pointer_cast versus dynamic_cast + return + //Correct cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Correct cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)) + && + //Incorrect cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Incorrect cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)); +} + +template +bool check_static_pointer_cast(const BasePtr &ptr) +{ + return + //Cast base -> derived -> base2 using static_pointer_cast + boost::get_pointer( + boost::static_pointer_cast( + boost::static_pointer_cast(ptr))) == + //Now the same with static_cast + static_cast(static_cast(boost::get_pointer(ptr))); +} + +template +bool check_const_pointer_cast(const BasePtr &ptr) +{ + return + //Unconst and const again using const_pointer_cast + boost::get_pointer( + boost::const_pointer_cast + (boost::const_pointer_cast(ptr))) == + //Now the same with const_cast + const_cast(const_cast(boost::get_pointer(ptr))); +} + +} + +int main() +{ + { + // Try casts with shared_ptr + + boost::shared_ptr ptr(new derived); + + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); + } + + { + // Try casts with raw pointer + + boost::scoped_ptr ptr(new derived); + + BOOST_TEST( check_dynamic_pointer_cast( ptr.get() ) ); + BOOST_TEST( check_static_pointer_cast( ptr.get() ) ); + BOOST_TEST( check_const_pointer_cast( ptr.get() ) ); + } + + return boost::report_errors(); +} diff --git a/test/pointer_to_other_test.cpp b/test/pointer_to_other_test.cpp new file mode 100644 index 0000000..c2ee187 --- /dev/null +++ b/test/pointer_to_other_test.cpp @@ -0,0 +1,74 @@ +// +// pointer_to_other_test.cpp - a test for boost/pointer_to_other.hpp +// +// Copyright (c) 2005 Peter Dimov +// +// 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 + +#include +#include +#include +#include +#include + +#include + +template void assert_same_type( T** pt = 0, U** pu = 0 ) +{ + pt = pu; +} + +struct X; +struct Y; + +int main() +{ + // shared_ptr + + assert_same_type< boost::pointer_to_other< boost::shared_ptr, Y >::type, boost::shared_ptr >(); + assert_same_type< boost::pointer_to_other< boost::shared_ptr, void >::type, boost::shared_ptr >(); + assert_same_type< boost::pointer_to_other< boost::shared_ptr, Y >::type, boost::shared_ptr >(); + + // shared_array + + assert_same_type< boost::pointer_to_other< boost::shared_array, Y >::type, boost::shared_array >(); + assert_same_type< boost::pointer_to_other< boost::shared_array, void >::type, boost::shared_array >(); + assert_same_type< boost::pointer_to_other< boost::shared_array, Y >::type, boost::shared_array >(); + + // scoped_ptr + + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, Y >::type, boost::scoped_ptr >(); + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, void >::type, boost::scoped_ptr >(); + assert_same_type< boost::pointer_to_other< boost::scoped_ptr, Y >::type, boost::scoped_ptr >(); + + // scoped_array + + assert_same_type< boost::pointer_to_other< boost::scoped_array, Y >::type, boost::scoped_array >(); + assert_same_type< boost::pointer_to_other< boost::scoped_array, void >::type, boost::scoped_array >(); + assert_same_type< boost::pointer_to_other< boost::scoped_array, Y >::type, boost::scoped_array >(); + + // intrusive_ptr + + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, Y >::type, boost::intrusive_ptr >(); + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, void >::type, boost::intrusive_ptr >(); + assert_same_type< boost::pointer_to_other< boost::intrusive_ptr, Y >::type, boost::intrusive_ptr >(); + + // auto_ptr + + assert_same_type< boost::pointer_to_other< std::auto_ptr, Y >::type, std::auto_ptr >(); + assert_same_type< boost::pointer_to_other< std::auto_ptr, void >::type, std::auto_ptr >(); + assert_same_type< boost::pointer_to_other< std::auto_ptr, Y >::type, std::auto_ptr >(); + + // raw pointer + + assert_same_type< boost::pointer_to_other< X *, Y >::type, Y * >(); + assert_same_type< boost::pointer_to_other< X *, void >::type, void * >(); + assert_same_type< boost::pointer_to_other< void *, Y >::type, Y * >(); + + return 0; +} diff --git a/test/scoped_array_eq_fail.cpp b/test/scoped_array_eq_fail.cpp new file mode 100644 index 0000000..6c7f214 --- /dev/null +++ b/test/scoped_array_eq_fail.cpp @@ -0,0 +1,27 @@ +#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 +#endif + +// +// scoped_array_eq_fail.cpp - a negative test for "p == q" +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +int main() +{ + boost::scoped_array p, q; + p == q; // must fail + return 0; +} diff --git a/test/scoped_ptr_eq_fail.cpp b/test/scoped_ptr_eq_fail.cpp new file mode 100644 index 0000000..0d6ade4 --- /dev/null +++ b/test/scoped_ptr_eq_fail.cpp @@ -0,0 +1,27 @@ +#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 +#endif + +// +// scoped_ptr_eq_fail.cpp - a negative test for "p == q" +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +int main() +{ + boost::scoped_ptr p, q; + p == q; // must fail + return 0; +} diff --git a/test/shared_from_this_test.cpp b/test/shared_from_this_test.cpp new file mode 100644 index 0000000..68d6098 --- /dev/null +++ b/test/shared_from_this_test.cpp @@ -0,0 +1,167 @@ +#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 +#endif + +// +// shared_from_this_test.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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 +#include + +#include + +// + +class X +{ +public: + + virtual void f() = 0; + +protected: + + ~X() {} +}; + +class Y +{ +public: + + virtual boost::shared_ptr getX() = 0; + +protected: + + ~Y() {} +}; + +boost::shared_ptr createY(); + +void test() +{ + boost::shared_ptr py = createY(); + BOOST_TEST(py.get() != 0); + BOOST_TEST(py.use_count() == 1); + + try + { + boost::shared_ptr px = py->getX(); + BOOST_TEST(px.get() != 0); + BOOST_TEST(py.use_count() == 2); + + px->f(); + + boost::shared_ptr py2 = boost::dynamic_pointer_cast(px); + BOOST_TEST(py.get() == py2.get()); + BOOST_TEST(!(py < py2 || py2 < py)); + BOOST_TEST(py.use_count() == 3); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "py->getX() failed" ); + } +} + +void test2(); +void test3(); + +int main() +{ + test(); + test2(); + test3(); + return boost::report_errors(); +} + +// virtual inheritance to stress the implementation +// (prevents Y* -> impl*, enable_shared_from_this* -> impl* casts) + +class impl: public X, public virtual Y, public virtual boost::enable_shared_from_this +{ +public: + + virtual void f() + { + } + + virtual boost::shared_ptr getX() + { + boost::shared_ptr pi = shared_from_this(); + BOOST_TEST(pi.get() == this); + return pi; + } +}; + +// intermediate impl2 to stress the implementation + +class impl2: public impl +{ +}; + +boost::shared_ptr createY() +{ + boost::shared_ptr pi(new impl2); + return pi; +} + +void test2() +{ + boost::shared_ptr pi(static_cast(0)); +} + +// + +struct V: public boost::enable_shared_from_this +{ +}; + +void test3() +{ + boost::shared_ptr p(new V); + + try + { + boost::shared_ptr q = p->shared_from_this(); + BOOST_TEST(p == q); + BOOST_TEST(!(p < q) && !(q < p)); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR( "p->shared_from_this() failed" ); + } + + V v2(*p); + + try + { + boost::shared_ptr r = v2.shared_from_this(); + BOOST_ERROR("v2.shared_from_this() failed to throw"); + } + catch( boost::bad_weak_ptr const & ) + { + } + + try + { + *p = V(); + boost::shared_ptr r = p->shared_from_this(); + BOOST_TEST(p == r); + BOOST_TEST(!(p < r) && !(r < p)); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR("p->shared_from_this() threw bad_weak_ptr after *p = V()"); + } +} diff --git a/test/shared_ptr_alias_test.cpp b/test/shared_ptr_alias_test.cpp new file mode 100644 index 0000000..83d866f --- /dev/null +++ b/test/shared_ptr_alias_test.cpp @@ -0,0 +1,146 @@ +#include + +// shared_ptr_alias_test.cpp +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include +#include +#include + +// + +class incomplete; + +struct X +{ + int v_; + + explicit X( int v ): v_( v ) + { + } + + ~X() + { + v_ = 0; + } +}; + +int main() +{ + { + int m = 0; + boost::shared_ptr< int > p; + boost::shared_ptr< int > p2( p, &m ); + + BOOST_TEST( p2.get() == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p2.reset( p, 0 ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + + { + int m = 0; + boost::shared_ptr< int > p( new int ); + boost::shared_ptr< int const > p2( p, &m ); + + BOOST_TEST( p2.get() == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + boost::shared_ptr< int volatile > p3; + p2.reset( p3, 0 ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p3.use_count() ); + BOOST_TEST( !( p3 < p2 ) && !( p2 < p3 ) ); + } + + { + boost::shared_ptr< int > p( new int ); + boost::shared_ptr< void const > p2( p, 0 ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + int m = 0; + boost::shared_ptr< void volatile > p3; + + p2.reset( p3, &m ); + + BOOST_TEST( p2.get() == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p3.use_count() ); + BOOST_TEST( !( p3 < p2 ) && !( p2 < p3 ) ); + } + + { + boost::shared_ptr< incomplete > p; + boost::shared_ptr< incomplete > p2( p, 0 ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p2.reset( p, 0 ); + + BOOST_TEST( p2.get() == 0 ); + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + + { + boost::shared_ptr< X > p( new X( 5 ) ); + boost::shared_ptr< int const > p2( p, &p->v_ ); + + BOOST_TEST( p2.get() == &p->v_ ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p.reset(); + BOOST_TEST( *p2 == 5 ); + + boost::shared_ptr< X const > p3( new X( 8 ) ); + p2.reset( p3, &p3->v_ ); + + BOOST_TEST( p2.get() == &p3->v_ ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p3.use_count() ); + BOOST_TEST( !( p3 < p2 ) && !( p2 < p3 ) ); + + p3.reset(); + BOOST_TEST( *p2 == 8 ); + } + + return boost::report_errors(); +} diff --git a/test/shared_ptr_alloc2_test.cpp b/test/shared_ptr_alloc2_test.cpp new file mode 100644 index 0000000..93f9d26 --- /dev/null +++ b/test/shared_ptr_alloc2_test.cpp @@ -0,0 +1,224 @@ +#include + +// shared_ptr_alloc2_test.cpp +// +// Copyright (c) 2005 Peter Dimov +// +// 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 +#include +#include +#include + +// test_allocator + +struct test_allocator_base +{ + int id_; + + static int last_global_id_; + static int count_; + + explicit test_allocator_base( int id ): id_( id ) + { + } +}; + +int test_allocator_base::last_global_id_ = 0; +int test_allocator_base::count_ = 0; + +template class test_allocator: public test_allocator_base +{ +public: + + typedef T * pointer; + typedef T const * const_pointer; + typedef T & reference; + typedef T const & const_reference; + typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + +private: + + static T * last_pointer_; + static std::size_t last_n_; + static int last_id_; + +public: + + template struct rebind + { + typedef test_allocator other; + }; + + pointer address( reference r ) const + { + return &r; + } + + const_pointer address( const_reference s ) const + { + return &s; + } + + explicit test_allocator( int id = 0 ): test_allocator_base( id ) + { + } + + template test_allocator( test_allocator const & r ): test_allocator_base( r ) + { + } + + template test_allocator & operator=( test_allocator const & r ) + { + test_allocator_base::operator=( r ); + return *this; + } + + void deallocate( pointer p, size_type n ) + { + BOOST_TEST( p == last_pointer_ ); + BOOST_TEST( n == last_n_ ); + BOOST_TEST( id_ == last_id_ ); + + --count_; + + ::operator delete( p ); + } + + pointer allocate( size_type n, void const * ) + { + T * p = static_cast< T* >( ::operator new( n * sizeof( T ) ) ); + + last_pointer_ = p; + last_n_ = n; + last_id_ = id_; + + last_global_id_ = id_; + ++count_; + + return p; + } + + void construct( pointer p, T const & t ) + { + new( p ) T( t ); + } + + void destroy( pointer p ) + { + p->~T(); + } + + size_type max_size() const + { + return size_type( -1 ) / sizeof( T ); + } +}; + +template T * test_allocator::last_pointer_ = 0; +template std::size_t test_allocator::last_n_ = 0; +template int test_allocator::last_id_ = 0; + +template inline bool operator==( test_allocator const & a1, test_allocator const & a2 ) +{ + return a1.id_ == a2.id_; +} + +template inline bool operator!=( test_allocator const & a1, test_allocator const & a2 ) +{ + return a1.id_ != a2.id_; +} + +template<> class test_allocator: public test_allocator_base +{ +public: + + typedef void * pointer; + typedef void const * const_pointer; + typedef void value_type; + + template struct rebind + { + typedef test_allocator other; + }; + + explicit test_allocator( int id = 0 ): test_allocator_base( id ) + { + } + + template test_allocator( test_allocator const & r ): test_allocator_base( r ) + { + } + + template test_allocator & operator=( test_allocator const & r ) + { + test_allocator_base::operator=( r ); + return *this; + } +}; + +// + +struct X +{ + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + boost::shared_ptr pv( new X, boost::checked_deleter(), std::allocator() ); + + BOOST_TEST( X::instances == 1 ); + + pv.reset( new X, boost::checked_deleter(), test_allocator( 42 ) ); + + BOOST_TEST( X::instances == 1 ); + + BOOST_TEST( test_allocator_base::last_global_id_ == 42 ); + BOOST_TEST( test_allocator_base::count_ > 0 ); + + pv.reset(); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( test_allocator_base::count_ == 0 ); + + pv.reset( new X, boost::checked_deleter(), test_allocator( 43 ) ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( test_allocator_base::last_global_id_ == 43 ); + + pv.reset( new X, boost::checked_deleter(), std::allocator() ); + + BOOST_TEST( X::instances == 1 ); + + pv.reset(); + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/shared_ptr_alloc_test.cpp b/test/shared_ptr_alloc_test.cpp new file mode 100644 index 0000000..0dedc37 --- /dev/null +++ b/test/shared_ptr_alloc_test.cpp @@ -0,0 +1,166 @@ +// +// shared_ptr_alloc_test.cpp - use to evaluate the impact of count allocations +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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 +#include +#include + +#include +#include +#include +#include +#include + +int const n = 1024 * 1024; + +template void test(T * = 0) +{ + std::clock_t t = std::clock(); + std::clock_t t2; + + { + std::vector< boost::shared_ptr > v; + + for(int i = 0; i < n; ++i) + { + boost::shared_ptr pi(new T(i)); + v.push_back(pi); + } + + t2 = std::clock(); + } + + std::clock_t t3 = std::clock(); + + std::cout << " " << static_cast(t3 - t) / CLOCKS_PER_SEC << " seconds, " << static_cast(t2 - t) / CLOCKS_PER_SEC << " + " << static_cast(t3 - t2) / CLOCKS_PER_SEC << ".\n"; +} + +class X +{ +public: + + explicit X(int n): n_(n) + { + } + + void * operator new(std::size_t) + { + return std::allocator().allocate(1, static_cast(0)); + } + + void operator delete(void * p) + { + std::allocator().deallocate(static_cast(p), 1); + } + +private: + + X(X const &); + X & operator=(X const &); + + int n_; +}; + +class Y +{ +public: + + explicit Y(int n): n_(n) + { + } + + void * operator new(std::size_t n) + { + return boost::detail::quick_allocator::alloc(n); + } + + void operator delete(void * p, std::size_t n) + { + boost::detail::quick_allocator::dealloc(p, n); + } + +private: + + Y(Y const &); + Y & operator=(Y const &); + + int n_; +}; + +class Z: public Y +{ +public: + + explicit Z(int n): Y(n), m_(n + 1) + { + } + +private: + + Z(Z const &); + Z & operator=(Z const &); + + int m_; +}; + +int main() +{ + std::cout << BOOST_COMPILER "\n"; + std::cout << BOOST_PLATFORM "\n"; + std::cout << BOOST_STDLIB "\n"; + +#if defined(BOOST_HAS_THREADS) + std::cout << "BOOST_HAS_THREADS: (defined)\n"; +#else + std::cout << "BOOST_HAS_THREADS: (not defined)\n"; +#endif + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) + std::cout << "BOOST_SP_USE_STD_ALLOCATOR: (defined)\n"; +#else + std::cout << "BOOST_SP_USE_STD_ALLOCATOR: (not defined)\n"; +#endif + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) + std::cout << "BOOST_SP_USE_QUICK_ALLOCATOR: (defined)\n"; +#else + std::cout << "BOOST_SP_USE_QUICK_ALLOCATOR: (not defined)\n"; +#endif + +#if defined(BOOST_QA_PAGE_SIZE) + std::cout << "BOOST_QA_PAGE_SIZE: " << BOOST_QA_PAGE_SIZE << "\n"; +#else + std::cout << "BOOST_QA_PAGE_SIZE: (not defined)\n"; +#endif + + std::cout << n << " shared_ptr allocations + deallocations:\n"; + + test(); + test(); + test(); + + std::cout << n << " shared_ptr allocations + deallocations:\n"; + + test(); + test(); + test(); + + std::cout << n << " shared_ptr allocations + deallocations:\n"; + + test(); + test(); + test(); + + std::cout << n << " shared_ptr allocations + deallocations:\n"; + + test(); + test(); + test(); +} diff --git a/test/shared_ptr_assign_fail.cpp b/test/shared_ptr_assign_fail.cpp new file mode 100644 index 0000000..c2820e0 --- /dev/null +++ b/test/shared_ptr_assign_fail.cpp @@ -0,0 +1,32 @@ +#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 +#endif + +// +// shared_ptr_assign_fail.cpp - a negative test for shared_ptr assignment +// +// Copyright (c) 2002 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 + +bool boost_error(char const *, char const *, char const *, long) +{ + return true; +} + +int main() +{ + boost::shared_ptr p; + p = new int(42); // assignment must fail + return 0; +} diff --git a/test/shared_ptr_basic_test.cpp b/test/shared_ptr_basic_test.cpp new file mode 100644 index 0000000..f699848 --- /dev/null +++ b/test/shared_ptr_basic_test.cpp @@ -0,0 +1,299 @@ +#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 + +#if (BOOST_MSVC >= 1310) +#pragma warning(disable: 4675) // resolved overload found with Koenig lookup +#endif + +#endif + +// +// shared_ptr_basic_test.cpp +// +// Copyright (c) 2001, 2002 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 + +#include +#include + +int cnt = 0; + +struct X +{ + X() + { + ++cnt; + } + + ~X() // virtual destructor deliberately omitted + { + --cnt; + } + + virtual int id() const + { + return 1; + } + +private: + + X(X const &); + X & operator= (X const &); +}; + +struct Y: public X +{ + Y() + { + ++cnt; + } + + ~Y() + { + --cnt; + } + + virtual int id() const + { + return 2; + } + +private: + + Y(Y const &); + Y & operator= (Y const &); +}; + +int * get_object() +{ + ++cnt; + return &cnt; +} + +void release_object(int * p) +{ + BOOST_TEST(p == &cnt); + --cnt; +} + +template void test_is_X(boost::shared_ptr const & p) +{ + BOOST_TEST(p->id() == 1); + BOOST_TEST((*p).id() == 1); +} + +template void test_is_X(boost::weak_ptr const & p) +{ + BOOST_TEST(p.get() != 0); + BOOST_TEST(p.get()->id() == 1); +} + +template void test_is_Y(boost::shared_ptr const & p) +{ + BOOST_TEST(p->id() == 2); + BOOST_TEST((*p).id() == 2); +} + +template void test_is_Y(boost::weak_ptr const & p) +{ + boost::shared_ptr q = p.lock(); + BOOST_TEST(q.get() != 0); + BOOST_TEST(q->id() == 2); +} + +template void test_eq(T const & a, T const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template void test_ne(T const & a, T const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template void test_shared(boost::weak_ptr const & a, boost::weak_ptr const & b) +{ + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template void test_nonshared(boost::weak_ptr const & a, boost::weak_ptr const & b) +{ + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template void test_eq2(T const & a, U const & b) +{ + BOOST_TEST(a == b); + BOOST_TEST(!(a != b)); +} + +template void test_ne2(T const & a, U const & b) +{ + BOOST_TEST(!(a == b)); + BOOST_TEST(a != b); +} + +template void test_is_zero(boost::shared_ptr const & p) +{ + BOOST_TEST(!p); + BOOST_TEST(p.get() == 0); +} + +template void test_is_nonzero(boost::shared_ptr const & p) +{ + // p? true: false is used to test p in a boolean context. + // BOOST_TEST(p) is not guaranteed to test the conversion, + // as the macro might test !!p instead. + BOOST_TEST(p? true: false); + BOOST_TEST(p.get() != 0); +} + +int main() +{ + using namespace boost; + + { + shared_ptr p(new Y); + shared_ptr p2(new X); + + test_is_nonzero(p); + test_is_nonzero(p2); + test_is_Y(p); + test_is_X(p2); + test_ne(p, p2); + + { + shared_ptr q(p); + test_eq(p, q); + } + + shared_ptr p3 = dynamic_pointer_cast(p); + shared_ptr p4 = dynamic_pointer_cast(p2); + + test_is_nonzero(p3); + test_is_zero(p4); + + BOOST_TEST(p.use_count() == 2); + BOOST_TEST(p2.use_count() == 1); + BOOST_TEST(p3.use_count() == 2); + + test_is_Y(p3); + test_eq2(p, p3); + test_ne2(p2, p4); + + shared_ptr p5(p); + + test_is_nonzero(p5); + test_eq2(p, p5); + + weak_ptr wp1(p2); + + BOOST_TEST(!wp1.expired()); + BOOST_TEST(wp1.use_count() != 0); + + p.reset(); + p2.reset(); + p3.reset(); + p4.reset(); + + test_is_zero(p); + test_is_zero(p2); + test_is_zero(p3); + test_is_zero(p4); + + BOOST_TEST(p5.use_count() == 1); + + BOOST_TEST(wp1.expired()); + BOOST_TEST(wp1.use_count() == 0); + + try + { + shared_ptr sp1(wp1); + BOOST_ERROR("shared_ptr sp1(wp1) failed to throw"); + } + catch(boost::bad_weak_ptr const &) + { + } + + test_is_zero(wp1.lock()); + + weak_ptr wp2 = static_pointer_cast(p5); + + BOOST_TEST(wp2.use_count() == 1); + test_is_Y(wp2); + test_nonshared(wp1, wp2); + + // Scoped to not affect the subsequent use_count() tests. + { + shared_ptr sp2(wp2); + test_is_nonzero(wp2.lock()); + } + + weak_ptr wp3 = dynamic_pointer_cast(wp2.lock()); + + BOOST_TEST(wp3.use_count() == 1); + test_shared(wp2, wp3); + + weak_ptr wp4(wp3); + + BOOST_TEST(wp4.use_count() == 1); + test_shared(wp2, wp4); + + wp1 = p2; + test_is_zero(wp1.lock()); + + wp1 = p4; + wp1 = wp3; + wp1 = wp2; + + BOOST_TEST(wp1.use_count() == 1); + test_shared(wp1, wp2); + + weak_ptr wp5; + + bool b1 = wp1 < wp5; + bool b2 = wp5 < wp1; + + p5.reset(); + + BOOST_TEST(wp1.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(wp3.use_count() == 0); + + // Test operator< stability for std::set< weak_ptr<> > + // Thanks to Joe Gottman for pointing this out + + BOOST_TEST(b1 == (wp1 < wp5)); + BOOST_TEST(b2 == (wp5 < wp1)); + + { + // note that both get_object and release_object deal with int* + shared_ptr p6(get_object(), release_object); + } + } + + BOOST_TEST(cnt == 0); + + return boost::report_errors(); +} diff --git a/test/shared_ptr_compare_fail.cpp b/test/shared_ptr_compare_fail.cpp new file mode 100644 index 0000000..296af14 --- /dev/null +++ b/test/shared_ptr_compare_fail.cpp @@ -0,0 +1,27 @@ +#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 +#endif + +// +// shared_ptr_compare_fail.cpp - a negative test for "p > q" +// +// Copyright 2006 Peter Dimov +// +// 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 + +int main() +{ + boost::shared_ptr p, q; + p > q; // must fail + return 0; +} diff --git a/test/shared_ptr_delete_fail.cpp b/test/shared_ptr_delete_fail.cpp new file mode 100644 index 0000000..66cfafe --- /dev/null +++ b/test/shared_ptr_delete_fail.cpp @@ -0,0 +1,27 @@ +#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 +#endif + +// +// shared_ptr_delete_fail.cpp - a negative test for "delete sp;" +// +// Copyright 2005 Peter Dimov +// +// 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 + +int main() +{ + boost::shared_ptr p; + delete p; // must fail + return 0; +} diff --git a/test/shared_ptr_move_test.cpp b/test/shared_ptr_move_test.cpp new file mode 100644 index 0000000..c02ffa9 --- /dev/null +++ b/test/shared_ptr_move_test.cpp @@ -0,0 +1,106 @@ +// +// shared_ptr_move_test.cpp +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include + +#if defined( BOOST_HAS_RVALUE_REFS ) + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +long X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( std::move( p ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + boost::shared_ptr p3( std::move( p2 ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p2.get() == 0 ); + + p3.reset(); + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2; + p2 = std::move( p ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + boost::shared_ptr p3; + p3 = std::move( p2 ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p2.get() == 0 ); + + p3.reset(); + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( new X ); + BOOST_TEST( X::instances == 2 ); + p2 = std::move( p ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + boost::shared_ptr p3( new X ); + BOOST_TEST( X::instances == 2 ); + p3 = std::move( p2 ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p2.get() == 0 ); + + p3.reset(); + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} + +#else // !defined( BOOST_HAS_RVALUE_REFS ) + +int main() +{ + return 0; +} + +#endif diff --git a/test/shared_ptr_mt_test.cpp b/test/shared_ptr_mt_test.cpp new file mode 100644 index 0000000..50a9f51 --- /dev/null +++ b/test/shared_ptr_mt_test.cpp @@ -0,0 +1,82 @@ +#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 +#endif + +// shared_ptr_mt_test.cpp - tests shared_ptr with multiple threads +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +#include + +#include +#include + +#include + +// + +int const n = 1024 * 1024; + +void test( boost::shared_ptr const & pi ) +{ + std::vector< boost::shared_ptr > v; + + for( int i = 0; i < n; ++i ) + { + v.push_back( pi ); + } +} + +int const m = 16; // threads + +#if defined( BOOST_HAS_PTHREADS ) + +char const * thmodel = "POSIX"; + +#else + +char const * thmodel = "Windows"; + +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf( "Using %s threads: %d threads, %d iterations: ", thmodel, m, n ); + + boost::shared_ptr pi( new int(42) ); + + clock_t t = clock(); + + pthread_t a[ m ]; + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( test, pi ) ); + } + + for( int j = 0; j < m; ++j ) + { + pthread_join( a[j], 0 ); + } + + t = clock() - t; + + printf( "\n\n%.3f seconds.\n", static_cast(t) / CLOCKS_PER_SEC ); + + return 0; +} diff --git a/test/shared_ptr_pv_fail.cpp b/test/shared_ptr_pv_fail.cpp new file mode 100644 index 0000000..924e657 --- /dev/null +++ b/test/shared_ptr_pv_fail.cpp @@ -0,0 +1,31 @@ +#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 +#endif + +// +// shared_ptr_pv_fail.cpp - a negative test for converting a shared_ptr to void* +// +// Copyright 2007 Peter Dimov +// +// 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 + +void f( void* ) +{ +} + +int main() +{ + boost::shared_ptr p; + f( p ); // must fail + return 0; +} diff --git a/test/shared_ptr_rv_test.cpp b/test/shared_ptr_rv_test.cpp new file mode 100644 index 0000000..fe77259 --- /dev/null +++ b/test/shared_ptr_rv_test.cpp @@ -0,0 +1,110 @@ +// +// shared_ptr_rv_test.cpp +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + + static boost::shared_ptr create() + { + return boost::shared_ptr( new X ); + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +long X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p( X::create() ); + BOOST_TEST( X::instances == 1 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + + p.reset(); + BOOST_TEST( X::instances == 0 ); + + p = X::create(); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp new file mode 100644 index 0000000..f697192 --- /dev/null +++ b/test/shared_ptr_test.cpp @@ -0,0 +1,3380 @@ +#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 + +#if (BOOST_MSVC >= 1310) +#pragma warning(disable: 4675) // resolved overload found with Koenig lookup +#endif + +#endif + +// +// shared_ptr_test.cpp +// +// Copyright (c) 2002, 2003 Peter Dimov +// +// 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 + +#include +#include + +#include +#include + +// + +namespace n_element_type +{ + +void f(int &) +{ +} + +void test() +{ + typedef boost::shared_ptr::element_type T; + T t; + f(t); +} + +} // namespace n_element_type + +namespace n_constructors +{ + +class incomplete; + +void default_constructor() +{ + { + boost::shared_ptr pi; + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); + } + + { + boost::shared_ptr pv; + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); + } + + { + boost::shared_ptr px; + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); + } +} + +struct A +{ + int dummy; +}; + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X(X const &); + X & operator= (X const &); +}; + +long X::instances = 0; + +// virtual inheritance stresses the implementation + +struct Y: public A, public virtual X +{ + static long instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y(Y const &); + Y & operator= (Y const &); +}; + +long Y::instances = 0; + +template void pc0_test(T * p) +{ + BOOST_TEST(p == 0); + boost::shared_ptr pt(p); + BOOST_TEST(pt? false: true); + BOOST_TEST(!pt); + BOOST_TEST(pt.get() == 0); + BOOST_TEST(pt.use_count() == 1); + BOOST_TEST(pt.unique()); +} + +void pointer_constructor() +{ + pc0_test(static_cast(0)); + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1300) + + pc0_test(static_cast(0)); + pc0_test(static_cast(0)); + pc0_test(static_cast(0)); + +#endif + + { + boost::shared_ptr pi(static_cast(0)); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + { + boost::shared_ptr pi(static_cast(0)); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + { + boost::shared_ptr pv(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + boost::shared_ptr pv(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + pc0_test(static_cast(0)); + pc0_test(static_cast(0)); + pc0_test(static_cast(0)); + pc0_test(static_cast(0)); + + { + boost::shared_ptr px(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + } + + { + boost::shared_ptr px(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + } + + { + boost::shared_ptr px(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + } + + { + boost::shared_ptr pv(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + boost::shared_ptr pv(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + int * p = new int(7); + boost::shared_ptr pi(p); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == p); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(*pi == 7); + } + + { + int * p = new int(7); + boost::shared_ptr pi(p); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == p); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(*pi == 7); + } + + { + int * p = new int(7); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == p); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + int * p = new int(7); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == p); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + BOOST_TEST(X::instances == 0); + + { + X * p = new X; + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + } + + BOOST_TEST(X::instances == 0); + + { + X * p = new X; + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + } + + BOOST_TEST(X::instances == 0); + + { + X * p = new X; + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == p); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + } + + BOOST_TEST(X::instances == 0); + + { + X * p = new X; + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == p); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + { + Y * p = new Y; + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + { + Y * p = new Y; + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); +} + +int m = 0; + +void deleter(int * p) +{ + BOOST_TEST(p == 0); +} + +void deleter2(int * p) +{ + BOOST_TEST(p == &m); + ++*p; +} + +struct deleter3 +{ + void operator()(incomplete * p) + { + BOOST_TEST(p == 0); + } +}; + +// Borland C++ 5.5.1 fails on static_cast(0) + +incomplete * p0 = 0; + +void deleter_constructor() +{ + { + boost::shared_ptr pi(static_cast(0), deleter); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + { + boost::shared_ptr pv(static_cast(0), &deleter); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + boost::shared_ptr pv(static_cast(0), deleter); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + boost::shared_ptr px(p0, deleter3()); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + } + + { + boost::shared_ptr pv(p0, deleter3()); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + { + boost::shared_ptr pv(p0, deleter3()); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + BOOST_TEST(m == 0); + + { + boost::shared_ptr pi(&m, deleter2); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == &m); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + BOOST_TEST(m == 1); + + { + boost::shared_ptr pi(&m, &deleter2); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == &m); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + BOOST_TEST(m == 2); + + { + boost::shared_ptr pv(&m, deleter2); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == &m); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + BOOST_TEST(m == 3); + + { + boost::shared_ptr pv(&m, &deleter2); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == &m); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + } + + BOOST_TEST(m == 4); +} + +void copy_constructor() +{ + { + boost::shared_ptr pi; + + boost::shared_ptr pi2(pi); + BOOST_TEST(pi2 == pi); + BOOST_TEST(pi2? false: true); + BOOST_TEST(!pi2); + BOOST_TEST(pi2.get() == 0); + BOOST_TEST(pi2.use_count() == pi.use_count()); + + boost::shared_ptr pi3(pi); + BOOST_TEST(pi3 == pi); + BOOST_TEST(pi3? false: true); + BOOST_TEST(!pi3); + BOOST_TEST(pi3.get() == 0); + BOOST_TEST(pi3.use_count() == pi.use_count()); + + boost::shared_ptr pi4(pi3); + BOOST_TEST(pi4 == pi3); + BOOST_TEST(pi4? false: true); + BOOST_TEST(!pi4); + BOOST_TEST(pi4.get() == 0); + BOOST_TEST(pi4.use_count() == pi3.use_count()); + } + + { + boost::shared_ptr pv; + + boost::shared_ptr pv2(pv); + BOOST_TEST(pv2 == pv); + BOOST_TEST(pv2? false: true); + BOOST_TEST(!pv2); + BOOST_TEST(pv2.get() == 0); + BOOST_TEST(pv2.use_count() == pv.use_count()); + } + + { + boost::shared_ptr px; + + boost::shared_ptr px2(px); + BOOST_TEST(px2 == px); + BOOST_TEST(px2? false: true); + BOOST_TEST(!px2); + BOOST_TEST(px2.get() == 0); + BOOST_TEST(px2.use_count() == px.use_count()); + + boost::shared_ptr px3(px); + BOOST_TEST(px3 == px); + BOOST_TEST(px3? false: true); + BOOST_TEST(!px3); + BOOST_TEST(px3.get() == 0); + BOOST_TEST(px3.use_count() == px.use_count()); + } + + { + boost::shared_ptr pi(static_cast(0)); + + boost::shared_ptr pi2(pi); + BOOST_TEST(pi2 == pi); + BOOST_TEST(pi2? false: true); + BOOST_TEST(!pi2); + BOOST_TEST(pi2.get() == 0); + BOOST_TEST(pi2.use_count() == 2); + BOOST_TEST(!pi2.unique()); + BOOST_TEST(pi2.use_count() == pi.use_count()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); // shared ownership test + + boost::shared_ptr pi3(pi); + BOOST_TEST(pi3 == pi); + BOOST_TEST(pi3? false: true); + BOOST_TEST(!pi3); + BOOST_TEST(pi3.get() == 0); + BOOST_TEST(pi3.use_count() == 3); + BOOST_TEST(!pi3.unique()); + BOOST_TEST(pi3.use_count() == pi.use_count()); + BOOST_TEST(!(pi < pi3 || pi3 < pi)); // shared ownership test + + boost::shared_ptr pi4(pi2); + BOOST_TEST(pi4 == pi2); + BOOST_TEST(pi4? false: true); + BOOST_TEST(!pi4); + BOOST_TEST(pi4.get() == 0); + BOOST_TEST(pi4.use_count() == 4); + BOOST_TEST(!pi4.unique()); + BOOST_TEST(pi4.use_count() == pi2.use_count()); + BOOST_TEST(!(pi2 < pi4 || pi4 < pi2)); // shared ownership test + + BOOST_TEST(pi3.use_count() == pi4.use_count()); + BOOST_TEST(!(pi3 < pi4 || pi4 < pi3)); // shared ownership test + } + + { + boost::shared_ptr px(static_cast(0)); + + boost::shared_ptr px2(px); + BOOST_TEST(px2 == px); + BOOST_TEST(px2? false: true); + BOOST_TEST(!px2); + BOOST_TEST(px2.get() == 0); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(!px2.unique()); + BOOST_TEST(px2.use_count() == px.use_count()); + BOOST_TEST(!(px < px2 || px2 < px)); // shared ownership test + + boost::shared_ptr px3(px); + BOOST_TEST(px3 == px); + BOOST_TEST(px3? false: true); + BOOST_TEST(!px3); + BOOST_TEST(px3.get() == 0); + BOOST_TEST(px3.use_count() == 3); + BOOST_TEST(!px3.unique()); + BOOST_TEST(px3.use_count() == px.use_count()); + BOOST_TEST(!(px < px3 || px3 < px)); // shared ownership test + + boost::shared_ptr px4(px2); + BOOST_TEST(px4 == px2); + BOOST_TEST(px4? false: true); + BOOST_TEST(!px4); + BOOST_TEST(px4.get() == 0); + BOOST_TEST(px4.use_count() == 4); + BOOST_TEST(!px4.unique()); + BOOST_TEST(px4.use_count() == px2.use_count()); + BOOST_TEST(!(px2 < px4 || px4 < px2)); // shared ownership test + + BOOST_TEST(px3.use_count() == px4.use_count()); + BOOST_TEST(!(px3 < px4 || px4 < px3)); // shared ownership test + } + + { + int * p = new int(7); + boost::shared_ptr pi(p); + + boost::shared_ptr pi2(pi); + BOOST_TEST(pi2 == pi); + BOOST_TEST(pi2? true: false); + BOOST_TEST(!!pi2); + BOOST_TEST(pi2.get() == p); + BOOST_TEST(pi2.use_count() == 2); + BOOST_TEST(!pi2.unique()); + BOOST_TEST(*pi2 == 7); + BOOST_TEST(pi2.use_count() == pi.use_count()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); // shared ownership test + } + + { + int * p = new int(7); + boost::shared_ptr pv(p); + BOOST_TEST(pv.get() == p); + + boost::shared_ptr pv2(pv); + BOOST_TEST(pv2 == pv); + BOOST_TEST(pv2? true: false); + BOOST_TEST(!!pv2); + BOOST_TEST(pv2.get() == p); + BOOST_TEST(pv2.use_count() == 2); + BOOST_TEST(!pv2.unique()); + BOOST_TEST(pv2.use_count() == pv.use_count()); + BOOST_TEST(!(pv < pv2 || pv2 < pv)); // shared ownership test + } + + BOOST_TEST(X::instances == 0); + + { + X * p = new X; + boost::shared_ptr px(p); + BOOST_TEST(px.get() == p); + + boost::shared_ptr px2(px); + BOOST_TEST(px2 == px); + BOOST_TEST(px2? true: false); + BOOST_TEST(!!px2); + BOOST_TEST(px2.get() == p); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(!px2.unique()); + + BOOST_TEST(X::instances == 1); + + BOOST_TEST(px2.use_count() == px.use_count()); + BOOST_TEST(!(px < px2 || px2 < px)); // shared ownership test + + boost::shared_ptr px3(px); + BOOST_TEST(px3 == px); + BOOST_TEST(px3? true: false); + BOOST_TEST(!!px3); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3.use_count() == 3); + BOOST_TEST(!px3.unique()); + BOOST_TEST(px3.use_count() == px.use_count()); + BOOST_TEST(!(px < px3 || px3 < px)); // shared ownership test + + boost::shared_ptr px4(px2); + BOOST_TEST(px4 == px2); + BOOST_TEST(px4? true: false); + BOOST_TEST(!!px4); + BOOST_TEST(px4.get() == p); + BOOST_TEST(px4.use_count() == 4); + BOOST_TEST(!px4.unique()); + BOOST_TEST(px4.use_count() == px2.use_count()); + BOOST_TEST(!(px2 < px4 || px4 < px2)); // shared ownership test + + BOOST_TEST(px3.use_count() == px4.use_count()); + BOOST_TEST(!(px3 < px4 || px4 < px3)); // shared ownership test + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + { + Y * p = new Y; + boost::shared_ptr py(p); + BOOST_TEST(py.get() == p); + + boost::shared_ptr px(py); + BOOST_TEST(px == py); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(!px.unique()); + BOOST_TEST(px.use_count() == py.use_count()); + BOOST_TEST(!(px < py || py < px)); // shared ownership test + + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + + boost::shared_ptr pv(px); + BOOST_TEST(pv == px); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == px.get()); + BOOST_TEST(pv.use_count() == 3); + BOOST_TEST(!pv.unique()); + BOOST_TEST(pv.use_count() == px.use_count()); + BOOST_TEST(!(px < pv || pv < px)); // shared ownership test + + boost::shared_ptr pv2(py); + BOOST_TEST(pv2 == py); + BOOST_TEST(pv2? true: false); + BOOST_TEST(!!pv2); + BOOST_TEST(pv2.get() == py.get()); + BOOST_TEST(pv2.use_count() == 4); + BOOST_TEST(!pv2.unique()); + BOOST_TEST(pv2.use_count() == py.use_count()); + BOOST_TEST(!(py < pv2 || pv2 < py)); // shared ownership test + + BOOST_TEST(pv.use_count() == pv2.use_count()); + BOOST_TEST(!(pv < pv2 || pv2 < pv)); // shared ownership test + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); +} + +void weak_ptr_constructor() +{ + { + boost::weak_ptr wp; + BOOST_TEST(wp.use_count() == 0); + + try + { + boost::shared_ptr p2(wp); + BOOST_ERROR("shared_ptr p2(wp) failed to throw"); + } + catch(boost::bad_weak_ptr) + { + } + + try + { + boost::shared_ptr p3(wp); + BOOST_ERROR("shared_ptr p3(wp) failed to throw"); + } + catch(boost::bad_weak_ptr) + { + } + } + + { + boost::shared_ptr p; + boost::weak_ptr wp(p); + + if(wp.use_count() != 0) // 0 allowed but not required + { + boost::shared_ptr p2(wp); + BOOST_TEST(p2.use_count() == wp.use_count()); + BOOST_TEST(p2.get() == 0); + + boost::shared_ptr p3(wp); + BOOST_TEST(p3.use_count() == wp.use_count()); + BOOST_TEST(p3.get() == 0); + } + } + + { + boost::shared_ptr p(new Y); + boost::weak_ptr wp(p); + + { + boost::shared_ptr p2(wp); + BOOST_TEST(p2? true: false); + BOOST_TEST(!!p2); + BOOST_TEST(p2.get() == p.get()); + BOOST_TEST(p2.use_count() == 2); + BOOST_TEST(!p2.unique()); + BOOST_TEST(p2.use_count() == wp.use_count()); + + BOOST_TEST(p.use_count() == p2.use_count()); + BOOST_TEST(!(p < p2 || p2 < p)); // shared ownership test + + boost::shared_ptr p3(wp); + BOOST_TEST(p3? true: false); + BOOST_TEST(!!p3); + BOOST_TEST(p3.get() == p.get()); + BOOST_TEST(p3.use_count() == 3); + BOOST_TEST(!p3.unique()); + BOOST_TEST(p3.use_count() == wp.use_count()); + + BOOST_TEST(p.use_count() == p3.use_count()); + } + + p.reset(); + BOOST_TEST(wp.use_count() == 0); + + try + { + boost::shared_ptr p2(wp); + BOOST_ERROR("shared_ptr p2(wp) failed to throw"); + } + catch(boost::bad_weak_ptr) + { + } + + try + { + boost::shared_ptr p3(wp); + BOOST_ERROR("shared_ptr p3(wp) failed to throw"); + } + catch(boost::bad_weak_ptr) + { + } + } +} + +#if defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB < 306) +# define BOOST_OLD_AUTO_PTR +#endif + +void auto_ptr_constructor() +{ + { + std::auto_ptr p; + boost::shared_ptr pi(p); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr pi(p); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr pv(p); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr pv(p); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr px(p); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr px(p); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr px(p); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr px(p); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr pv(p); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p; + boost::shared_ptr pv(p); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(p.get() == 0); + } + + { + std::auto_ptr p(new int(7)); + int * q = p.get(); + boost::shared_ptr pi(p); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == q); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(*pi == 7); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + { + std::auto_ptr p(new int(7)); + int * q = p.get(); + boost::shared_ptr pi(p); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == q); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + BOOST_TEST(*pi == 7); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + { + std::auto_ptr p(new int(7)); + int * q = p.get(); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == q); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + { + std::auto_ptr p(new int(7)); + int * q = p.get(); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == q); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + + { + std::auto_ptr p(new X); + X * q = p.get(); + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == q); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + + { + std::auto_ptr p(new X); + X * q = p.get(); + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == q); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + + { + std::auto_ptr p(new X); + X * q = p.get(); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == q); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + + { + std::auto_ptr p(new X); + X * q = p.get(); + boost::shared_ptr pv(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == q); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + { + std::auto_ptr p(new Y); + Y * q = p.get(); + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == q); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + { + std::auto_ptr p(new Y); + Y * q = p.get(); + boost::shared_ptr px(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == q); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p.get() == 0); +#endif + } + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); +} + +void test() +{ + default_constructor(); + pointer_constructor(); + deleter_constructor(); + copy_constructor(); + weak_ptr_constructor(); + auto_ptr_constructor(); +} + +} // namespace n_constructors + +namespace n_assignment +{ + +class incomplete; + +struct A +{ + int dummy; +}; + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X(X const &); + X & operator= (X const &); +}; + +long X::instances = 0; + +struct Y: public A, public virtual X +{ + static long instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y(Y const &); + Y & operator= (Y const &); +}; + +long Y::instances = 0; + +void copy_assignment() +{ + { + boost::shared_ptr p1; + + p1 = p1; + + BOOST_TEST(p1 == p1); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p2; + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p3(p1); + + p1 = p3; + + BOOST_TEST(p1 == p3); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + } + + { + boost::shared_ptr p1; + + p1 = p1; + + BOOST_TEST(p1 == p1); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p2; + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p3(p1); + + p1 = p3; + + BOOST_TEST(p1 == p3); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p4(new int); + BOOST_TEST(p4.use_count() == 1); + + p1 = p4; + + BOOST_TEST(p1 == p4); + BOOST_TEST(!(p1 < p4 || p4 < p1)); + BOOST_TEST(p1.use_count() == 2); + BOOST_TEST(p4.use_count() == 2); + + p1 = p3; + + BOOST_TEST(p1 == p3); + BOOST_TEST(p4.use_count() == 1); + } + + { + boost::shared_ptr p1; + + p1 = p1; + + BOOST_TEST(p1 == p1); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p2; + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p3(p1); + + p1 = p3; + + BOOST_TEST(p1 == p3); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + BOOST_TEST(X::instances == 0); + + boost::shared_ptr p4(new X); + + BOOST_TEST(X::instances == 1); + + p1 = p4; + + BOOST_TEST(X::instances == 1); + + BOOST_TEST(p1 == p4); + BOOST_TEST(!(p1 < p4 || p4 < p1)); + + BOOST_TEST(p1.use_count() == 2); + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(X::instances == 1); + + p4 = p3; + + BOOST_TEST(p4 == p3); + BOOST_TEST(X::instances == 0); + } +} + +void conversion_assignment() +{ + { + boost::shared_ptr p1; + + boost::shared_ptr p2; + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + boost::shared_ptr p4(new int); + BOOST_TEST(p4.use_count() == 1); + + boost::shared_ptr p5(p4); + BOOST_TEST(p4.use_count() == 2); + + p1 = p4; + + BOOST_TEST(p1 == p4); + BOOST_TEST(!(p1 < p5 || p5 < p1)); + BOOST_TEST(p1.use_count() == 3); + BOOST_TEST(p4.use_count() == 3); + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p4.use_count() == 2); + } + + { + boost::shared_ptr p1; + + boost::shared_ptr p2; + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + boost::shared_ptr p4(new Y); + + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + BOOST_TEST(p4.use_count() == 1); + + boost::shared_ptr p5(p4); + BOOST_TEST(p4.use_count() == 2); + + p1 = p4; + + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + + BOOST_TEST(p1 == p4); + BOOST_TEST(!(p1 < p5 || p5 < p1)); + + BOOST_TEST(p1.use_count() == 3); + BOOST_TEST(p4.use_count() == 3); + + p1 = p2; + + BOOST_TEST(p1 == p2); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + BOOST_TEST(p4.use_count() == 2); + + p4 = p2; + p5 = p2; + + BOOST_TEST(p4 == p2); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + } +} + +void auto_ptr_assignment() +{ + { + boost::shared_ptr p1; + + std::auto_ptr p2; + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + + int * p = new int; + std::auto_ptr p3(p); + + p1 = p3; + BOOST_TEST(p1.get() == p); + BOOST_TEST(p1.use_count() == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p3.get() == 0); +#endif + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + } + + { + boost::shared_ptr p1; + + std::auto_ptr p2; + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + + int * p = new int; + std::auto_ptr p3(p); + + p1 = p3; + BOOST_TEST(p1.get() == p); + BOOST_TEST(p1.use_count() == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p3.get() == 0); +#endif + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + } + + + { + boost::shared_ptr p1; + + std::auto_ptr p2; + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + Y * p = new Y; + std::auto_ptr p3(p); + + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + + p1 = p3; + BOOST_TEST(p1.get() == p); + BOOST_TEST(p1.use_count() == 1); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + +#if !defined(BOOST_OLD_AUTO_PTR) + BOOST_TEST(p3.get() == 0); +#endif + + p1 = p2; + BOOST_TEST(p1? false: true); + BOOST_TEST(!p1); + BOOST_TEST(p1.get() == 0); + BOOST_TEST(p1.use_count() == 1); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + } +} + +void test() +{ + copy_assignment(); + conversion_assignment(); + auto_ptr_assignment(); +} + +} // namespace n_assignment + +namespace n_reset +{ + +class incomplete; + +incomplete * p0 = 0; + +void deleter(incomplete *) +{ +} + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X(X const &); + X & operator= (X const &); +}; + +long X::instances = 0; + +void plain_reset() +{ + { + boost::shared_ptr pi; + pi.reset(); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); + } + + { + boost::shared_ptr pi(static_cast(0)); + pi.reset(); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); + } + + { + boost::shared_ptr pi(new int); + pi.reset(); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); + } + + { + boost::shared_ptr px; + px.reset(); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); + } + + { + boost::shared_ptr px(p0, deleter); + px.reset(); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); + } + + { + boost::shared_ptr px; + px.reset(); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); + } + + { + BOOST_TEST(X::instances == 0); + boost::shared_ptr px(new X); + BOOST_TEST(X::instances == 1); + px.reset(); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); + BOOST_TEST(X::instances == 0); + } + + { + boost::shared_ptr pv; + pv.reset(); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); + } + + { + BOOST_TEST(X::instances == 0); + boost::shared_ptr pv(new X); + BOOST_TEST(X::instances == 1); + pv.reset(); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); + BOOST_TEST(X::instances == 0); + } +} + +struct A +{ + int dummy; +}; + +struct Y: public A, public virtual X +{ + static long instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y(Y const &); + Y & operator= (Y const &); +}; + +long Y::instances = 0; + +void pointer_reset() +{ + { + boost::shared_ptr pi; + + pi.reset(static_cast(0)); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + + int * p = new int; + pi.reset(p); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == p); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + + pi.reset(static_cast(0)); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + } + + { + boost::shared_ptr px; + + px.reset(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 0); + + X * p = new X; + px.reset(p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + + px.reset(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + Y * q = new Y; + px.reset(q); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == q); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + + px.reset(static_cast(0)); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + } + + { + boost::shared_ptr pv; + + pv.reset(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 0); + + X * p = new X; + pv.reset(p); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == p); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + + pv.reset(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + + Y * q = new Y; + pv.reset(q); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == q); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 1); + BOOST_TEST(Y::instances == 1); + + pv.reset(static_cast(0)); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + BOOST_TEST(X::instances == 0); + BOOST_TEST(Y::instances == 0); + } +} + +void * deleted = 0; + +void deleter2(void * p) +{ + deleted = p; +} + +void deleter_reset() +{ + { + boost::shared_ptr pi; + + pi.reset(static_cast(0), deleter2); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + + deleted = π + + int m = 0; + pi.reset(&m, deleter2); + BOOST_TEST(deleted == 0); + BOOST_TEST(pi? true: false); + BOOST_TEST(!!pi); + BOOST_TEST(pi.get() == &m); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + + pi.reset(static_cast(0), deleter2); + BOOST_TEST(deleted == &m); + BOOST_TEST(pi? false: true); + BOOST_TEST(!pi); + BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 1); + BOOST_TEST(pi.unique()); + + pi.reset(); + BOOST_TEST(deleted == 0); + } + + { + boost::shared_ptr px; + + px.reset(static_cast(0), deleter2); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + deleted = &px; + + X x; + px.reset(&x, deleter2); + BOOST_TEST(deleted == 0); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == &x); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + px.reset(static_cast(0), deleter2); + BOOST_TEST(deleted == &x); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + Y y; + px.reset(&y, deleter2); + BOOST_TEST(deleted == 0); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(px.get() == &y); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + px.reset(static_cast(0), deleter2); + BOOST_TEST(deleted == &y); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + px.reset(); + BOOST_TEST(deleted == 0); + } + + { + boost::shared_ptr pv; + + pv.reset(static_cast(0), deleter2); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + + deleted = &pv; + + X x; + pv.reset(&x, deleter2); + BOOST_TEST(deleted == 0); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == &x); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + + pv.reset(static_cast(0), deleter2); + BOOST_TEST(deleted == &x); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + + Y y; + pv.reset(&y, deleter2); + BOOST_TEST(deleted == 0); + BOOST_TEST(pv? true: false); + BOOST_TEST(!!pv); + BOOST_TEST(pv.get() == &y); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + + pv.reset(static_cast(0), deleter2); + BOOST_TEST(deleted == &y); + BOOST_TEST(pv? false: true); + BOOST_TEST(!pv); + BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 1); + BOOST_TEST(pv.unique()); + + pv.reset(); + BOOST_TEST(deleted == 0); + } + + { + boost::shared_ptr px; + + px.reset(p0, deleter2); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + deleted = &px; + px.reset(p0, deleter2); + BOOST_TEST(deleted == 0); + } +} + +void test() +{ + plain_reset(); + pointer_reset(); + deleter_reset(); +} + +} // namespace n_reset + +namespace n_access +{ + +struct X +{ +}; + +void test() +{ + { + boost::shared_ptr px; + BOOST_TEST(px.get() == 0); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + boost::shared_ptr px(static_cast(0)); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + boost::shared_ptr px(static_cast(0), boost::checked_deleter()); + BOOST_TEST(px.get() == 0); + BOOST_TEST(px? false: true); + BOOST_TEST(!px); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + X * p = new X; + boost::shared_ptr px(p); + BOOST_TEST(px.get() == p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(&*px == px.get()); + BOOST_TEST(px.operator ->() == px.get()); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } + + { + X * p = new X; + boost::shared_ptr px(p, boost::checked_deleter()); + BOOST_TEST(px.get() == p); + BOOST_TEST(px? true: false); + BOOST_TEST(!!px); + BOOST_TEST(&*px == px.get()); + BOOST_TEST(px.operator ->() == px.get()); + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) + using boost::get_pointer; +#endif + + BOOST_TEST(get_pointer(px) == px.get()); + } +} + +} // namespace n_access + +namespace n_use_count +{ + +struct X +{ +}; + +void test() +{ + { + boost::shared_ptr px(static_cast(0)); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + boost::shared_ptr px2(px); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(!px2.unique()); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(!px.unique()); + } + + { + boost::shared_ptr px(new X); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + boost::shared_ptr px2(px); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(!px2.unique()); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(!px.unique()); + } + + { + boost::shared_ptr px(new X, boost::checked_deleter()); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px.unique()); + + boost::shared_ptr px2(px); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(!px2.unique()); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(!px.unique()); + } +} + +} // namespace n_use_count + +namespace n_swap +{ + +struct X +{ +}; + +void test() +{ + { + boost::shared_ptr px; + boost::shared_ptr px2; + + px.swap(px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == 0); + } + + { + X * p = new X; + boost::shared_ptr px; + boost::shared_ptr px2(p); + boost::shared_ptr px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(px2.get() == 0); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3.use_count() == 2); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == 0); + BOOST_TEST(px2.get() == p); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(px3.get() == p); + BOOST_TEST(px3.use_count() == 2); + } + + { + X * p1 = new X; + X * p2 = new X; + boost::shared_ptr px(p1); + boost::shared_ptr px2(p2); + boost::shared_ptr px3(px2); + + px.swap(px2); + + BOOST_TEST(px.get() == p2); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(px2.get() == p1); + BOOST_TEST(px2.use_count() == 1); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3.use_count() == 2); + + using std::swap; + swap(px, px2); + + BOOST_TEST(px.get() == p1); + BOOST_TEST(px.use_count() == 1); + BOOST_TEST(px2.get() == p2); + BOOST_TEST(px2.use_count() == 2); + BOOST_TEST(px3.get() == p2); + BOOST_TEST(px3.use_count() == 2); + } +} + +} // namespace n_swap + +namespace n_comparison +{ + +struct X +{ + int dummy; +}; + +struct Y +{ + int dummy2; +}; + +struct Z: public X, public virtual Y +{ +}; + +void test() +{ + { + boost::shared_ptr px; + BOOST_TEST(px == px); + BOOST_TEST(!(px != px)); + BOOST_TEST(!(px < px)); + + boost::shared_ptr px2; + + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(px == px2); + BOOST_TEST(!(px != px2)); + BOOST_TEST(!(px < px2 && px2 < px)); + } + + { + boost::shared_ptr px; + boost::shared_ptr px2(px); + + BOOST_TEST(px2 == px2); + BOOST_TEST(!(px2 != px2)); + BOOST_TEST(!(px2 < px2)); + + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(px == px2); + BOOST_TEST(!(px != px2)); + BOOST_TEST(!(px < px2 && px2 < px)); + } + + { + boost::shared_ptr px; + boost::shared_ptr px2(new X); + + BOOST_TEST(px2 == px2); + BOOST_TEST(!(px2 != px2)); + BOOST_TEST(!(px2 < px2)); + + BOOST_TEST(px.get() != px2.get()); + BOOST_TEST(px != px2); + BOOST_TEST(!(px == px2)); + BOOST_TEST(px < px2 || px2 < px); + BOOST_TEST(!(px < px2 && px2 < px)); + } + + { + boost::shared_ptr px(new X); + boost::shared_ptr px2(new X); + + BOOST_TEST(px.get() != px2.get()); + BOOST_TEST(px != px2); + BOOST_TEST(!(px == px2)); + BOOST_TEST(px < px2 || px2 < px); + BOOST_TEST(!(px < px2 && px2 < px)); + } + + { + boost::shared_ptr px(new X); + boost::shared_ptr px2(px); + + BOOST_TEST(px2 == px2); + BOOST_TEST(!(px2 != px2)); + BOOST_TEST(!(px2 < px2)); + + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(px == px2); + BOOST_TEST(!(px != px2)); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::shared_ptr px(new X); + boost::shared_ptr py(new Y); + boost::shared_ptr pz(new Z); + + BOOST_TEST(px.get() != pz.get()); + BOOST_TEST(px != pz); + BOOST_TEST(!(px == pz)); + + BOOST_TEST(py.get() != pz.get()); + BOOST_TEST(py != pz); + BOOST_TEST(!(py == pz)); + + BOOST_TEST(px < py || py < px); + BOOST_TEST(px < pz || pz < px); + BOOST_TEST(py < pz || pz < py); + + BOOST_TEST(!(px < py && py < px)); + BOOST_TEST(!(px < pz && pz < px)); + BOOST_TEST(!(py < pz && pz < py)); + + boost::shared_ptr pvx(px); + + BOOST_TEST(pvx == pvx); + BOOST_TEST(!(pvx != pvx)); + BOOST_TEST(!(pvx < pvx)); + + boost::shared_ptr pvy(py); + boost::shared_ptr pvz(pz); + + BOOST_TEST(pvx < pvy || pvy < pvx); + BOOST_TEST(pvx < pvz || pvz < pvx); + BOOST_TEST(pvy < pvz || pvz < pvy); + + BOOST_TEST(!(pvx < pvy && pvy < pvx)); + BOOST_TEST(!(pvx < pvz && pvz < pvx)); + BOOST_TEST(!(pvy < pvz && pvz < pvy)); + } + + { + boost::shared_ptr pz(new Z); + boost::shared_ptr px(pz); + + BOOST_TEST(px == px); + BOOST_TEST(!(px != px)); + BOOST_TEST(!(px < px)); + + boost::shared_ptr py(pz); + + BOOST_TEST(px.get() == pz.get()); + BOOST_TEST(px == pz); + BOOST_TEST(!(px != pz)); + + BOOST_TEST(py.get() == pz.get()); + BOOST_TEST(py == pz); + BOOST_TEST(!(py != pz)); + + BOOST_TEST(!(px < py || py < px)); + BOOST_TEST(!(px < pz || pz < px)); + BOOST_TEST(!(py < pz || pz < py)); + + boost::shared_ptr pvx(px); + boost::shared_ptr pvy(py); + boost::shared_ptr pvz(pz); + + // pvx and pvy aren't equal... + BOOST_TEST(pvx.get() != pvy.get()); + BOOST_TEST(pvx != pvy); + BOOST_TEST(!(pvx == pvy)); + + // ... but they share ownership ... + BOOST_TEST(!(pvx < pvy || pvy < pvx)); + + // ... with pvz + BOOST_TEST(!(pvx < pvz || pvz < pvx)); + BOOST_TEST(!(pvy < pvz || pvz < pvy)); + } +} + +} // namespace n_comparison + +namespace n_static_cast +{ + +struct X +{ +}; + +struct Y: public X +{ +}; + +void test() +{ + { + boost::shared_ptr pv; + + boost::shared_ptr pi = boost::static_pointer_cast(pv); + BOOST_TEST(pi.get() == 0); + + boost::shared_ptr px = boost::static_pointer_cast(pv); + BOOST_TEST(px.get() == 0); + } + + { + boost::shared_ptr pi(new int); + boost::shared_ptr pv(pi); + + boost::shared_ptr pi2 = boost::static_pointer_cast(pv); + BOOST_TEST(pi.get() == pi2.get()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); + BOOST_TEST(pi.use_count() == 3); + BOOST_TEST(pv.use_count() == 3); + BOOST_TEST(pi2.use_count() == 3); + } + + { + boost::shared_ptr px(new X); + boost::shared_ptr pv(px); + + boost::shared_ptr px2 = boost::static_pointer_cast(pv); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + BOOST_TEST(px.use_count() == 3); + BOOST_TEST(pv.use_count() == 3); + BOOST_TEST(px2.use_count() == 3); + } + + { + boost::shared_ptr px(new Y); + + boost::shared_ptr py = boost::static_pointer_cast(px); + BOOST_TEST(px.get() == py.get()); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(py.use_count() == 2); + + boost::shared_ptr px2(py); + BOOST_TEST(!(px < px2 || px2 < px)); + } +} + +} // namespace n_static_cast + +namespace n_const_cast +{ + +struct X; + +void test() +{ + { + boost::shared_ptr px; + + boost::shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px2.get() == 0); + } + + { + boost::shared_ptr px; + + boost::shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px2.get() == 0); + } + + { + boost::shared_ptr px; + + boost::shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px2.get() == 0); + } + + { + boost::shared_ptr px(new int); + + boost::shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(px2.use_count() == 2); + } + + { + boost::shared_ptr px(new int); + + boost::shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + BOOST_TEST(px.use_count() == 2); + BOOST_TEST(px2.use_count() == 2); + } +} + +} // namespace n_const_cast + +namespace n_dynamic_cast +{ + +struct V +{ + virtual ~V() {} +}; + +struct W: public V +{ +}; + +void test() +{ + { + boost::shared_ptr pv; + boost::shared_ptr pw = boost::dynamic_pointer_cast(pv); + BOOST_TEST(pw.get() == 0); + } + + { + boost::shared_ptr pv(static_cast(0)); + + boost::shared_ptr pw = boost::dynamic_pointer_cast(pv); + BOOST_TEST(pw.get() == 0); + + boost::shared_ptr pv2(pw); + BOOST_TEST(pv < pv2 || pv2 < pv); + } + + { + boost::shared_ptr pv(static_cast(0)); + + boost::shared_ptr pw = boost::dynamic_pointer_cast(pv); + BOOST_TEST(pw.get() == 0); + + boost::shared_ptr pv2(pw); + BOOST_TEST(pv < pv2 || pv2 < pv); + } + + { + boost::shared_ptr pv(new V); + + boost::shared_ptr pw = boost::dynamic_pointer_cast(pv); + BOOST_TEST(pw.get() == 0); + + boost::shared_ptr pv2(pw); + BOOST_TEST(pv < pv2 || pv2 < pv); + } + + { + boost::shared_ptr pv(new W); + + boost::shared_ptr pw = boost::dynamic_pointer_cast(pv); + BOOST_TEST(pw.get() == pv.get()); + BOOST_TEST(pv.use_count() == 2); + BOOST_TEST(pw.use_count() == 2); + + boost::shared_ptr pv2(pw); + BOOST_TEST(!(pv < pv2 || pv2 < pv)); + } +} + +} // namespace n_dynamic_cast + +namespace n_map +{ + +struct X +{ +}; + +void test() +{ + std::vector< boost::shared_ptr > vi; + + { + boost::shared_ptr pi1(new int); + boost::shared_ptr pi2(new int); + boost::shared_ptr pi3(new int); + + vi.push_back(pi1); + vi.push_back(pi1); + vi.push_back(pi1); + vi.push_back(pi2); + vi.push_back(pi1); + vi.push_back(pi2); + vi.push_back(pi1); + vi.push_back(pi3); + vi.push_back(pi3); + vi.push_back(pi2); + vi.push_back(pi1); + } + + std::vector< boost::shared_ptr > vx; + + { + boost::shared_ptr px1(new X); + boost::shared_ptr px2(new X); + boost::shared_ptr px3(new X); + + vx.push_back(px2); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px1); + vx.push_back(px1); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px3); + vx.push_back(px2); + } + + std::map< boost::shared_ptr, long > m; + + { + for(std::vector< boost::shared_ptr >::iterator i = vi.begin(); i != vi.end(); ++i) + { + ++m[*i]; + } + } + + { + for(std::vector< boost::shared_ptr >::iterator i = vx.begin(); i != vx.end(); ++i) + { + ++m[*i]; + } + } + + { + for(std::map< boost::shared_ptr, long >::iterator i = m.begin(); i != m.end(); ++i) + { + BOOST_TEST(i->first.use_count() == i->second + 1); + } + } +} + +} // namespace n_map + +namespace n_transitive +{ + +struct X +{ + X(): next() {} + boost::shared_ptr next; +}; + +void test() +{ + boost::shared_ptr p(new X); + p->next = boost::shared_ptr(new X); + BOOST_TEST(!p->next->next); + p = p->next; + BOOST_TEST(!p->next); +} + +} // namespace n_transitive + +namespace n_report_1 +{ + +class foo +{ +public: + + foo(): m_self(this) + { + } + + void suicide() + { + m_self.reset(); + } + +private: + + boost::shared_ptr m_self; +}; + +void test() +{ + foo * foo_ptr = new foo; + foo_ptr->suicide(); +} + +} // namespace n_report_1 + +// Test case by Per Kristensen +namespace n_report_2 +{ + +class foo +{ +public: + + void setWeak(boost::shared_ptr s) + { + w = s; + } + +private: + + boost::weak_ptr w; +}; + +class deleter +{ +public: + + deleter(): lock(0) + { + } + + ~deleter() + { + BOOST_TEST(lock == 0); + } + + void operator() (foo * p) + { + ++lock; + delete p; + --lock; + } + +private: + + int lock; +}; + +void test() +{ + boost::shared_ptr s(new foo, deleter()); + s->setWeak(s); + s.reset(); +} + +} // namespace n_report_2 + +namespace n_spt_incomplete +{ + +class file; + +boost::shared_ptr fopen(char const * name, char const * mode); +void fread(boost::shared_ptr f, void * data, long size); + +int file_instances = 0; + +void test() +{ + BOOST_TEST(file_instances == 0); + + { + boost::shared_ptr pf = fopen("name", "mode"); + BOOST_TEST(file_instances == 1); + fread(pf, 0, 17041); + } + + BOOST_TEST(file_instances == 0); +} + +} // namespace n_spt_incomplete + +namespace n_spt_pimpl +{ + +class file +{ +private: + + class impl; + boost::shared_ptr pimpl_; + +public: + + file(char const * name, char const * mode); + + // compiler generated members are fine and useful + + void read(void * data, long size); + + long total_size() const; +}; + +int file_instances = 0; + +void test() +{ + BOOST_TEST(file_instances == 0); + + { + file f("name", "mode"); + BOOST_TEST(file_instances == 1); + f.read(0, 152); + + file f2(f); + BOOST_TEST(file_instances == 1); + f2.read(0, 894); + + BOOST_TEST(f.total_size() == 152+894); + + { + file f3("name2", "mode2"); + BOOST_TEST(file_instances == 2); + } + + BOOST_TEST(file_instances == 1); + } + + BOOST_TEST(file_instances == 0); +} + +} // namespace n_spt_pimpl + +namespace n_spt_abstract +{ + +class X +{ +public: + + virtual void f(int) = 0; + virtual int g() = 0; + +protected: + + ~X() {} +}; + +boost::shared_ptr createX(); + +int X_instances = 0; + +void test() +{ + BOOST_TEST(X_instances == 0); + + { + boost::shared_ptr px = createX(); + + BOOST_TEST(X_instances == 1); + + px->f(18); + px->f(152); + + BOOST_TEST(px->g() == 170); + } + + BOOST_TEST(X_instances == 0); +} + +} // namespace n_spt_abstract + +namespace n_spt_preventing_delete +{ + +int X_instances = 0; + +class X +{ +private: + + X() + { + ++X_instances; + } + + ~X() + { + --X_instances; + } + + class deleter; + friend class deleter; + + class deleter + { + public: + + void operator()(X * p) { delete p; } + }; + +public: + + static boost::shared_ptr create() + { + boost::shared_ptr px(new X, X::deleter()); + return px; + } +}; + +void test() +{ + BOOST_TEST(X_instances == 0); + + { + boost::shared_ptr px = X::create(); + BOOST_TEST(X_instances == 1); + } + + BOOST_TEST(X_instances == 0); +} + +} // namespace n_spt_preventing_delete + +namespace n_spt_array +{ + +int X_instances = 0; + +struct X +{ + X() + { + ++X_instances; + } + + ~X() + { + --X_instances; + } +}; + +void test() +{ + BOOST_TEST(X_instances == 0); + + { + boost::shared_ptr px(new X[4], boost::checked_array_deleter()); + BOOST_TEST(X_instances == 4); + } + + BOOST_TEST(X_instances == 0); +} + +} // namespace n_spt_array + +namespace n_spt_static +{ + +class X +{ +public: + + X() + { + } + +private: + + void operator delete(void *) + { + // Comeau 4.3.0.1 wants a definition + BOOST_ERROR("n_spt_static::X::operator delete() called."); + } +}; + +struct null_deleter +{ + void operator()(void const *) const + { + } +}; + +static X x; + +void test() +{ + boost::shared_ptr px(&x, null_deleter()); +} + +} // namespace n_spt_static + +namespace n_spt_intrusive +{ + +int X_instances = 0; + +struct X +{ + long count; + + X(): count(0) + { + ++X_instances; + } + + ~X() + { + --X_instances; + } +}; + +void intrusive_ptr_add_ref(X * p) +{ + ++p->count; +} + +void intrusive_ptr_release(X * p) +{ + if(--p->count == 0) delete p; +} + +template struct intrusive_deleter +{ + void operator()(T * p) + { + if(p != 0) intrusive_ptr_release(p); + } +}; + +boost::shared_ptr make_shared_from_intrusive(X * p) +{ + if(p != 0) intrusive_ptr_add_ref(p); + boost::shared_ptr px(p, intrusive_deleter()); + return px; +} + +void test() +{ + BOOST_TEST(X_instances == 0); + + { + X * p = new X; + BOOST_TEST(X_instances == 1); + BOOST_TEST(p->count == 0); + boost::shared_ptr px = make_shared_from_intrusive(p); + BOOST_TEST(px.get() == p); + BOOST_TEST(p->count == 1); + boost::shared_ptr px2(px); + BOOST_TEST(px2.get() == p); + BOOST_TEST(p->count == 1); + } + + BOOST_TEST(X_instances == 0); +} + +} // namespace n_spt_intrusive + +namespace n_spt_another_sp +{ + +template class another_ptr: private boost::shared_ptr +{ +private: + + typedef boost::shared_ptr base_type; + +public: + + explicit another_ptr(T * p = 0): base_type(p) + { + } + + void reset() + { + base_type::reset(); + } + + T * get() const + { + return base_type::get(); + } +}; + +class event_handler +{ +public: + + virtual ~event_handler() {} + virtual void begin() = 0; + virtual void handle(int event) = 0; + virtual void end() = 0; +}; + +int begin_called = 0; +int handle_called = 0; +int end_called = 0; + +class event_handler_impl: public event_handler +{ +public: + + virtual void begin() + { + ++begin_called; + } + + virtual void handle(int event) + { + handle_called = event; + } + + virtual void end() + { + ++end_called; + } +}; + +another_ptr get_event_handler() +{ + another_ptr p(new event_handler_impl); + return p; +} + +boost::shared_ptr current_handler; + +void install_event_handler(boost::shared_ptr p) +{ + p->begin(); + current_handler = p; +} + +void handle_event(int event) +{ + current_handler->handle(event); +} + +void remove_event_handler() +{ + current_handler->end(); + current_handler.reset(); +} + +template class smart_pointer_deleter +{ +private: + + P p_; + +public: + + smart_pointer_deleter(P const & p): p_(p) + { + } + + void operator()(void const *) + { + p_.reset(); + } +}; + +void test() +{ + another_ptr p = get_event_handler(); + + boost::shared_ptr q(p.get(), smart_pointer_deleter< another_ptr >(p)); + + p.reset(); + + BOOST_TEST(begin_called == 0); + + install_event_handler(q); + + BOOST_TEST(begin_called == 1); + + BOOST_TEST(handle_called == 0); + + handle_event(17041); + + BOOST_TEST(handle_called == 17041); + + BOOST_TEST(end_called == 0); + + remove_event_handler(); + + BOOST_TEST(end_called == 1); +} + +} // namespace n_spt_another_sp + +namespace n_spt_shared_from_this +{ + +class X +{ +public: + + virtual void f() = 0; + +protected: + + ~X() {} +}; + +class Y +{ +public: + + virtual boost::shared_ptr getX() = 0; + +protected: + + ~Y() {} +}; + +class impl: public X, public Y +{ +private: + + boost::weak_ptr weak_this; + + impl(impl const &); + impl & operator=(impl const &); + + impl() {} + +public: + + static boost::shared_ptr create() + { + boost::shared_ptr pi(new impl); + pi->weak_this = pi; + return pi; + } + + virtual void f() {} + + virtual boost::shared_ptr getX() + { + boost::shared_ptr px = weak_this.lock(); + return px; + } +}; + +void test() +{ + boost::shared_ptr py = impl::create(); + BOOST_TEST(py.get() != 0); + BOOST_TEST(py.use_count() == 1); + + boost::shared_ptr px = py->getX(); + BOOST_TEST(px.get() != 0); + BOOST_TEST(py.use_count() == 2); + + boost::shared_ptr py2 = boost::dynamic_pointer_cast(px); + BOOST_TEST(py.get() == py2.get()); + BOOST_TEST(!(py < py2 || py2 < py)); + BOOST_TEST(py.use_count() == 3); +} + +} // namespace n_spt_shared_from_this + +namespace n_spt_wrap +{ + +void test() +{ +} + +} // namespace n_spt_wrap + +int main() +{ + n_element_type::test(); + n_constructors::test(); + n_assignment::test(); + n_reset::test(); + n_access::test(); + n_use_count::test(); + n_swap::test(); + n_comparison::test(); + n_static_cast::test(); + n_const_cast::test(); + n_dynamic_cast::test(); + + n_map::test(); + + n_transitive::test(); + n_report_1::test(); + n_report_2::test(); + + n_spt_incomplete::test(); + n_spt_pimpl::test(); + n_spt_abstract::test(); + n_spt_preventing_delete::test(); + n_spt_array::test(); + n_spt_static::test(); + n_spt_intrusive::test(); + n_spt_another_sp::test(); + n_spt_shared_from_this::test(); + n_spt_wrap::test(); + + return boost::report_errors(); +} + +namespace n_spt_incomplete +{ + +class file +{ +public: + + file(): fread_called(false) + { + ++file_instances; + } + + ~file() + { + BOOST_TEST(fread_called); + --file_instances; + } + + bool fread_called; +}; + +boost::shared_ptr fopen(char const *, char const *) +{ + boost::shared_ptr pf(new file); + return pf; +} + +void fread(boost::shared_ptr pf, void *, long) +{ + pf->fread_called = true; +} + +} // namespace n_spt_incomplete + +namespace n_spt_pimpl +{ + +class file::impl +{ +private: + + impl(impl const &); + impl & operator=(impl const &); + + long total_size_; + +public: + + impl(char const *, char const *): total_size_(0) + { + ++file_instances; + } + + ~impl() + { + --file_instances; + } + + void read(void *, long size) + { + total_size_ += size; + } + + long total_size() const + { + return total_size_; + } +}; + +file::file(char const * name, char const * mode): pimpl_(new impl(name, mode)) +{ +} + +void file::read(void * data, long size) +{ + pimpl_->read(data, size); +} + +long file::total_size() const +{ + return pimpl_->total_size(); +} + +} // namespace n_spt_pimpl + +namespace n_spt_abstract +{ + +class X_impl: public X +{ +private: + + X_impl(X_impl const &); + X_impl & operator=(X_impl const &); + + int n_; + +public: + + X_impl(): n_(0) + { + ++X_instances; + } + + ~X_impl() + { + --X_instances; + } + + virtual void f(int n) + { + n_ += n; + } + + virtual int g() + { + return n_; + } +}; + +boost::shared_ptr createX() +{ + boost::shared_ptr px(new X_impl); + return px; +} + +} // namespace n_spt_abstract diff --git a/test/shared_ptr_timing_test.cpp b/test/shared_ptr_timing_test.cpp new file mode 100644 index 0000000..79e62ff --- /dev/null +++ b/test/shared_ptr_timing_test.cpp @@ -0,0 +1,46 @@ +#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 +#endif + +// +// shared_ptr_timing_test.cpp - use to evaluate the impact of thread safety +// +// Copyright (c) 2002 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 +#include +#include +#include + +int const n = 8 * 1024 * 1024; + +int main() +{ + using namespace std; + + std::vector< boost::shared_ptr > v; + boost::shared_ptr pi(new int); + + clock_t t = clock(); + + for(int i = 0; i < n; ++i) + { + v.push_back(pi); + } + + t = clock() - t; + + std::cout << static_cast(t) / CLOCKS_PER_SEC << '\n'; + + return 0; +} diff --git a/test/smart_ptr_test.cpp b/test/smart_ptr_test.cpp new file mode 100644 index 0000000..8832deb --- /dev/null +++ b/test/smart_ptr_test.cpp @@ -0,0 +1,308 @@ +// smart pointer test program ----------------------------------------------// + +// Copyright Beman Dawes 1998, 1999. 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) + +// See http://www.boost.org/libs/smart_ptr for documentation. + +// Revision History +// 24 May 01 use Boost test library for error detection, reporting, add tests +// for operations on incomplete types (Beman Dawes) +// 29 Nov 99 added std::swap and associative container tests (Darin Adler) +// 25 Sep 99 added swap tests +// 20 Jul 99 header name changed to .hpp +// 20 Apr 99 additional error tests added. + +#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 + +#if (BOOST_MSVC >= 1310) +# pragma warning(disable: 4675) // resolved overload found with Koenig lookup +#endif + +#endif + +#ifdef __BORLANDC__ +# pragma warn -8092 // template argument passed to 'find' is not an iterator +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include + +class Incomplete; + +Incomplete * get_ptr( boost::shared_ptr& incomplete ) +{ + return incomplete.get(); +} + +template +void ck( const T* v1, T v2 ) { BOOST_TEST( *v1 == v2 ); } + +namespace { + int UDT_use_count; // independent of pointer maintained counts + } + +// user defined type -------------------------------------------------------// + +class UDT { + long value_; + public: + explicit UDT( long value=0 ) : value_(value) { ++UDT_use_count; } + ~UDT() { + --UDT_use_count; + std::cout << "UDT with value " << value_ << " being destroyed\n"; + } + long value() const { return value_; } + void value( long v ) { value_ = v;; } + }; // UDT + +// tests on incomplete types -----------------------------------------------// + +// Certain smart pointer operations are specified to work on incomplete types, +// and some uses depend upon this feature. These tests verify compilation +// only - the functions aren't actually invoked. + +class Incomplete; + +Incomplete * check_incomplete( boost::scoped_ptr& incomplete ) +{ + return incomplete.get(); +} + +Incomplete * check_incomplete( boost::shared_ptr& incomplete, + boost::shared_ptr& i2 ) +{ + incomplete.swap(i2); + std::cout << incomplete.use_count() << ' ' << incomplete.unique() << '\n'; + return incomplete.get(); +} + +// This isn't a very systematic test; it just hits some of the basics. + +void test() +{ + BOOST_TEST( UDT_use_count == 0 ); // reality check + + // test scoped_ptr with a built-in type + long * lp = new long; + boost::scoped_ptr sp ( lp ); + BOOST_TEST( sp.get() == lp ); + BOOST_TEST( lp == sp.get() ); + BOOST_TEST( &*sp == lp ); + + *sp = 1234568901L; + BOOST_TEST( *sp == 1234568901L ); + BOOST_TEST( *lp == 1234568901L ); + ck( static_cast(sp.get()), 1234568901L ); + ck( lp, *sp ); + + sp.reset(); + BOOST_TEST( sp.get() == 0 ); + + // test scoped_ptr with a user defined type + boost::scoped_ptr udt_sp ( new UDT( 999888777 ) ); + BOOST_TEST( udt_sp->value() == 999888777 ); + udt_sp.reset(); + udt_sp.reset( new UDT( 111222333 ) ); + BOOST_TEST( udt_sp->value() == 111222333 ); + udt_sp.reset( new UDT( 333222111 ) ); + BOOST_TEST( udt_sp->value() == 333222111 ); + + // test scoped_array with a build-in type + char * sap = new char [ 100 ]; + boost::scoped_array sa ( sap ); + BOOST_TEST( sa.get() == sap ); + BOOST_TEST( sap == sa.get() ); + + strcpy( sa.get(), "Hot Dog with mustard and relish" ); + BOOST_TEST( strcmp( sa.get(), "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( sap, "Hot Dog with mustard and relish" ) == 0 ); + + BOOST_TEST( sa[0] == 'H' ); + BOOST_TEST( sa[30] == 'h' ); + + sa[0] = 'N'; + sa[4] = 'd'; + BOOST_TEST( strcmp( sap, "Not dog with mustard and relish" ) == 0 ); + + sa.reset(); + BOOST_TEST( sa.get() == 0 ); + + // test shared_ptr with a built-in type + int * ip = new int; + boost::shared_ptr cp ( ip ); + BOOST_TEST( ip == cp.get() ); + BOOST_TEST( cp.use_count() == 1 ); + + *cp = 54321; + BOOST_TEST( *cp == 54321 ); + BOOST_TEST( *ip == 54321 ); + ck( static_cast(cp.get()), 54321 ); + ck( static_cast(ip), *cp ); + + boost::shared_ptr cp2 ( cp ); + BOOST_TEST( ip == cp2.get() ); + BOOST_TEST( cp.use_count() == 2 ); + BOOST_TEST( cp2.use_count() == 2 ); + + BOOST_TEST( *cp == 54321 ); + BOOST_TEST( *cp2 == 54321 ); + ck( static_cast(cp2.get()), 54321 ); + ck( static_cast(ip), *cp2 ); + + boost::shared_ptr cp3 ( cp ); + BOOST_TEST( cp.use_count() == 3 ); + BOOST_TEST( cp2.use_count() == 3 ); + BOOST_TEST( cp3.use_count() == 3 ); + cp.reset(); + BOOST_TEST( cp2.use_count() == 2 ); + BOOST_TEST( cp3.use_count() == 2 ); + cp.reset( new int ); + *cp = 98765; + BOOST_TEST( *cp == 98765 ); + *cp3 = 87654; + BOOST_TEST( *cp3 == 87654 ); + BOOST_TEST( *cp2 == 87654 ); + cp.swap( cp3 ); + BOOST_TEST( *cp == 87654 ); + BOOST_TEST( *cp2 == 87654 ); + BOOST_TEST( *cp3 == 98765 ); + cp.swap( cp3 ); + BOOST_TEST( *cp == 98765 ); + BOOST_TEST( *cp2 == 87654 ); + BOOST_TEST( *cp3 == 87654 ); + cp2 = cp2; + BOOST_TEST( cp2.use_count() == 2 ); + BOOST_TEST( *cp2 == 87654 ); + cp = cp2; + BOOST_TEST( cp2.use_count() == 3 ); + BOOST_TEST( *cp2 == 87654 ); + BOOST_TEST( cp.use_count() == 3 ); + BOOST_TEST( *cp == 87654 ); + +#if defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) + using boost::swap; +#endif + + boost::shared_ptr cp4; + swap( cp2, cp4 ); + BOOST_TEST( cp4.use_count() == 3 ); + BOOST_TEST( *cp4 == 87654 ); + BOOST_TEST( cp2.get() == 0 ); + + std::set< boost::shared_ptr > scp; + scp.insert(cp4); + BOOST_TEST( scp.find(cp4) != scp.end() ); + BOOST_TEST( scp.find(cp4) == scp.find( boost::shared_ptr(cp4) ) ); + + // test shared_array with a built-in type + char * cap = new char [ 100 ]; + boost::shared_array ca ( cap ); + BOOST_TEST( ca.get() == cap ); + BOOST_TEST( cap == ca.get() ); + BOOST_TEST( &ca[0] == cap ); + + strcpy( ca.get(), "Hot Dog with mustard and relish" ); + BOOST_TEST( strcmp( ca.get(), "Hot Dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( cap, "Hot Dog with mustard and relish" ) == 0 ); + + BOOST_TEST( ca[0] == 'H' ); + BOOST_TEST( ca[30] == 'h' ); + + boost::shared_array ca2 ( ca ); + boost::shared_array ca3 ( ca2 ); + + ca[0] = 'N'; + ca[4] = 'd'; + BOOST_TEST( strcmp( ca.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( ca2.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( strcmp( ca3.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( ca.use_count() == 3 ); + BOOST_TEST( ca2.use_count() == 3 ); + BOOST_TEST( ca3.use_count() == 3 ); + ca2.reset(); + BOOST_TEST( ca.use_count() == 2 ); + BOOST_TEST( ca3.use_count() == 2 ); + BOOST_TEST( ca2.use_count() == 1 ); + + ca.reset(); + BOOST_TEST( ca.get() == 0 ); + + boost::shared_array ca4; + swap( ca3, ca4 ); + BOOST_TEST( ca4.use_count() == 1 ); + BOOST_TEST( strcmp( ca4.get(), "Not dog with mustard and relish" ) == 0 ); + BOOST_TEST( ca3.get() == 0 ); + + std::set< boost::shared_array > sca; + sca.insert(ca4); + BOOST_TEST( sca.find(ca4) != sca.end() ); + BOOST_TEST( sca.find(ca4) == sca.find( boost::shared_array(ca4) ) ); + + // test shared_array with user defined type + boost::shared_array udta ( new UDT[3] ); + + udta[0].value( 111 ); + udta[1].value( 222 ); + udta[2].value( 333 ); + boost::shared_array udta2 ( udta ); + + BOOST_TEST( udta[0].value() == 111 ); + BOOST_TEST( udta[1].value() == 222 ); + BOOST_TEST( udta[2].value() == 333 ); + BOOST_TEST( udta2[0].value() == 111 ); + BOOST_TEST( udta2[1].value() == 222 ); + BOOST_TEST( udta2[2].value() == 333 ); + udta2.reset(); + BOOST_TEST( udta2.get() == 0 ); + BOOST_TEST( udta.use_count() == 1 ); + BOOST_TEST( udta2.use_count() == 1 ); + + BOOST_TEST( UDT_use_count == 4 ); // reality check + + // test shared_ptr with a user defined type + UDT * up = new UDT; + boost::shared_ptr sup ( up ); + BOOST_TEST( up == sup.get() ); + BOOST_TEST( sup.use_count() == 1 ); + + sup->value( 54321 ) ; + BOOST_TEST( sup->value() == 54321 ); + BOOST_TEST( up->value() == 54321 ); + + boost::shared_ptr sup2; + sup2 = sup; + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); + sup2 = sup2; + BOOST_TEST( sup2->value() == 54321 ); + BOOST_TEST( sup.use_count() == 2 ); + BOOST_TEST( sup2.use_count() == 2 ); + + std::cout << "OK\n"; + + new char[12345]; // deliberate memory leak to verify leaks detected +} + +int main() +{ + test(); + return boost::report_errors(); +} diff --git a/test/sp_atomic_mt2_test.cpp b/test/sp_atomic_mt2_test.cpp new file mode 100644 index 0000000..6a2e44e --- /dev/null +++ b/test/sp_atomic_mt2_test.cpp @@ -0,0 +1,247 @@ + +// Copyright (c) 2008 Peter Dimov +// +// 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 + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +// + +static void next_value( unsigned & v ) +{ + v = v % 2? 3 * v + 1: v / 2; +} + +struct X +{ + std::vector v_; + + explicit X( std::size_t n ): v_( n ) + { + for( std::size_t i = 0; i < n; ++i ) + { + v_[ i ] = i; + } + } + + unsigned get() const + { + return std::accumulate( v_.begin(), v_.end(), 0 ); + } + + void set() + { + std::for_each( v_.begin(), v_.end(), next_value ); + } +}; + +static boost::shared_ptr ps; + +static boost::detail::lightweight_mutex lm; +static boost::shared_mutex rw; + +enum prim_type +{ + pt_mutex, + pt_rwlock, + pt_atomics +}; + +int read_access( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + { + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + return ps->get(); + } + + case pt_rwlock: + { + boost::shared_lock lock( rw ); + return ps->get(); + } + + case pt_atomics: + { + boost::shared_ptr p2 = boost::atomic_load( &ps ); + return p2->get(); + } + } +} + +void write_access( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + { + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + ps->set(); + } + break; + + case pt_rwlock: + { + boost::unique_lock lock( rw ); + ps->set(); + } + break; + + case pt_atomics: + { + boost::shared_ptr p1 = boost::atomic_load( &ps ); + + for( ;; ) + { + boost::shared_ptr p2( new X( *p1 ) ); + p2->set(); + + if( boost::atomic_compare_exchange( &ps, &p1, p2 ) ) break; + } + } + break; + } +} + +void worker( int k, prim_type pt, int n, int r ) +{ + ++r; + + unsigned s = 0, nr = 0, nw = 0; + + for( int i = 0; i < n; ++i ) + { + if( i % r ) + { + s += read_access( pt ); + ++nr; + } + else + { + write_access( pt ); + ++s; + ++nw; + } + } + + printf( "Worker %2d: %u:%u, %10u\n", k, nr, nw, s ); +} + +#if defined( BOOST_HAS_PTHREADS ) + char const * thmodel = "POSIX"; +#else + char const * thmodel = "Windows"; +#endif + +char const * pt_to_string( prim_type pt ) +{ + switch( pt ) + { + case pt_mutex: + + return "mutex"; + + case pt_rwlock: + + return "rwlock"; + + case pt_atomics: + + return "atomics"; + } +} + +static void handle_pt_option( std::string const & opt, prim_type & pt, prim_type pt2 ) +{ + if( opt == pt_to_string( pt2 ) ) + { + pt = pt2; + } +} + +static void handle_int_option( std::string const & opt, std::string const & prefix, int & k, int kmin, int kmax ) +{ + if( opt.substr( 0, prefix.size() ) == prefix ) + { + int v = atoi( opt.substr( prefix.size() ).c_str() ); + + if( v >= kmin && v <= kmax ) + { + k = v; + } + } +} + +int main( int ac, char const * av[] ) +{ + using namespace std; // printf, clock_t, clock + + int m = 4; // threads + int n = 10000; // vector size + int k = 1000000; // iterations + int r = 100; // read/write ratio, r:1 + + prim_type pt = pt_atomics; + + for( int i = 1; i < ac; ++i ) + { + handle_pt_option( av[i], pt, pt_mutex ); + handle_pt_option( av[i], pt, pt_rwlock ); + handle_pt_option( av[i], pt, pt_atomics ); + + handle_int_option( av[i], "n=", n, 1, INT_MAX ); + handle_int_option( av[i], "size=", n, 1, INT_MAX ); + + handle_int_option( av[i], "k=", k, 1, INT_MAX ); + handle_int_option( av[i], "iterations=", k, 1, INT_MAX ); + + handle_int_option( av[i], "m=", m, 1, INT_MAX ); + handle_int_option( av[i], "threads=", m, 1, INT_MAX ); + + handle_int_option( av[i], "r=", r, 1, INT_MAX ); + handle_int_option( av[i], "ratio=", r, 1, INT_MAX ); + } + + printf( "%s: threads=%d size=%d iterations=%d ratio=%d %s\n\n", thmodel, m, n, k, r, pt_to_string( pt ) ); + + ps.reset( new X( n ) ); + + clock_t t = clock(); + + std::vector a( m ); + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( worker, i, pt, k, r ) ); + } + + for( int j = 0; j < m; ++j ) + { + pthread_join( a[ j ], 0 ); + } + + t = clock() - t; + + double ts = static_cast( t ) / CLOCKS_PER_SEC; + printf( "%.3f seconds, %.3f accesses per microsecond.\n", ts, m * k / ts / 1e+6 ); +} diff --git a/test/sp_atomic_mt_test.cpp b/test/sp_atomic_mt_test.cpp new file mode 100644 index 0000000..0f0bf68 --- /dev/null +++ b/test/sp_atomic_mt_test.cpp @@ -0,0 +1,191 @@ + +// Copyright (c) 2008 Peter Dimov +// +// 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 + +//#define USE_MUTEX +//#define USE_RWLOCK + +#include + +#include +#include + +#if defined( USE_RWLOCK ) +#include +#include +#endif + +#include +#include +#include + +#include +#include + +// + +int const n = 1024 * 1024; + +struct X +{ + int v_; // version + + unsigned a_; + unsigned b_; + + X(): v_( 0 ), a_( 1 ), b_( 1 ) + { + } + + int get() const + { + return a_ * 7 + b_ * 11; + } + + void set() + { + int tmp = get(); + + b_ = a_; + a_ = tmp; + + ++v_; + } +}; + +static boost::shared_ptr ps( new X ); + +static boost::detail::lightweight_mutex lm; + +#if defined( USE_RWLOCK ) +static boost::shared_mutex rw; +#endif + +static int tr = 0; + +void reader( int r ) +{ + int k = 0; + unsigned s = 0; + + for( int i = 0; i < n; ++k ) + { +#if defined( USE_MUTEX ) + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + + s += ps->get(); + + BOOST_TEST( ps->v_ >= i ); + i = ps->v_; + +#elif defined( USE_RWLOCK ) + + boost::shared_lock lock( rw ); + + s += ps->get(); + + BOOST_TEST( ps->v_ >= i ); + i = ps->v_; + +#else + + boost::shared_ptr p2 = boost::atomic_load( &ps ); + + s += p2->get(); + + BOOST_TEST( p2->v_ >= i ); + i = p2->v_; + +#endif + } + + printf( "Reader %d: %9d iterations (%6.3fx), %u\n", r, k, (double)k / n, s ); + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + tr += k; +} + +void writer() +{ + for( int i = 0; i < n; ++i ) + { +#if defined( USE_MUTEX ) + + boost::detail::lightweight_mutex::scoped_lock lock( lm ); + + BOOST_TEST( ps->v_ == i ); + ps->set(); + +#elif defined( USE_RWLOCK ) + + boost::unique_lock lock( rw ); + + BOOST_TEST( ps->v_ == i ); + ps->set(); + +#else + + boost::shared_ptr p2( new X( *ps ) ); + + BOOST_TEST( p2->v_ == i ); + p2->set(); + + boost::atomic_store( &ps, p2 ); + +#endif + } +} + +#if defined( BOOST_HAS_PTHREADS ) + char const * thmodel = "POSIX"; +#else + char const * thmodel = "Windows"; +#endif + +int const mr = 8; // reader threads +int const mw = 1; // writer thread + +#if defined( USE_MUTEX ) + char const * prim = "mutex"; +#elif defined( USE_RWLOCK ) + char const * prim = "rwlock"; +#else + char const * prim = "atomics"; +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf( "Using %s threads: %dR + %dW threads, %d iterations, %s\n\n", thmodel, mr, mw, n, prim ); + + clock_t t = clock(); + + pthread_t a[ mr+mw ]; + + for( int i = 0; i < mr; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( reader, i ) ); + } + + for( int i = mr; i < mr+mw; ++i ) + { + boost::detail::lw_thread_create( a[ i ], writer ); + } + + for( int j = 0; j < mr+mw; ++j ) + { + pthread_join( a[ j ], 0 ); + } + + t = clock() - t; + + double ts = static_cast( t ) / CLOCKS_PER_SEC; + printf( "%.3f seconds, %.3f reads per microsecond.\n", ts, tr / ts / 1e+6 ); + + return boost::report_errors(); +} diff --git a/test/sp_atomic_test.cpp b/test/sp_atomic_test.cpp new file mode 100644 index 0000000..c8c3586 --- /dev/null +++ b/test/sp_atomic_test.cpp @@ -0,0 +1,87 @@ +#include + +// sp_atomic_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +// + +struct X +{ +}; + +#define BOOST_TEST_SP_EQ( p, q ) BOOST_TEST( p == q && !( p < q ) && !( q < p ) ) + +int main() +{ + boost::shared_ptr px( new X ); + + { + boost::shared_ptr p2 = boost::atomic_load( &px ); + BOOST_TEST_SP_EQ( p2, px ); + + boost::shared_ptr px2( new X ); + boost::atomic_store( &px, px2 ); + BOOST_TEST_SP_EQ( px, px2 ); + + p2 = boost::atomic_load( &px ); + BOOST_TEST_SP_EQ( p2, px ); + BOOST_TEST_SP_EQ( p2, px2 ); + + boost::shared_ptr px3( new X ); + boost::shared_ptr p3 = boost::atomic_exchange( &px, px3 ); + BOOST_TEST_SP_EQ( p3, px2 ); + BOOST_TEST_SP_EQ( px, px3 ); + + boost::shared_ptr px4( new X ); + boost::shared_ptr cmp; + + bool r = boost::atomic_compare_exchange( &px, &cmp, px4 ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( px, px3 ); + BOOST_TEST_SP_EQ( cmp, px3 ); + + r = boost::atomic_compare_exchange( &px, &cmp, px4 ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( px, px4 ); + } + + // + + px.reset(); + + { + boost::shared_ptr p2 = boost::atomic_load_explicit( &px, boost::memory_order_acquire ); + BOOST_TEST_SP_EQ( p2, px ); + + boost::shared_ptr px2( new X ); + boost::atomic_store_explicit( &px, px2, boost::memory_order_release ); + BOOST_TEST_SP_EQ( px, px2 ); + + boost::shared_ptr p3 = boost::atomic_exchange_explicit( &px, boost::shared_ptr(), boost::memory_order_acq_rel ); + BOOST_TEST_SP_EQ( p3, px2 ); + BOOST_TEST_SP_EQ( px, p2 ); + + boost::shared_ptr px4( new X ); + boost::shared_ptr cmp( px2 ); + + bool r = boost::atomic_compare_exchange_explicit( &px, &cmp, px4, boost::memory_order_acquire, boost::memory_order_relaxed ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( px, p2 ); + BOOST_TEST_SP_EQ( cmp, p2 ); + + r = boost::atomic_compare_exchange_explicit( &px, &cmp, px4, boost::memory_order_release, boost::memory_order_acquire ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( px, px4 ); + } + + return boost::report_errors(); +} diff --git a/test/sp_convertible_test.cpp b/test/sp_convertible_test.cpp new file mode 100644 index 0000000..7f49e1f --- /dev/null +++ b/test/sp_convertible_test.cpp @@ -0,0 +1,71 @@ +#include + +// sp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +// + +class incomplete; + +struct X +{ +}; + +struct Y +{ +}; + +struct Z: public X +{ +}; + +int f( boost::shared_ptr ) +{ + return 1; +} + +int f( boost::shared_ptr ) +{ + return 2; +} + +int f( boost::shared_ptr ) +{ + return 3; +} + +int g( boost::shared_ptr ) +{ + return 4; +} + +int g( boost::shared_ptr ) +{ + return 5; +} + +int g( boost::shared_ptr ) +{ + return 6; +} + +int main() +{ + boost::shared_ptr p1; + BOOST_TEST( 1 == f( p1 ) ); + BOOST_TEST( 1 == f( boost::shared_ptr() ) ); + + boost::shared_ptr p2; + BOOST_TEST( 4 == g( p2 ) ); + BOOST_TEST( 4 == g( boost::shared_ptr() ) ); + + return boost::report_errors(); +} diff --git a/test/sp_recursive_assign2_rv_test.cpp b/test/sp_recursive_assign2_rv_test.cpp new file mode 100644 index 0000000..e450c72 --- /dev/null +++ b/test/sp_recursive_assign2_rv_test.cpp @@ -0,0 +1,114 @@ +// +// sp_recursive_assign2_rv_test.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +// + +class X +{ +public: + + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const& ); +}; + +int X::instances = 0; + +class Y +{ +public: + + static int instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y( Y const& ); +}; + +int Y::instances = 0; + +static boost::shared_ptr s_pv; + +class Z +{ +public: + + static int instances; + + Z() + { + ++instances; + } + + ~Z() + { + --instances; + s_pv = boost::shared_ptr( new Y ); + } + +private: + + Z( Z const& ); +}; + +int Z::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv = boost::shared_ptr( new Z ); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 1 ); + + s_pv = boost::shared_ptr( new X ); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv = boost::shared_ptr(); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/sp_recursive_assign2_test.cpp b/test/sp_recursive_assign2_test.cpp new file mode 100644 index 0000000..ef6fa52 --- /dev/null +++ b/test/sp_recursive_assign2_test.cpp @@ -0,0 +1,122 @@ +// +// sp_recursive_assign2_test.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +// + +class X +{ +public: + + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const& ); +}; + +int X::instances = 0; + +class Y +{ +public: + + static int instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y( Y const& ); +}; + +int Y::instances = 0; + +static boost::shared_ptr s_pv; + +class Z +{ +public: + + static int instances; + + Z() + { + ++instances; + } + + ~Z() + { + --instances; + + boost::shared_ptr pv( new Y ); + s_pv = pv; + } + +private: + + Z( Z const& ); +}; + +int Z::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + { + boost::shared_ptr pv( new Z ); + s_pv = pv; + } + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 1 ); + + { + boost::shared_ptr pv( new X ); + s_pv = pv; + } + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv.reset(); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/sp_recursive_assign_rv_test.cpp b/test/sp_recursive_assign_rv_test.cpp new file mode 100644 index 0000000..8d80e72 --- /dev/null +++ b/test/sp_recursive_assign_rv_test.cpp @@ -0,0 +1,114 @@ +// +// sp_recursive_assign_rv_test.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +// + +class X +{ +public: + + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const& ); +}; + +int X::instances = 0; + +class Y +{ +public: + + static int instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y( Y const& ); +}; + +int Y::instances = 0; + +static boost::shared_ptr s_pv; + +class Z +{ +public: + + static int instances; + + Z() + { + ++instances; + } + + ~Z() + { + --instances; + s_pv = boost::shared_ptr( new Y ); + } + +private: + + Z( Z const& ); +}; + +int Z::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv = boost::shared_ptr( new Z ); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 1 ); + + s_pv = boost::shared_ptr( new X ); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv = boost::shared_ptr(); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/sp_recursive_assign_test.cpp b/test/sp_recursive_assign_test.cpp new file mode 100644 index 0000000..0f36891 --- /dev/null +++ b/test/sp_recursive_assign_test.cpp @@ -0,0 +1,122 @@ +// +// sp_recursive_assign_test.cpp +// +// Copyright 2009 Peter Dimov +// +// 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 +#include + +// + +class X +{ +public: + + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const& ); +}; + +int X::instances = 0; + +class Y +{ +public: + + static int instances; + + Y() + { + ++instances; + } + + ~Y() + { + --instances; + } + +private: + + Y( Y const& ); +}; + +int Y::instances = 0; + +static boost::shared_ptr s_pv; + +class Z +{ +public: + + static int instances; + + Z() + { + ++instances; + } + + ~Z() + { + --instances; + + boost::shared_ptr pv( new Y ); + s_pv = pv; + } + +private: + + Z( Z const& ); +}; + +int Z::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + { + boost::shared_ptr pv( new Z ); + s_pv = pv; + } + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 1 ); + + { + boost::shared_ptr pv( new X ); + s_pv = pv; + } + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( Z::instances == 0 ); + + s_pv.reset(); + + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( Y::instances == 0 ); + BOOST_TEST( Z::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/sp_unary_addr_test.cpp b/test/sp_unary_addr_test.cpp new file mode 100644 index 0000000..a4007a2 --- /dev/null +++ b/test/sp_unary_addr_test.cpp @@ -0,0 +1,67 @@ +// +// sp_unary_addr_test.cpp +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include +#include + +struct deleter +{ +private: + + void operator& (); + void operator& () const; + +public: + + int data; + + deleter(): data( 17041 ) + { + } + + void operator()( void * ) + { + } +}; + +struct X +{ +}; + +int main() +{ + X x; + + { + boost::shared_ptr p( &x, deleter() ); + + deleter * q = boost::get_deleter( p ); + + BOOST_TEST( q != 0 ); + BOOST_TEST( q != 0 && q->data == 17041 ); + } + +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, < 1300 ) +#else + + { + boost::shared_ptr p( &x, deleter(), std::allocator() ); + + deleter * q = boost::get_deleter( p ); + + BOOST_TEST( q != 0 ); + BOOST_TEST( q != 0 && q->data == 17041 ); + } + +#endif + + return boost::report_errors(); +} diff --git a/test/spinlock_pool_test.cpp b/test/spinlock_pool_test.cpp new file mode 100644 index 0000000..53f61ca --- /dev/null +++ b/test/spinlock_pool_test.cpp @@ -0,0 +1,30 @@ +// +// spinlock_pool_test.cpp +// +// Copyright 2008 Peter Dimov +// +// 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 + +// Sanity check only + +int main() +{ + int x = 0; + + { + boost::detail::spinlock_pool<0>::scoped_lock lock( &x ); + ++x; + } + + { + boost::detail::spinlock_pool<1>::scoped_lock lock( &x ); + boost::detail::spinlock_pool<2>::scoped_lock lock2( &x ); + } + + return 0; +} diff --git a/test/spinlock_test.cpp b/test/spinlock_test.cpp new file mode 100644 index 0000000..d2c66c0 --- /dev/null +++ b/test/spinlock_test.cpp @@ -0,0 +1,31 @@ +// +// spinlock_test.cpp +// +// Copyright 2008 Peter Dimov +// +// 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 + +// Sanity check only + +static boost::detail::spinlock sp = BOOST_DETAIL_SPINLOCK_INIT; +static boost::detail::spinlock sp2 = BOOST_DETAIL_SPINLOCK_INIT; + +int main() +{ + sp.lock(); + sp2.lock(); + sp.unlock(); + sp2.unlock(); + + { + boost::detail::spinlock::scoped_lock lock( sp ); + boost::detail::spinlock::scoped_lock lock2( sp2 ); + } + + return 0; +} diff --git a/test/spinlock_try_test.cpp b/test/spinlock_try_test.cpp new file mode 100644 index 0000000..008b60e --- /dev/null +++ b/test/spinlock_try_test.cpp @@ -0,0 +1,46 @@ +// +// spinlock_try_test.cpp +// +// Copyright 2008 Peter Dimov +// +// 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 +#include + +// Sanity check only + +static boost::detail::spinlock sp = BOOST_DETAIL_SPINLOCK_INIT; +static boost::detail::spinlock sp2 = BOOST_DETAIL_SPINLOCK_INIT; + +int main() +{ + BOOST_TEST( sp.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( sp2.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + sp.lock(); + BOOST_TEST( !sp.try_lock() ); + sp2.lock(); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + { + boost::detail::spinlock::scoped_lock lock( sp ); + BOOST_TEST( !sp.try_lock() ); + boost::detail::spinlock::scoped_lock lock2( sp2 ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + } + + return boost::report_errors(); +} diff --git a/test/weak_ptr_move_test.cpp b/test/weak_ptr_move_test.cpp new file mode 100644 index 0000000..572b13d --- /dev/null +++ b/test/weak_ptr_move_test.cpp @@ -0,0 +1,121 @@ +// +// weak_ptr_move_test.cpp +// +// Copyright (c) 2007 Peter Dimov +// +// 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 +#include + +#if defined( BOOST_HAS_RVALUE_REFS ) + +struct X +{ + static long instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +long X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr p_( new X ); + boost::weak_ptr p( p_ ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.use_count() == 1 ); + + boost::weak_ptr p2( std::move( p ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p2.use_count() == 1 ); + BOOST_TEST( p.expired() ); + + boost::weak_ptr p3( std::move( p2 ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p3.use_count() == 1 ); + BOOST_TEST( p2.expired() ); + + p_.reset(); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( p3.expired() ); + } + + { + boost::shared_ptr p_( new X ); + boost::weak_ptr p( p_ ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.use_count() == 1 ); + + boost::weak_ptr p2; + p2 = static_cast< boost::weak_ptr && >( p ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p2.use_count() == 1 ); + BOOST_TEST( p.expired() ); + + boost::weak_ptr p3; + p3 = std::move( p2 ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p3.use_count() == 1 ); + BOOST_TEST( p2.expired() ); + + p_.reset(); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( p3.expired() ); + } + + { + boost::shared_ptr p_( new X ); + boost::weak_ptr p( p_ ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.use_count() == 1 ); + + boost::shared_ptr p_2( new X ); + boost::weak_ptr p2( p_2 ); + BOOST_TEST( X::instances == 2 ); + p2 = std::move( p ); + BOOST_TEST( X::instances == 2 ); + BOOST_TEST( p2.use_count() == 1 ); + BOOST_TEST( p.expired() ); + BOOST_TEST( p2.lock() != p_2 ); + + boost::shared_ptr p_3( new X ); + boost::weak_ptr p3( p_3 ); + BOOST_TEST( X::instances == 3 ); + p3 = std::move( p2 ); + BOOST_TEST( X::instances == 3 ); + BOOST_TEST( p3.use_count() == 1 ); + BOOST_TEST( p2.expired() ); + BOOST_TEST( p3.lock() != p_3 ); + } + + return boost::report_errors(); +} + +#else // !defined( BOOST_HAS_RVALUE_REFS ) + +int main() +{ + return 0; +} + +#endif diff --git a/test/weak_ptr_mt_test.cpp b/test/weak_ptr_mt_test.cpp new file mode 100644 index 0000000..04439e6 --- /dev/null +++ b/test/weak_ptr_mt_test.cpp @@ -0,0 +1,122 @@ +#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 +#endif + +// weak_ptr_mt_test.cpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright 2005, 2008 Peter Dimov +// +// 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 +#include +#include + +#include + +#include +#include +#include + +#include + +// + +int const n = 16384; +int const k = 512; // vector size +int const m = 16; // threads + +void test( std::vector< boost::shared_ptr > & v ) +{ + using namespace std; // printf, rand + + std::vector< boost::weak_ptr > w( v.begin(), v.end() ); + + int s = 0, f = 0, r = 0; + + for( int i = 0; i < n; ++i ) + { + // randomly kill a pointer + + v[ rand() % k ].reset(); + ++s; + + for( int j = 0; j < k; ++j ) + { + if( boost::shared_ptr px = w[ j ].lock() ) + { + ++s; + + if( rand() & 4 ) + { + continue; + } + + // rebind anyway with prob. 50% for add_ref_lock() against weak_release() contention + ++f; + } + else + { + ++r; + } + + w[ j ] = v[ rand() % k ]; + } + } + + printf( "\n%d locks, %d forced rebinds, %d normal rebinds.", s, f, r ); +} + +#if defined( BOOST_HAS_PTHREADS ) + +char const * thmodel = "POSIX"; + +#else + +char const * thmodel = "Windows"; + +#endif + +int main() +{ + using namespace std; // printf, clock_t, clock + + printf("Using %s threads: %d threads, %d * %d iterations: ", thmodel, m, n, k ); + + std::vector< boost::shared_ptr > v( k ); + + for( int i = 0; i < k; ++i ) + { + v[ i ].reset( new int( 0 ) ); + } + + clock_t t = clock(); + + pthread_t a[ m ]; + + for( int i = 0; i < m; ++i ) + { + boost::detail::lw_thread_create( a[ i ], boost::bind( test, v ) ); + } + + v.resize( 0 ); // kill original copies + + for( int j = 0; j < m; ++j ) + { + pthread_join( a[j], 0 ); + } + + t = clock() - t; + + printf("\n\n%.3f seconds.\n", static_cast(t) / CLOCKS_PER_SEC); + + return 0; +} diff --git a/test/weak_ptr_test.cpp b/test/weak_ptr_test.cpp new file mode 100644 index 0000000..7213794 --- /dev/null +++ b/test/weak_ptr_test.cpp @@ -0,0 +1,1368 @@ +#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 + +#if (BOOST_MSVC >= 1310) +#pragma warning(disable: 4675) // resolved overload found with Koenig lookup +#endif + +#endif + +// +// weak_ptr_test.cpp +// +// Copyright (c) 2002-2005 Peter Dimov +// +// 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 + +#include +#include + +#include +#include + +// + +namespace n_element_type +{ + +void f(int &) +{ +} + +void test() +{ + typedef boost::weak_ptr::element_type T; + T t; + f(t); +} + +} // namespace n_element_type + +class incomplete; + +boost::shared_ptr create_incomplete(); + +struct X +{ + int dummy; +}; + +struct Y +{ + int dummy2; +}; + +struct Z: public X, public virtual Y +{ +}; + +namespace n_constructors +{ + +void default_constructor() +{ + { + boost::weak_ptr wp; + BOOST_TEST(wp.use_count() == 0); + } + + { + boost::weak_ptr wp; + BOOST_TEST(wp.use_count() == 0); + } + + { + boost::weak_ptr wp; + BOOST_TEST(wp.use_count() == 0); + } +} + +void shared_ptr_constructor() +{ + { + boost::shared_ptr sp; + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + + boost::weak_ptr wp2(sp); + BOOST_TEST(wp2.use_count() == sp.use_count()); + } + + { + boost::shared_ptr sp(static_cast(0)); + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + } + + { + boost::shared_ptr sp(new int); + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + } + + { + boost::shared_ptr sp; + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + } + + { + boost::shared_ptr sp(static_cast(0)); + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + + { + boost::shared_ptr sp(new int); + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + + { + boost::shared_ptr sp; + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + + boost::weak_ptr wp2(sp); + BOOST_TEST(wp2.use_count() == sp.use_count()); + } + + { + boost::shared_ptr sp = create_incomplete(); + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + + { + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } + } + + { + boost::shared_ptr sp = create_incomplete(); + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == sp.use_count()); + BOOST_TEST(wp.use_count() == 1); + boost::shared_ptr sp2(wp); + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!(sp < sp2 || sp2 < sp)); + } +} + +void copy_constructor() +{ + { + boost::weak_ptr wp; + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::weak_ptr wp; + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::weak_ptr wp; + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::shared_ptr sp(static_cast(0)); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(new int); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(static_cast(0)); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(new int); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp = create_incomplete(); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } +} + +void conversion_constructor() +{ + { + boost::weak_ptr wp; + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::weak_ptr wp; + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::weak_ptr wp; + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 0); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + } + + { + boost::shared_ptr sp(static_cast(0)); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(new int); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp = create_incomplete(); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(static_cast(0)); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(static_cast(0)); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(new Z); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } + + { + boost::shared_ptr sp(new Z); + boost::weak_ptr wp(sp); + + boost::weak_ptr wp2(wp); + BOOST_TEST(wp2.use_count() == wp.use_count()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + sp.reset(); + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp3.use_count() == wp.use_count()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + } +} + +void test() +{ + default_constructor(); + shared_ptr_constructor(); + copy_constructor(); + conversion_constructor(); +} + +} // namespace n_constructors + +namespace n_assignment +{ + +template void copy_assignment(boost::shared_ptr & sp) +{ + BOOST_TEST(sp.unique()); + + boost::weak_ptr p1; + + p1 = p1; + BOOST_TEST(p1.use_count() == 0); + + boost::weak_ptr p2; + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + + boost::weak_ptr p3(p1); + + p1 = p3; + BOOST_TEST(p1.use_count() == 0); + + boost::weak_ptr p4(sp); + + p4 = p4; + BOOST_TEST(p4.use_count() == 1); + + p1 = p4; + BOOST_TEST(p1.use_count() == 1); + + p4 = p2; + BOOST_TEST(p4.use_count() == 0); + + sp.reset(); + + p1 = p1; + BOOST_TEST(p1.use_count() == 0); + + p4 = p1; + BOOST_TEST(p4.use_count() == 0); +} + +void conversion_assignment() +{ + { + boost::weak_ptr p1; + + boost::weak_ptr p2; + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + + boost::shared_ptr sp = create_incomplete(); + boost::weak_ptr p3(sp); + + p1 = p3; + BOOST_TEST(p1.use_count() == 1); + + sp.reset(); + + p1 = p3; + BOOST_TEST(p1.use_count() == 0); + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + } + + { + boost::weak_ptr p1; + + boost::weak_ptr p2; + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + + boost::shared_ptr sp(new Z); + boost::weak_ptr p3(sp); + + p1 = p3; + BOOST_TEST(p1.use_count() == 1); + + sp.reset(); + + p1 = p3; + BOOST_TEST(p1.use_count() == 0); + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + } + + { + boost::weak_ptr p1; + + boost::weak_ptr p2; + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + + boost::shared_ptr sp(new Z); + boost::weak_ptr p3(sp); + + p1 = p3; + BOOST_TEST(p1.use_count() == 1); + + sp.reset(); + + p1 = p3; + BOOST_TEST(p1.use_count() == 0); + + p1 = p2; + BOOST_TEST(p1.use_count() == 0); + } +} + +template void shared_ptr_assignment(boost::shared_ptr & sp, T * = 0) +{ + BOOST_TEST(sp.unique()); + + boost::weak_ptr p1; + boost::weak_ptr p2(p1); + boost::weak_ptr p3(sp); + boost::weak_ptr p4(p3); + + p1 = sp; + BOOST_TEST(p1.use_count() == 1); + + p2 = sp; + BOOST_TEST(p2.use_count() == 1); + + p3 = sp; + BOOST_TEST(p3.use_count() == 1); + + p4 = sp; + BOOST_TEST(p4.use_count() == 1); + + sp.reset(); + + BOOST_TEST(p1.use_count() == 0); + BOOST_TEST(p2.use_count() == 0); + BOOST_TEST(p3.use_count() == 0); + BOOST_TEST(p4.use_count() == 0); + + p1 = sp; +} + +void test() +{ + { + boost::shared_ptr p( new int ); + copy_assignment( p ); + } + + { + boost::shared_ptr p( new X ); + copy_assignment( p ); + } + + { + boost::shared_ptr p( new int ); + copy_assignment( p ); + } + + { + boost::shared_ptr p = create_incomplete(); + copy_assignment( p ); + } + + conversion_assignment(); + + { + boost::shared_ptr p( new int ); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p( new int ); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p( new X ); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p( new X ); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p( new int ); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p = create_incomplete(); + shared_ptr_assignment( p ); + } + + { + boost::shared_ptr p = create_incomplete(); + shared_ptr_assignment( p ); + } +} + +} // namespace n_assignment + +namespace n_reset +{ + +template void test2( boost::shared_ptr & sp, T * = 0 ) +{ + BOOST_TEST(sp.unique()); + + boost::weak_ptr p1; + boost::weak_ptr p2(p1); + boost::weak_ptr p3(sp); + boost::weak_ptr p4(p3); + boost::weak_ptr p5(sp); + boost::weak_ptr p6(p5); + + p1.reset(); + BOOST_TEST(p1.use_count() == 0); + + p2.reset(); + BOOST_TEST(p2.use_count() == 0); + + p3.reset(); + BOOST_TEST(p3.use_count() == 0); + + p4.reset(); + BOOST_TEST(p4.use_count() == 0); + + sp.reset(); + + p5.reset(); + BOOST_TEST(p5.use_count() == 0); + + p6.reset(); + BOOST_TEST(p6.use_count() == 0); +} + +void test() +{ + { + boost::shared_ptr p( new int ); + test2( p ); + } + + { + boost::shared_ptr p( new int ); + test2( p ); + } + + { + boost::shared_ptr p( new X ); + test2( p ); + } + + { + boost::shared_ptr p( new X ); + test2( p ); + } + + { + boost::shared_ptr p( new int ); + test2( p ); + } + + { + boost::shared_ptr p = create_incomplete(); + test2( p ); + } + + { + boost::shared_ptr p = create_incomplete(); + test2( p ); + } +} + +} // namespace n_reset + +namespace n_use_count +{ + +void test() +{ + { + boost::weak_ptr wp; + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp.expired()); + + boost::weak_ptr wp2; + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp.expired()); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp.expired()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(wp3.expired()); + } + + { + boost::shared_ptr sp(static_cast(0)); + + boost::weak_ptr wp(sp); + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(!wp.expired()); + + boost::weak_ptr wp2(sp); + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(!wp.expired()); + + boost::weak_ptr wp3(wp); + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(!wp.expired()); + BOOST_TEST(wp3.use_count() == 1); + BOOST_TEST(!wp3.expired()); + + boost::shared_ptr sp2(sp); + + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!wp.expired()); + BOOST_TEST(wp2.use_count() == 2); + BOOST_TEST(!wp2.expired()); + BOOST_TEST(wp3.use_count() == 2); + BOOST_TEST(!wp3.expired()); + + boost::shared_ptr sp3(sp); + + BOOST_TEST(wp.use_count() == 3); + BOOST_TEST(!wp.expired()); + BOOST_TEST(wp2.use_count() == 3); + BOOST_TEST(!wp2.expired()); + BOOST_TEST(wp3.use_count() == 3); + BOOST_TEST(!wp3.expired()); + + sp.reset(); + + BOOST_TEST(wp.use_count() == 2); + BOOST_TEST(!wp.expired()); + BOOST_TEST(wp2.use_count() == 2); + BOOST_TEST(!wp2.expired()); + BOOST_TEST(wp3.use_count() == 2); + BOOST_TEST(!wp3.expired()); + + sp2.reset(); + + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(!wp.expired()); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!wp2.expired()); + BOOST_TEST(wp3.use_count() == 1); + BOOST_TEST(!wp3.expired()); + + sp3.reset(); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp.expired()); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(wp2.expired()); + BOOST_TEST(wp3.use_count() == 0); + BOOST_TEST(wp3.expired()); + } +} + +} // namespace n_use_count + +namespace n_swap +{ + +void test() +{ + { + boost::weak_ptr wp; + boost::weak_ptr wp2; + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + } + + { + boost::shared_ptr sp(new X); + boost::weak_ptr wp; + boost::weak_ptr wp2(sp); + boost::weak_ptr wp3(sp); + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + + sp.reset(); + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + } + + { + boost::shared_ptr sp(new X); + boost::shared_ptr sp2(new X); + boost::weak_ptr wp(sp); + boost::weak_ptr wp2(sp2); + boost::weak_ptr wp3(sp2); + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + + sp.reset(); + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 1); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 1); + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + + sp2.reset(); + + wp.swap(wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + + using std::swap; + swap(wp, wp2); + + BOOST_TEST(wp.use_count() == 0); + BOOST_TEST(wp2.use_count() == 0); + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + } +} + +} // namespace n_swap + +namespace n_comparison +{ + +void test() +{ + { + boost::weak_ptr wp; + BOOST_TEST(!(wp < wp)); + + boost::weak_ptr wp2; + BOOST_TEST(!(wp < wp2 && wp2 < wp)); + + boost::weak_ptr wp3(wp); + BOOST_TEST(!(wp3 < wp3)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + } + + { + boost::shared_ptr sp(new X); + + boost::weak_ptr wp(sp); + BOOST_TEST(!(wp < wp)); + + boost::weak_ptr wp2; + BOOST_TEST(wp < wp2 || wp2 < wp); + BOOST_TEST(!(wp < wp2 && wp2 < wp)); + + bool b1 = wp < wp2; + bool b2 = wp2 < wp; + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(wp2 < wp3 || wp3 < wp2); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(wp4 < wp3 || wp3 < wp4); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + + sp.reset(); + + BOOST_TEST(b1 == (wp < wp2)); + BOOST_TEST(b2 == (wp2 < wp)); + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(wp2 < wp3 || wp3 < wp2); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(wp4 < wp3 || wp3 < wp4); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + } + + { + boost::shared_ptr sp(new X); + boost::shared_ptr sp2(new X); + + boost::weak_ptr wp(sp); + boost::weak_ptr wp2(sp2); + + BOOST_TEST(wp < wp2 || wp2 < wp); + BOOST_TEST(!(wp < wp2 && wp2 < wp)); + + bool b1 = wp < wp2; + bool b2 = wp2 < wp; + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(wp2 < wp3 || wp3 < wp2); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(wp4 < wp3 || wp3 < wp4); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + + sp.reset(); + + BOOST_TEST(b1 == (wp < wp2)); + BOOST_TEST(b2 == (wp2 < wp)); + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(wp2 < wp3 || wp3 < wp2); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(wp4 < wp3 || wp3 < wp4); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + + sp2.reset(); + + BOOST_TEST(b1 == (wp < wp2)); + BOOST_TEST(b2 == (wp2 < wp)); + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(wp2 < wp3 || wp3 < wp2); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(wp4 < wp3 || wp3 < wp4); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + } + + { + boost::shared_ptr sp(new X); + boost::shared_ptr sp2(sp); + + boost::weak_ptr wp(sp); + boost::weak_ptr wp2(sp2); + + BOOST_TEST(!(wp < wp2 || wp2 < wp)); + BOOST_TEST(!(wp < wp2 && wp2 < wp)); + + bool b1 = wp < wp2; + bool b2 = wp2 < wp; + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(!(wp4 < wp3 || wp3 < wp4)); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + + sp.reset(); + sp2.reset(); + + BOOST_TEST(b1 == (wp < wp2)); + BOOST_TEST(b2 == (wp2 < wp)); + + { + boost::weak_ptr wp3(wp); + + BOOST_TEST(!(wp < wp3 || wp3 < wp)); + BOOST_TEST(!(wp < wp3 && wp3 < wp)); + + BOOST_TEST(!(wp2 < wp3 || wp3 < wp2)); + BOOST_TEST(!(wp2 < wp3 && wp3 < wp2)); + + boost::weak_ptr wp4(wp2); + + BOOST_TEST(!(wp4 < wp3 || wp3 < wp4)); + BOOST_TEST(!(wp4 < wp3 && wp3 < wp4)); + } + } + + { + boost::shared_ptr spx(new X); + boost::shared_ptr spy(new Y); + boost::shared_ptr spz(new Z); + + boost::weak_ptr px(spx); + boost::weak_ptr py(spy); + boost::weak_ptr pz(spz); + + BOOST_TEST(px < py || py < px); + BOOST_TEST(px < pz || pz < px); + BOOST_TEST(py < pz || pz < py); + + BOOST_TEST(!(px < py && py < px)); + BOOST_TEST(!(px < pz && pz < px)); + BOOST_TEST(!(py < pz && pz < py)); + + boost::weak_ptr pvx(px); + BOOST_TEST(!(pvx < pvx)); + + boost::weak_ptr pvy(py); + BOOST_TEST(!(pvy < pvy)); + + boost::weak_ptr pvz(pz); + BOOST_TEST(!(pvz < pvz)); + + BOOST_TEST(pvx < pvy || pvy < pvx); + BOOST_TEST(pvx < pvz || pvz < pvx); + BOOST_TEST(pvy < pvz || pvz < pvy); + + BOOST_TEST(!(pvx < pvy && pvy < pvx)); + BOOST_TEST(!(pvx < pvz && pvz < pvx)); + BOOST_TEST(!(pvy < pvz && pvz < pvy)); + + spx.reset(); + spy.reset(); + spz.reset(); + + BOOST_TEST(px < py || py < px); + BOOST_TEST(px < pz || pz < px); + BOOST_TEST(py < pz || pz < py); + + BOOST_TEST(!(px < py && py < px)); + BOOST_TEST(!(px < pz && pz < px)); + BOOST_TEST(!(py < pz && pz < py)); + + BOOST_TEST(!(pvx < pvx)); + BOOST_TEST(!(pvy < pvy)); + BOOST_TEST(!(pvz < pvz)); + + BOOST_TEST(pvx < pvy || pvy < pvx); + BOOST_TEST(pvx < pvz || pvz < pvx); + BOOST_TEST(pvy < pvz || pvz < pvy); + + BOOST_TEST(!(pvx < pvy && pvy < pvx)); + BOOST_TEST(!(pvx < pvz && pvz < pvx)); + BOOST_TEST(!(pvy < pvz && pvz < pvy)); + } + + { + boost::shared_ptr spz(new Z); + boost::shared_ptr spx(spz); + + boost::weak_ptr pz(spz); + boost::weak_ptr px(spx); + boost::weak_ptr py(spz); + + BOOST_TEST(!(px < px)); + BOOST_TEST(!(py < py)); + + BOOST_TEST(!(px < py || py < px)); + BOOST_TEST(!(px < pz || pz < px)); + BOOST_TEST(!(py < pz || pz < py)); + + boost::weak_ptr pvx(px); + boost::weak_ptr pvy(py); + boost::weak_ptr pvz(pz); + + BOOST_TEST(!(pvx < pvy || pvy < pvx)); + BOOST_TEST(!(pvx < pvz || pvz < pvx)); + BOOST_TEST(!(pvy < pvz || pvz < pvy)); + + spx.reset(); + spz.reset(); + + BOOST_TEST(!(px < px)); + BOOST_TEST(!(py < py)); + + BOOST_TEST(!(px < py || py < px)); + BOOST_TEST(!(px < pz || pz < px)); + BOOST_TEST(!(py < pz || pz < py)); + + BOOST_TEST(!(pvx < pvy || pvy < pvx)); + BOOST_TEST(!(pvx < pvz || pvz < pvx)); + BOOST_TEST(!(pvy < pvz || pvz < pvy)); + } +} + +} // namespace n_comparison + +namespace n_lock +{ + +void test() +{ +} + +} // namespace n_lock + +namespace n_map +{ + +void test() +{ + std::vector< boost::shared_ptr > vi; + + { + boost::shared_ptr pi1(new int); + boost::shared_ptr pi2(new int); + boost::shared_ptr pi3(new int); + + vi.push_back(pi1); + vi.push_back(pi1); + vi.push_back(pi1); + vi.push_back(pi2); + vi.push_back(pi1); + vi.push_back(pi2); + vi.push_back(pi1); + vi.push_back(pi3); + vi.push_back(pi3); + vi.push_back(pi2); + vi.push_back(pi1); + } + + std::vector< boost::shared_ptr > vx; + + { + boost::shared_ptr px1(new X); + boost::shared_ptr px2(new X); + boost::shared_ptr px3(new X); + + vx.push_back(px2); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px1); + vx.push_back(px1); + vx.push_back(px2); + vx.push_back(px1); + vx.push_back(px3); + vx.push_back(px2); + } + + std::map< boost::weak_ptr, long > m; + + { + for(std::vector< boost::shared_ptr >::iterator i = vi.begin(); i != vi.end(); ++i) + { + ++m[*i]; + } + } + + { + for(std::vector< boost::shared_ptr >::iterator i = vx.begin(); i != vx.end(); ++i) + { + ++m[*i]; + } + } + + { + for(std::map< boost::weak_ptr, long >::iterator i = m.begin(); i != m.end(); ++i) + { + BOOST_TEST(i->first.use_count() == i->second); + } + } +} + +} // namespace n_map + +int main() +{ + n_element_type::test(); + n_constructors::test(); + n_assignment::test(); + n_reset::test(); + n_use_count::test(); + n_swap::test(); + n_comparison::test(); + n_lock::test(); + + n_map::test(); + + return boost::report_errors(); +} + +class incomplete +{ +}; + +boost::shared_ptr create_incomplete() +{ + boost::shared_ptr px(new incomplete); + return px; +} diff --git a/test/weak_ptr_timing_test.cpp b/test/weak_ptr_timing_test.cpp new file mode 100644 index 0000000..1c24b0a --- /dev/null +++ b/test/weak_ptr_timing_test.cpp @@ -0,0 +1,85 @@ +#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 +#endif + +// +// weak_ptr_timing_test.cpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright 2005 Peter Dimov +// +// 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 +#include + +#include +#include +#include +#include + +// + +int const n = 29000; +int const k = 2048; + +void test( std::vector< boost::shared_ptr > & v ) +{ + using namespace std; // printf, rand + + std::vector< boost::weak_ptr > w( v.begin(), v.end() ); + + int s = 0, r = 0; + + for( int i = 0; i < n; ++i ) + { + // randomly kill a pointer + + v[ rand() % k ].reset(); + + for( int j = 0; j < k; ++j ) + { + if( boost::shared_ptr px = w[ j ].lock() ) + { + ++s; + } + else + { + ++r; + w[ j ] = v[ rand() % k ]; + } + } + } + + printf( "\n%d locks, %d rebinds.", s, r ); +} + +int main() +{ + using namespace std; // printf, clock_t, clock + + std::vector< boost::shared_ptr > v( k ); + + for( int i = 0; i < k; ++i ) + { + v[ i ].reset( new int( 0 ) ); + } + + clock_t t = clock(); + + test( v ); + + t = clock() - t; + + printf( "\n\n%.3f seconds.\n", static_cast( t ) / CLOCKS_PER_SEC ); + + return 0; +} diff --git a/test/wp_convertible_test.cpp b/test/wp_convertible_test.cpp new file mode 100644 index 0000000..cceacda --- /dev/null +++ b/test/wp_convertible_test.cpp @@ -0,0 +1,68 @@ +#include + +// wp_convertible_test.cpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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 +#include + +// + +class incomplete; + +struct X +{ +}; + +struct Y +{ +}; + +struct Z: public X +{ +}; + +int f( boost::weak_ptr ) +{ + return 1; +} + +int f( boost::weak_ptr ) +{ + return 2; +} + +int f( boost::weak_ptr ) +{ + return 3; +} + +int g( boost::weak_ptr ) +{ + return 4; +} + +int g( boost::weak_ptr ) +{ + return 5; +} + +int g( boost::weak_ptr ) +{ + return 6; +} + +int main() +{ + BOOST_TEST( 1 == f( boost::weak_ptr() ) ); + BOOST_TEST( 1 == f( boost::shared_ptr() ) ); + BOOST_TEST( 4 == g( boost::weak_ptr() ) ); + BOOST_TEST( 4 == g( boost::shared_ptr() ) ); + + return boost::report_errors(); +} diff --git a/test/yield_k_test.cpp b/test/yield_k_test.cpp new file mode 100644 index 0000000..593c13d --- /dev/null +++ b/test/yield_k_test.cpp @@ -0,0 +1,23 @@ +// +// yield_k_test.cpp +// +// Copyright 2008 Peter Dimov +// +// 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 + +// Sanity check only + +int main() +{ + for( unsigned k = 0; k < 256; ++k ) + { + boost::detail::yield( k ); + } + + return 0; +} diff --git a/weak_ptr.htm b/weak_ptr.htm new file mode 100644 index 0000000..0fa87f7 --- /dev/null +++ b/weak_ptr.htm @@ -0,0 +1,242 @@ + + + + weak_ptr + + + +

boost.png (6897 bytes)weak_ptr class template

+

Introduction
+ Synopsis
+ Members
+ Free Functions
+ Frequently Asked Questions +

+

Introduction

+

The weak_ptr class template stores a "weak reference" to an object that's + already managed by a shared_ptr. To access the object, a weak_ptr + can be converted to a shared_ptr using + the shared_ptr constructor or the member function + lock. When the last shared_ptr to the object goes + away and the object is deleted, the attempt to obtain a shared_ptr + from the weak_ptr instances that refer to the deleted object will fail: + the constructor will throw an exception of type boost::bad_weak_ptr, + and weak_ptr::lock will return an empty shared_ptr.

+

Every weak_ptr meets the CopyConstructible and Assignable requirements + of the C++ Standard Library, and so can be used in standard library containers. + Comparison operators are supplied so that weak_ptr works with the + standard library's associative containers.

+

weak_ptr operations never throw exceptions.

+

The class template is parameterized on T, the type of the object pointed + to.

+

Compared to shared_ptr, weak_ptr provides a + very limited subset of operations since accessing its stored pointer is often + dangerous in multithreaded programs, and sometimes unsafe even within a single + thread (that is, it may invoke undefined behavior.) Pretend for a moment that weak_ptr + has a get member function that returns a raw pointer, and consider this + innocent piece of code:

+
shared_ptr<int> p(new int(5));
+weak_ptr<int> q(p);
+
+// some time later
+
+if(int * r = q.get())
+{
+    // use *r
+}
+
+

Imagine that after the if, but immediately before r + is used, another thread executes the statement p.reset(). Now r + is a dangling pointer.

+

The solution to this problem is to create a temporary shared_ptr + from q:

+
shared_ptr<int> p(new int(5));
+weak_ptr<int> q(p);
+
+// some time later
+
+if(shared_ptr<int> r = q.lock())
+{
+    // use *r
+}
+
+

Now r holds a reference to the object that was pointed by q. + Even if p.reset() is executed in another thread, the object will + stay alive until r goes out of scope or is reset. By obtaining + a shared_ptr to the object, we have effectively locked it + against destruction.

+

Synopsis

+
namespace boost {
+
+  template<class T> class weak_ptr {
+
+    public:
+      typedef T element_type;
+
+      weak_ptr();
+
+      template<class Y> weak_ptr(shared_ptr<Y> const & r);
+      weak_ptr(weak_ptr const & r);
+      template<class Y> weak_ptr(weak_ptr<Y> const & r);
+
+      ~weak_ptr();
+
+      weak_ptr & operator=(weak_ptr const & r);
+      template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r);
+      template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r);
+
+      long use_count() const;
+      bool expired() const;
+      shared_ptr<T> lock() const;
+
+      void reset();
+      void swap(weak_ptr<T> & b);
+  };
+
+  template<class T, class U>
+    bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
+
+  template<class T>
+    void swap(weak_ptr<T> & a, weak_ptr<T> & b);
+}
+
+

Members

+

element_type

+
typedef T element_type;
+
+

Provides the type of the template parameter T.

+
+

constructors

+
weak_ptr();
+
+

Effects: Constructs an empty weak_ptr.

+

Postconditions: use_count() == 0.

+

Throws: nothing.

+
+
template<class Y> weak_ptr(shared_ptr<Y> const & r);
+weak_ptr(weak_ptr const & r);
+template<class Y> weak_ptr(weak_ptr<Y> const & r);
+
+

Effects: If r is empty, constructs an empty + weak_ptr; otherwise, constructs a weak_ptr that shares + ownership with r as if by storing a copy of the + pointer stored in r.

+

Postconditions: use_count() == r.use_count().

+

Throws: nothing.

+
+

destructor

+
~weak_ptr();
+
+

Effects: Destroys this weak_ptr but has no effect on the object + its stored pointer points to.

+

Throws: nothing.

+
+

assignment

+
weak_ptr & operator=(weak_ptr const & r);
+template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r);
+template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r);
+
+

Effects: Equivalent to weak_ptr(r).swap(*this).

+

Throws: nothing.

+

Notes: The implementation is free to meet the effects (and the implied + guarantees) via different means, without creating a temporary.

+
+

use_count

+
long use_count() const;
+
+

Returns: 0 if *this is empty; otherwise, the + number of shared_ptr objects that share ownership with *this.

+

Throws: nothing.

+

Notes: use_count() is not necessarily efficient. Use only + for debugging and testing purposes, not for production code.

+
+

expired

+
bool expired() const;
+
+

Returns: use_count() == 0.

+

Throws: nothing.

+

Notes: expired() may be faster than use_count().

+
+

lock

+
shared_ptr<T> lock() const;
+
+

Returns: expired()? shared_ptr<T>(): shared_ptr<T>(*this).

+

Throws: nothing.

+
+

reset

+
void reset();
+
+

Effects: Equivalent to weak_ptr().swap(*this).

+
+

swap

+
void swap(weak_ptr & b);
+
+

Effects: Exchanges the contents of the two smart pointers.

+

Throws: nothing.

+
+

Free Functions

+

comparison

+
template<class T, class U>
+  bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
+
+

Returns: an unspecified value such that

+
    +
  • + operator< is a strict weak ordering as described in section 25.3 [lib.alg.sorting] + of the C++ standard; +
  • + under the equivalence relation defined by operator<, !(a + < b) && !(b < a), two weak_ptr instances + are equivalent if and only if they share ownership or are both empty.
+

Throws: nothing.

+

Notes: Allows weak_ptr objects to be used as keys in + associative containers.

+
+

swap

+
template<class T>
+  void swap(weak_ptr<T> & a, weak_ptr<T> & b)
+
+

Effects: Equivalent to a.swap(b).

+

Throws: nothing.

+

Notes: Matches the interface of std::swap. Provided as an aid to + generic programming.

+
+

Frequently Asked Questions

+

Q. Can an object create a weak_ptr to itself in its + constructor?

+

A. No. A weak_ptr can only be created from a shared_ptr, + and at object construction time no shared_ptr to the object + exists yet. Even if you could create a temporary shared_ptr to + this, it would go out of scope at the end of the constructor, and + all weak_ptr instances would instantly expire.

+

The solution is to make the constructor private, and supply a factory function + that returns a shared_ptr:
+

+
+class X
+{
+private:
+
+    X();
+
+public:
+
+    static shared_ptr<X> create()
+    {
+        shared_ptr<X> px(new X);
+        // create weak pointers from px here
+        return px;
+    }
+};
+
+


+

+
+

$Date$

+

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. + Copyright 2002-2005 Peter Dimov. 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.

+ +