/*****************************************************************************
 * $Id: gfx_stack.hh,v 1.26 2006/08/03 02:17:21 devel Exp $
 * @file
 * @author  Jim E. Brooks  http://www.jimbrooks.org
 * @brief   C++ template for a stack of objects.
 * @remarks Why was this written instead of using STL's std::stack?
 *          Because this can be compiled to do type signatue checking.
 *          This Stack class is based on pointers to objects for speed.
 * @verbatim
 * Template for a stack of C++ objects.
 *
 * Interface:
 *   Push()
 *   Pop()
 *   Cnt()
 *    IfEmpty()
 *   ~Stack()     automatically deletes any remaining pushed objects
 *
 * @endverbatim
 *//*
 * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_STACK_HH
#define GFX_STACK_HH 1

#include "gfx_list.hh"

namespace gfx {

////////////////////////////////////////////////////////////////////////////////
/// @brief Stack class template.
/// NOTE: When stack is destroyed, any stacked objects will be deleted unconditionally!
/// Stack is built over a linked list.
template<typename T>
class Stack
{
    PREVENT_COPYING(Stack<T>)
public:
                	Stack( void );
                	~Stack();
	inline void		Push( T* obj );
	inline T*		Pop( void );
	inline bool		IfEmpty( void ) const;
	inline uint		Cnt( void ) const;

private:
	Dlist<T>	mDlist;  // when this is destroyed, it'll destroy linked objects
	uint		mCnt;

public:
	DECL_TYPESIG( TYPESIG_LIB_STACK )
	friend bool StackTest( void );
};

/*****************************************************************************
 * Constructor.
 *****************************************************************************/
template<typename T>
Stack<T>::Stack( void )
: mCnt(0)
{
	SET_TYPESIG( this, TYPESIG_LIB_STACK );
}

/*****************************************************************************
 * Destructor.
 *****************************************************************************/
template<typename T>
Stack<T>::~Stack()
{
    CHECK_TYPESIG( &mDlist, TYPESIG_LIB_DLIST );
    INVALIDATE_TYPESIG( this, TYPESIG_LIB_STACK );
}

/*****************************************************************************
 * Push a C++ object.
 *****************************************************************************/
template<typename T>
void
Stack<T>::Push( T* obj )
{
CHECK_TYPESIG( this,  TYPESIG_LIB_STACK );
CHECK_TYPESIG( &mDlist, TYPESIG_LIB_DLIST );
ASSERT( obj );

	mDlist.Append( obj );  // push by appending to list
	++mCnt;
}

/*****************************************************************************
 * Pop a C++ object.
 * @return NULL if stack empty.
 *****************************************************************************/
template<typename T>
T*
Stack<T>::Pop( void )
{
CHECK_TYPESIG( this,  TYPESIG_LIB_STACK );
CHECK_TYPESIG( &mDlist, TYPESIG_LIB_DLIST );

	Dlink<T>* dlink = mDlist.Last();	// get last link in list (pushing appends to list)
	if ( EX( dlink != NULL ) )
	{
		T* obj = dlink->mObj;			// pop by unlinking object from list
		mDlist.Unlink( dlink );
		--mCnt;
		return obj;
	}
	else
	{
		ASSERT(0);
        return NULL;                    // oops, stack is empty!
	}
}

/*****************************************************************************
 * Is stack empty?
 *****************************************************************************/
template<typename T>
bool
Stack<T>::IfEmpty( void ) const
{
	return mCnt == 0;
}

/*****************************************************************************
 * @return Amount of pushed items.
 *****************************************************************************/
template<typename T>
uint
Stack<T>::Cnt( void ) const
{
	return mCnt;
}

} // namespace gfx

#endif // GFX_STACK_HH
