intrusive_ptr_object.hpp

//
// Copyright (c) 2006 Alexis Wilke and Doug Barbieri
//
// Boost Software License - Version 1.0 - August 17th, 2003
// 
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#ifndef BOOST_INTRUSIVE_PTR_OBJECT
#define	BOOST_INTRUSIVE_PTR_OBJECT 1

#include	
#include	
// avoid thread overhead if not required/available
#if defined(BOOST_HAS_THREADS)
#include	
#endif

// place these in the boost namespace so the intrusive_ptr<> template
// finds the intrusive_ptr_add_ref() and intrusive_ptr_release() functions
// whatever the compiler. (see the boost::intrusive_ptr documentation)
//
//	http://www.boost.org/libs/smart_ptr/intrusive_ptr.html
//
namespace boost
{




// objects are derived last from this class; this way they
// can be reference counted
class intrusive_ptr_object
{
public:
	intrusive_ptr_object() throw()
		: m_ref_count(0)
	{
	}
	virtual ~intrusive_ptr_object() = 0;

	void add_ref()
	{
#if defined(BOOST_HAS_THREADS)
		mutex::scoped_lock lock(m_mutex);
#endif
		++m_ref_count;
	}
	void release()
	{
#if defined(BOOST_HAS_THREADS)
		mutex::scoped_lock lock(m_mutex);
#endif
		// since users should not call release() themselves but use
		// the intrusive_ptr<> template instead, this should never happen
		BOOST_ASSERT(m_ref_count != 0);
		--m_ref_count;
		if(m_ref_count == 0) {
			delete this;
		}
	}

private:
	unsigned int	m_ref_count;
#if defined(BOOST_HAS_THREADS)
	mutex		m_mutex;
#endif
};


inline intrusive_ptr_object::~intrusive_ptr_object()
{
	// a stack object will be deleted without a release() call...
	// if you use objects properly, this should never happen!
	BOOST_ASSERT(m_ref_count == 0);
}



// All your classes derive from this class to allow for the
// dynamic_cast<> in the intrusive_ptr_add_ref() and
// intrusive_ptr_release() functions.
class intrusive_ptr_base
{
public:
	// cannot instantiate
	virtual ~intrusive_ptr_base() = 0;
};

inline intrusive_ptr_base::~intrusive_ptr_base()
{
}


inline void intrusive_ptr_add_ref(intrusive_ptr_base *a)
{
	dynamic_cast(a)->add_ref();
}


inline void intrusive_ptr_release(intrusive_ptr_base *a)
{
	dynamic_cast(a)->release();
}



// the classes you want to allocate with new and manage with
// an intrusive_ptr<> template are typedef with this template
// first, i.e.
//
//   class A;
//   typedef intrusive_ptr_heap A_heap;
//
template class intrusive_ptr_heap : public T, public intrusive_ptr_object {};

}	// namespace boost


#endif // #ifdef BOOST_INTRUSIVE_PTR_OBJECT
// vim: ts=4