// -----------------------------------------------------------------------------
// File contents / class description:
// -----------------------------------------------------------------------------
//
// Smart pointer template class
//
// -----------------------------------------------------------------------------
// Originally created on 05/15/2000 by Bernhard Glueck
// Email: jglueck@vol.at
// You can use this software at your own free will, however I am not to be held
// responsible for any damage this does to you or to your health :-)
// You can freely use the code provided in your own programs, however if you find
// any bugs, or add a cool new feature to it, I would like to hear about it.
// -----------------------------------------------------------------------------

#ifndef	__POINTER_H__
#define __POINTER_H__

	/// Disable UDT warning
	#pragma warning ( disable : 4284 )

// -----------------------------------------------------------------------------
	/// Error handling macro only for this version
	#define ErrorReport( a ) 

	/// A simple macro for relasing C++ classes safely
	#define SafeRelease( object ) if ( object ) delete object

	/// SmartPointer template which offers automatic reference counting
	template <class T>
	class Pointer
	{
		public:
		
		struct PointerData
		{
			T *		data;
			int		count;
		};
			
		/// Assigns a native pointer
		inline void			operator = ( T * p );
		
		/// Assigns another smartpointer
		inline void			operator = ( const Pointer &p );
		
		/// Compares two smartpointers
		inline bool			operator == ( const Pointer &p );
		
		/// The same only negative
		inline bool			operator != ( const Pointer &p );
		
		/// Compares a smartpointer and a native pointer
		inline bool			operator == ( const T * p );
		
		/// Compares a smartpointer and a native pointer, negative
		inline bool			operator != ( const T * p );

		/// Accesses the native pointer
		inline const T *	operator -> ()  { return Get(); }
		
		/// Dereferences the native pointer
		inline T &			operator *	() { return *Get(); }

		/// Checks if the native pointer is valid
		inline bool			Valid();
		
		/// Converts the pointer to native
		inline operator const T * () { return Get(); }

		/// Releases the referenced object (safe)
		inline void			Release();

		/// Retrieves the native pointer...
		inline T *			Get();

		/// Increases the reference count by one, use with extreme CAUTION!
		inline void			AddRef();

		// Construction/Destruction
		inline	Pointer( T * p = NULL );
		inline	Pointer( const Pointer & );
		inline	~Pointer();

		private:
		
		inline void			Set( T * p );
		
		// Data members
		PointerData *		m_pointer;
	};

// -----------------------------------------------------------------------------
	template <class T>
	inline Pointer<T>::Pointer( T * p )
	{
		m_pointer = NULL;
		Set(p);
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline Pointer<T>::Pointer( const Pointer &p )
	{
		m_pointer = p.m_pointer;
		m_pointer->count ++;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline Pointer<T>::~Pointer()
	{
		Release();
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline bool Pointer<T>::operator != ( const Pointer &p )
	{
		if ( m_pointer != p.m_pointer ) return true;
		else return false;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline bool Pointer<T>::operator == ( const Pointer &p )
	{
		if ( m_pointer == p.m_pointer ) return true;
		else return false;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline bool Pointer<T>::operator != ( const T * p )
	{
		if ( m_pointer )
		{
			if ( m_pointer->data == p ) return true;
			else return false;
		}
		else return true;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline bool Pointer<T>::operator == ( const T * p )
	{
		if ( m_pointer )
		{
			if ( m_pointer->data != p ) return false;
			else return true;
		}
		else return false;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline void Pointer<T>::operator = ( T * p )
	{
		Set( p );
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline void Pointer<T>::operator = ( const Pointer &p )
	{
		Release();

		m_pointer = p.m_pointer;
		m_pointer->count ++;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline void Pointer<T>::Set( T * p )
	{
		Release();

		m_pointer = new PointerData();
		m_pointer->data = p;
		m_pointer->count = 1;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline void Pointer<T>::AddRef()
	{
		if ( m_pointer )
			m_pointer->count ++;
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline void Pointer<T>::Release()
	{
		if ( m_pointer )
		{
			m_pointer->count --;

			if ( m_pointer->count == 0 )
			{
				if ( m_pointer->data )
				{	
					delete m_pointer->data;
					m_pointer->data = NULL;
				}
				
				delete m_pointer; // This can only happen when no objects still refer it
			}
		
			// Very important
			m_pointer = NULL;
		}
	}

// -----------------------------------------------------------------------------
	template <class T>
	inline T* Pointer<T>::Get()
	{
		if ( m_pointer )
		{
			if ( m_pointer->data )
			{
				return m_pointer->data;
			}
			else 
			{	
				ErrorReport("Trying to access NULL pointer");
				return NULL;
			}
		}
		else 
		{	
			ErrorReport("Pointer access error");
			// Only for syntax, should never happen!
			return NULL;
		}
	}
// -----------------------------------------------------------------------------
	template <class T>
	inline bool Pointer<T>::Valid()
	{
		if ( m_pointer )
		{
			if ( m_pointer->data )
			{
				return true;
			}
			else return false;
		}
		else return false;
	}

// -----------------------------------------------------------------------------

#endif // __POINTER_H__

// -----------------------------------------------------------------------------
// Pointer.h - End of file
// -----------------------------------------------------------------------------

