/* === E T L =============================================================== */
/*!	\file _handle.h
**	$Id$
**	\brief Template Object Handle Implementation
**	\internal
**
**	\legal
**	Copyright (c) 2002 Robert B. Quattlebaum Jr.
**	Copyright (c) 2007, 2008 Chris Moore
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**	General Public License for more details.
**	\endlegal
**
**	\note
**		This is an internal header file, included by other ETL headers.
**		You should not attempt to use it directly.
*/
/* ========================================================================= */

/* === S T A R T =========================================================== */

#ifndef __ETL__HANDLE_H
#define __ETL__HANDLE_H

/* === H E A D E R S ======================================================= */

#include <cassert>
#include <typeinfo>
#include <atomic>

/* === M A C R O S ========================================================= */

/* === T Y P E D E F S ===================================================== */

#define ETL_SELF_DELETING_SHARED_OBJECT

/* === C L A S S E S & S T R U C T S ======================================= */

namespace etl {

// Forward Declarations
template <class T> class handle;
template <class T> class loose_handle;
template <class T> class rhandle;


// ========================================================================
/*!	\class	shared_object _handle.h	ETL/handle
**	\brief	Shared Object Base Class
**	\see handle, loose_handle
**	\writeme
*/
class shared_object
{
private:
	mutable std::atomic<int> refcount;

protected:
	shared_object():refcount(0) { }
	shared_object(const shared_object&):refcount(0) { }
	shared_object& operator= (const shared_object&) { return *this; }

#ifdef ETL_SELF_DELETING_SHARED_OBJECT
	virtual ~shared_object() { }
#else
	~shared_object() { }
#endif

public:
	virtual void ref()const
	{
		++refcount;
	}

	//! Returns \c false if object needs to be deleted
	virtual bool unref()const
	{
		bool ret = (bool)(--refcount);
#ifdef ETL_SELF_DELETING_SHARED_OBJECT
		if (!ret)
			delete this;
#endif
		return ret;
	}

	//! Decrease reference counter without deletion of object
	//! Returns \c false if references exceed and object should be deleted
	virtual bool unref_inactive()const
	{
		return (bool)(--refcount);
	}

	int count()const { return refcount; }

}; // END of class shared_object

// ========================================================================
/*!	\class	virtual_shared_object _handle.h	ETL/handle
**	\brief	Virtual Shared Object Base Class
**	\see handle, loose_handle
**	\writeme
*/
class virtual_shared_object
{
protected:
	virtual_shared_object() { }
	virtual_shared_object(const virtual_shared_object&) { }
	virtual_shared_object& operator= (const virtual_shared_object&) { return *this; }
public:
	virtual ~virtual_shared_object() { }
	virtual void ref()const=0;
	virtual bool unref()const=0;
	virtual bool unref_inactive()const=0;
	virtual int count()const=0;
}; // END of class virtual_shared_object

// ========================================================================
/*!	\class	handle _handle.h	ETL/handle
**	\brief	Object Handle
**	\see shared_object, loose_handle
**	\writeme
*/
template <class T>
class handle
{
public:

	typedef T value_type;
	typedef T& reference;
	typedef const T& const_reference;
	typedef T* pointer;
	typedef const T* const_pointer;
	typedef int count_type;
	typedef int size_type;

protected:
#ifdef _DEBUG
public:
#endif
	value_type *obj;		//!< Pointer to object

public:

	//! Default constructor - empty handle
	handle():obj(NULL) {}

	//! Constructor that constructs from a pointer to new object
	handle(pointer x):obj(x)
	{
		if(obj)
			obj->ref();
	}

	//! Default copy constructor
	handle(const handle<value_type> &x):obj(x.get())
	{
		if(obj)
			obj->ref();
	}

	//! Handle is released on deletion
	~handle() { detach(); }

	//! Template Assignment operator
	/*! \note This class may not be necessary, and may be removed
	**		at some point in the future.
	*/
	/*
	template <class U> handle<value_type> &
	operator=(const handle<U> &x)
	{
		if(x.get()==obj)
			return *this;

		detach();

		obj=static_cast<value_type*>(x.get());
		if(obj)obj->ref();
		return *this;
	}
	*/

	//! Assignment operator
	handle<value_type> &
	operator=(const handle<value_type> &x)
	{
		if(x.get()==obj)
			return *this;
		// add reference before detach
		pointer xobj(x.get());
		if(xobj) xobj->ref();
		detach();
		obj=xobj;
		return *this;
	}

	//! Swaps the values of two handles without reference counts
	handle<value_type> &
	swap(handle<value_type> &x)
	{
		pointer ptr=x.obj;
		x.obj=obj;
		obj=ptr;
		return *this;
	}

	//! Handle detach procedure
	/*! unref()'s the object and sets the internal object pointer to \c NULL */
	void
	detach()
	{
		pointer xobj(obj);
		obj=0;
#ifdef ETL_SELF_DELETING_SHARED_OBJECT
		if(xobj)
			xobj->unref();
#else
		if(xobj && !xobj->unref())
			delete xobj;
#endif
	}

	// This will be reintroduced with a new function
	//void release() { detach(); }

	void reset() { detach(); }

	bool empty()const { return obj==0; }

	//! Creates a new instance of a T object and puts it in the handle.
	/*! Uses the default constructor */
	void spawn() { operator=(handle(new T())); }

	//! Returns a constant handle to our object
	handle<const value_type> constant()const { assert(obj); return *this; }

	//! Returns number of instances
	count_type
	count()const
		{ return obj?obj->count():0; }

	//! Returns true if there is only one instance of the object
	bool
	unique()const
		{ assert(obj); return count()==1; }

	reference
	operator*()const
		{ assert(obj); return *obj; }

	pointer
	operator->()const
		{ assert(obj); return obj; }

	//! More explicit bool cast
	operator bool()const
		{ return obj!=NULL; }

	operator handle<const value_type>()const
	{ return handle<const value_type>(static_cast<const_pointer>(obj)); }

	//! <tt> static_cast\<\> </tt> wrapper
	template <class U> static handle<T> cast_static		(const handle<U> &x) { return handle<T>(static_cast		<T*>(x.get())); }
	//! <tt> dynamic_cast\<\> </tt> wrapper
	template <class U> static handle<T> cast_dynamic	(const handle<U> &x) { return handle<T>(dynamic_cast	<T*>(x.get())); }
	//! <tt> const_cast\<\> </tt> wrapper
	template <class U> static handle<T> cast_const		(const handle<U> &x) { return handle<T>(const_cast		<T*>(x.get())); }
	//! <tt> reinterpret_cast\<\> </tt> wrapper
	template <class U> static handle<T> cast_reinterpret(const handle<U> &x) { return handle<T>(reinterpret_cast<T*>(x.get())); }

	template <class U> static handle<T> cast_static		(const loose_handle<U> &x);
	template <class U> static handle<T> cast_dynamic	(const loose_handle<U> &x);
	template <class U> static handle<T> cast_const		(const loose_handle<U> &x);
	template <class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);

	template <class U> static handle<T> cast_static		(const rhandle<U> &x);
	template <class U> static handle<T> cast_dynamic	(const rhandle<U> &x);
	template <class U> static handle<T> cast_const		(const rhandle<U> &x);
	template <class U> static handle<T> cast_reinterpret(const rhandle<U> &x);

	template <class U> static handle<T> cast_static		(U* x);
	template <class U> static handle<T> cast_dynamic	(U* x);
	template <class U> static handle<T> cast_const		(U* x);
	template <class U> static handle<T> cast_reinterpret(U* x);

	//! Returns pointer to the object that is being wrapped
	pointer get()const { return obj; }

	bool
	operator!()const
		{ return !obj; }

	//! static_cast<> overload -- Useful for implicit casts
	template <class U>
	operator handle<U>()const
	{ return handle<U>(obj); }

	template<typename U>
	bool type_is() const
	{ return dynamic_cast<const U*>(obj); }

	template<typename U>
	U* type_pointer() const
	{ return dynamic_cast<U*>(obj); }

	template<typename U>
	bool type_equal() const
	{ return typeid(*obj) == typeid(U); }
}; // END of template class handle

// ========================================================================
/*!	\class	rshared_object _handle.h	ETL/handle
**	\brief	Replaceable Shared Object Base Class
**	\see rhandle
**	\writeme
*/
class rshared_object : public shared_object
{
private:
	mutable int rrefcount;

public:
	void *front_;
	void *back_;

protected:
	rshared_object():rrefcount(0),front_(0),back_(0) { }
	rshared_object(const rshared_object &other): shared_object(other), rrefcount(0),front_(0),back_(0) { }
	rshared_object& operator= (const rshared_object&) { return *this; }

public:
	virtual void rref()const
		{ rrefcount++; }

	virtual void runref()const
	{
		assert(rrefcount>0);
		rrefcount--;
	}

	int rcount()const
		{ return rrefcount; }
}; // END of class rshared_object

// ========================================================================
/*!	\class	rhandle _handle.h	ETL/handle
**	\brief	Replaceable Object Handle
**	\see rshared_object, handle, loose_handle
**	\writeme
*/
template <class T>
class rhandle : public handle<T>
{
	friend class rshared_object;
public:

	typedef T value_type;
	typedef T& reference;
	typedef const T& const_reference;
	typedef T* pointer;
	typedef const T* const_pointer;
	typedef int count_type;
	typedef int size_type;


	using handle<value_type>::count;
	using handle<value_type>::unique;
	using handle<value_type>::operator bool;
	using handle<value_type>::get;
	using handle<value_type>::operator*;
	using handle<value_type>::operator->;

	/*
	operator const handle<value_type>&()const
	{ return *this; }
	*/

private:
	using handle<value_type>::obj;

	rhandle<value_type> *prev_;
	rhandle<value_type> *next_;

	void add_to_rlist()
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing

		assert(obj);
		obj->rref();

		// If this is the first reversible handle
		if(!obj->front_)
		{
			obj->front_=obj->back_=this;
			prev_=next_=0;
			return;
		}

		prev_=reinterpret_cast<rhandle<value_type>*>(obj->back_);
		next_=0;
		prev_->next_=this;
		obj->back_=this;
	}

	void del_from_rlist()
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		assert(obj);
		obj->runref();

		// If this is the last reversible handle
		if(obj->front_==obj->back_)
		{
			obj->front_=obj->back_=0;
			prev_=next_=0;
			return;
		}

		if(!prev_)
			obj->front_=(void*)next_;
		else
			prev_->next_=next_;

		if(!next_)
			obj->back_=(void*)prev_;
		else
			next_->prev_=prev_;
	}

public:

	//! Default constructor - empty handle
	rhandle() {}

	//! Constructor that constructs from a pointer to new object
	rhandle(pointer x):handle<T>(x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(obj)add_to_rlist();
	}

	rhandle(const handle<value_type> &x):handle<T>(x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(obj)add_to_rlist();
	}

	//! Default copy constructor
	rhandle(const rhandle<value_type> &x):handle<T>(x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(obj)add_to_rlist();
	}

	//! Handle is released on deletion
	~rhandle() { detach(); }

	//! Template Assignment operator
	/*! \note This class may not be necessary, and may be removed
	**		at some point in the future.
	*/
	/*
	template <class U> const handle<value_type> &
	operator=(const handle<U> &x)
	{
		if(x.get()==obj)
			return *this;

		detach();

		obj=static_cast<value_type*>(x.get());
		if(obj)
		{
			obj->ref();
			add_to_rlist();
		}
		return *this;
	}
	*/

	//! Assignment operator
	rhandle<value_type> &
	operator=(const rhandle<value_type> &x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(x.get()==obj)
			return *this;

		detach();

		obj=x.get();
		if(obj)
		{
			obj->ref();
			add_to_rlist();
		}
		return *this;
	}

	rhandle<value_type>&
	operator=(const handle<value_type> &x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(x.get()==obj)
			return *this;

		detach();

		obj=x.get();
		if(obj)
		{
			obj->ref();
			add_to_rlist();
		}
		return *this;
	}

	rhandle<value_type>&
	operator=(value_type* x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(x==obj)
			return *this;

		detach();

		obj=x;
		if(obj)
		{
			obj->ref();
			add_to_rlist();
		}
		return *this;
	}

	//! Handle release procedure
	/*! unref()'s the object and sets the internal object pointer to \c NULL */
	void
	detach()
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		if(obj)del_from_rlist();
		handle<value_type>::detach();
		obj=0;
	}

	// This will be reintroduced with a new function
	//void release() { detach(); }

	void reset() { detach(); }

	//! Creates a new instance of a T object and puts it in the handle.
	/*! Uses the default constructor */
	void spawn() { operator=(handle<value_type>(new T())); }

	//! Returns number of reversible instances
	count_type
	rcount()const
	{
//		value_type*const& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		return obj?obj->rcount():0;
	}

	//! Returns true if there is only one instance of the object
	bool
	runique()const
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		assert(obj); return obj->front_==obj->back_;
	}

	//! \writeme
	int replace(const handle<value_type> &x)
	{
//		value_type*& obj(handle<T>::obj); // Required to keep gcc 3.4.2 from barfing
		assert(obj);
		assert(x.get()!=obj);

		if(x.get()==obj)
			return 0;

		rhandle<value_type> *iter;
		rhandle<value_type> *next;

		iter=reinterpret_cast<rhandle<value_type>*>(obj->front_);

		assert(iter);

		next=iter->next_;

		int i=0;
		#ifndef NDEBUG
		pointer obj_=obj;
		#endif

		for(;iter;iter=next,next=iter?iter->next_:0,i++)
		{
			assert(iter->get()==obj_);
			(*iter)=x;
		}

		assert(obj==x.get());

		return i;
	}

	//! Swaps the values of two handles without reference counts
	/*!	\warning not yet implemented. \writeme */
	handle<value_type> &
	swap(handle<value_type> &x);
	/*
	{
		assert(0);
		pointer ptr=x.obj;
		x.obj=obj;
		obj=ptr;
		return *this;
	}
	*/
}; // END of template class rhandle


// ========================================================================
/*!	\class	loose_handle _handle.h	ETL/handle
**	\brief	Loose Object Handle
**	\see shared_object, handle
**	\writeme
*/
template <class T>
class loose_handle
{
public:

	typedef T value_type;
	typedef T& reference;
	typedef const T& const_reference;
	typedef T* pointer;
	typedef const T* const_pointer;
	typedef int count_type;
	typedef int size_type;

protected:
#ifdef _DEBUG
public:
#endif
	value_type *obj;		//!< Pointer to object

public:

	//! Default constructor - empty handle
	loose_handle():obj(0) {}

	//! Constructor that constructs from a pointer to new object
	loose_handle(pointer x):obj(x) { }

	//! Default copy constructor
	loose_handle(const loose_handle<value_type> &x):obj(x.get()) { }

	loose_handle(const handle<value_type> &x):obj(x.get()) { }

	template <class U> const loose_handle<value_type> &
	operator=(const handle<U> &x)
	{
		if(x.get()==obj)
			return *this;

		obj=x.get();
		return *this;
	}

	template <class U> const loose_handle<value_type> &
	operator=(const loose_handle<U> &x)
	{
		if(x.get()==obj)
			return *this;

		obj=x.get();
		return *this;
	}

	//! Assignment operator
	const loose_handle<value_type> &
	operator=(const loose_handle<value_type> &x)
	{
		if(x.get()==obj)
			return *this;

		obj=x.get();
		return *this;
	}

	//! Swaps the values of two handles without reference counts
	loose_handle<value_type> &
	swap(loose_handle<value_type> &x)
	{
		pointer ptr=x.obj;
		x.obj=obj;
		obj=ptr;
		return *this;
	}

	//! Handle release procedure
	void detach() { obj=0;	}

	// This will be reintroduced with a new function
	//void release() { detach(); }

	void reset() { detach(); }

	bool empty()const { return obj==0; }

	//! Returns a constant handle to our object
	loose_handle<const value_type> constant()const { return *this; }

	//! Returns number of instances
	count_type
	count()const
		{ return obj?obj->count():0; }

	reference
	operator*()const
		{ assert(obj); return *obj; }

	pointer
	operator->()const
		{ assert(obj); return obj; }

	//! static_cast<> overload
	//template <class U>
	//operator loose_handle<U>()const
	//{ return loose_handle<U>(static_cast<U*>(obj)); }

	//! static_cast<> overload (for consts)
	operator loose_handle<const value_type>()const
	{ return loose_handle<const value_type>(static_cast<const_pointer>(obj)); }

	operator handle<value_type>()const
	{ return handle<value_type>(obj); }

	operator rhandle<value_type>()const
	{ return rhandle<value_type>(obj); }

	//! Returns pointer to the object that is being wrapped
	pointer get()const { return obj; }

	//! More explicit bool cast
	operator bool()const
		{ return obj!=0; }

	bool
	operator!()const
		{ return !obj; }

	void ref() { if(obj)obj->ref(); }

	bool unref() { if(obj && !obj->unref()){ obj=0; return false; } return true; }

	template<typename U>
	bool type_is() const
	{ return dynamic_cast<const U*>(obj); }

	template<typename U>
	U* type_pointer() const
	{ return dynamic_cast<U*>(obj); }

	template<typename U>
	bool type_equal() const
	{ return typeid(*obj) == typeid(U); }
}; // END of template class loose_handle

// cast loose_handle<> -> handle<>
template <class T> template <class U> handle<T> handle<T>::cast_static	   (const loose_handle<U>& x) { return handle<T>(static_cast	 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_dynamic	   (const loose_handle<U>& x) { return handle<T>(dynamic_cast	 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_const	   (const loose_handle<U>& x) { return handle<T>(const_cast		 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const loose_handle<U>& x) { return handle<T>(reinterpret_cast<T*>(x.get())); }

// cast rhandle_handle<> -> handle<>
template <class T> template <class U> handle<T> handle<T>::cast_static	   (const rhandle<U>&	   x) { return handle<T>(static_cast	 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_dynamic	   (const rhandle<U>&	   x) { return handle<T>(dynamic_cast	 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_const	   (const rhandle<U>&	   x) { return handle<T>(const_cast		 <T*>(x.get())); }
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const rhandle<U>&	   x) { return handle<T>(reinterpret_cast<T*>(x.get())); }

// cast U* -> handle<>
template <class T> template <class U> handle<T> handle<T>::cast_static	   (U*					   x) { return handle<T>(static_cast	 <T*>(x));		 }
template <class T> template <class U> handle<T> handle<T>::cast_dynamic	   (U*					   x) { return handle<T>(dynamic_cast	 <T*>(x));		 }
template <class T> template <class U> handle<T> handle<T>::cast_const	   (U*					   x) { return handle<T>(const_cast		 <T*>(x));		 }
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(U*					   x) { return handle<T>(reinterpret_cast<T*>(x));		 }

// operator== for handle<>, loose_handle<> and T*
template <class T,class U> bool operator==(const handle		 <T>& lhs,const handle		<U>& rhs) { return (lhs.get()==rhs.get()); }
template <class T,class U> bool operator==(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
template <class T,class U> bool operator==(const handle		 <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()==rhs.get()); }
template <class T,class U> bool operator==(const loose_handle<T>& lhs,const handle		<U>& rhs) { return (lhs.get()==rhs.get()); }
template <class T>		   bool operator==(const handle<T>&		  lhs,const T*				 rhs) { return (lhs.get()==rhs);	   }
template <class T>		   bool operator==(const loose_handle<T>& lhs,const T*				 rhs) { return (lhs.get()==rhs);	   }
template <class T>		   bool operator==(const T*				  lhs,const handle<T>&		 rhs) { return (lhs		 ==rhs.get()); }
template <class T>		   bool operator==(const T*				  lhs,const loose_handle<T>& rhs) { return (lhs		 ==rhs.get()); }

// operator!= for handle<>, loose_handle<> and T*
template <class T,class U> bool operator!=(const handle		 <T>& lhs,const handle		<U>& rhs) { return (lhs.get()!=rhs.get()); }
template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
template <class T,class U> bool operator!=(const handle		 <T>& lhs,const loose_handle<U>& rhs) { return (lhs.get()!=rhs.get()); }
template <class T,class U> bool operator!=(const loose_handle<T>& lhs,const handle		<U>& rhs) { return (lhs.get()!=rhs.get()); }
template <class T>		   bool operator!=(const handle<T>&		  lhs,const T*				 rhs) { return (lhs.get()!=rhs);	   }
template <class T>		   bool operator!=(const loose_handle<T>& lhs,const T*				 rhs) { return (lhs.get()!=rhs);	   }
template <class T>		   bool operator!=(const T*				  lhs,const handle<T>&		 rhs) { return (lhs		 !=rhs.get()); }
template <class T>		   bool operator!=(const T*				  lhs,const loose_handle<T>& rhs) { return (lhs		 !=rhs.get()); }

// operator< for handle<>, loose_handle<> and T*
template <class T,class U> bool operator<(const handle<T>&		  lhs,const handle<U>&		 rhs) { return (lhs.get()<rhs.get());  }
template <class T,class U> bool operator<(const loose_handle<T>&  lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get());  }
template <class T,class U> bool operator<(const handle<T>&		  lhs,const loose_handle<U>& rhs) { return (lhs.get()<rhs.get());  }
template <class T,class U> bool operator<(const loose_handle<T>&  lhs,const handle<U>&		 rhs) { return (lhs.get()<rhs.get());  }
template <class T>		   bool operator<(const handle<T>&		  lhs,const T*				 rhs) { return (lhs.get()<rhs);		   }
template <class T>		   bool operator<(const loose_handle<T>&  lhs,const T*				 rhs) { return (lhs.get()<rhs);		   }
template <class T>		   bool operator<(const T*				  lhs,const handle<T>&		 rhs) { return (lhs		 <rhs.get());  }
template <class T>		   bool operator<(const T*				  lhs,const loose_handle<T>& rhs) { return (lhs		 <rhs.get());  }

};

/* === E N D =============================================================== */

#endif
