#if !defined(BRDELSTA_H) && !defined(__BEDRC__)
#define BRDELSTA_H
// We don't want this file included by BedRC -- there is a sizeof in an enum
//========================================================================================
//
//	This source file is a component of the Bedrock Class Library
//
//	File:				BRDelSta.h
//	Release Version:	$ 1.0d1 $
//
//	Creation Date:		June 1, 1992
//
//	COPYRIGHT 1990-93 SYMANTEC CORPORATION. ALL RIGHTS RESERVED. UNPUBLISHED -- RIGHTS
//	RESERVED UNDER THE COPYRIGHT LAWS OF THE UNITED STATES. USE OF COPYRIGHT NOTICE IS
//	PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION OR DISCLOSURE.
//
//	THIS SOFTWARE Contains PROPRIETARY AND CONFIDENTIAL INFORMATION OF SYMANTEC
//	CORPORATION. USE, DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
//	EXPRESS WRITTEN PERMISSION OF SYMANTEC CORPORATION.
//
//	RESTRICTED RIGHTS LEGEND
//	Use, duplication, or disclosure by the Government is subject to restrictions as Set
//	forth in subparagraph (c)(l)(ii) of the Rights in Technical Data and Computer
//	Software clause at DFARS 252.227-7013. Symantec Corporation, 10201 Torre Avenue,
//	Cupertino, CA 95014.
//
//========================================================================================

#ifndef   BREXCTAS_H
#include "BRExcTas.h"
#endif

#ifndef   BRPRIDEB_H
#include "BRPriDeb.h"
#endif

#ifndef   BREXCRUN_H
#include "BRExcRun.h"
#endif

class _BR_CDeleteStack;
class _BR_CDeleteEntry;
class _BR_CMetaClass;
class _BR_CAutoDestructObject;

//========================================================================================
// CLASS _BR_CDeleteEntry
//========================================================================================

class _BR_CDeleteEntry
{
public:

	enum __DeleteType
	{
		__kObject,
		__kGuard,
		__kDeleted,
		__kInvalid
	};

	__DeleteType fType;
	union 
	{
		_BR_CAutoDestructObject * fObject;
		_BR_CMetaClass *fGuard;
	};

	void *fObjectVTable; // The objects v table at time of construction
	
	_BR_CDeleteEntry(_BR_CAutoDestructObject * anObject);
	_BR_CDeleteEntry(_BR_CMetaClass * guard);

	__DeleteType GetType();
	void SetType(__DeleteType type);
	_BR_CMetaClass *GetGuard();
	_BR_CAutoDestructObject *GetObject();
};


//========================================================================================
// CLASS _BR_CDeleteStack
//
//	The delete stack is maintained as an array of pointers to DeleteEntry, and three
//	pointers into the array.  The three pointers are the StackBase, StackTop, and 
//	StackLimit.  The StackBase points to the beginning of the array, the StackLimit points
//	one past the last position in the array, and the StackTop points one past the last
//	pushed item.  When the stack is empty, StackBase == StackTop.  When the stack is 
//	full StackTop == StackLimit.  If an item is pushed when the stack is full, it is
//	resized, which may move the array, so all three pointers need to be updated.  To do
//	this, an integer offset RelativeTopOfStack is sometimes used to remember the location
//	of a StackTop across code that might resize the stack.
//
//	Class Invariants:
//		GetStackBase() != NULL
//		GetStackBase() <= GetStackTop() <= GetStackLimit()
//		GetStackTop() == GetStackBase() + RelativeTopOfStack()
//		GetStackBase() + GetCurrentStackSize() == GetStackLimit()
//========================================================================================

class _BR_CDeleteStack
{
public:
	static void Initialize();
	static void Terminate();

    static inline void Push(_BR_CAutoDestructObject* anObject);
    static inline void Push(_BR_CMetaClass* aGuard);

	static int IsClassExpectedInContext(_BR_CTryBlockContext *BRTryBlo, _BR_CMetaClass *thrownType);
		// Search for a guard that would prevent throwing this class to the next BRTryBlo.
		// If we don't find such a guard then return true otherwise return false.

	static void PopOffAndDeleteObjectsInContext(_BR_CTryBlockContext *BRTryBlo);
	static _BR_StackEntries RelativeTopOfStack();
	static void PopIfTopEquals(_BR_CAutoDestructObject* anObject);
    static _BR_CMetaClass * PopGuard();

private:
#ifdef _NOSCOPING
    static void Push(void * aGuardOrObject, __DeleteType deleteType);
#else
    static void Push(void * aGuardOrObject, _BR_CDeleteEntry::__DeleteType deleteType);
#endif

	enum
	{
		kNumberOfObjectsToGrowStack = 256,
		kStepByteSize = kNumberOfObjectsToGrowStack * sizeof(_BR_CDeleteEntry)
	};

	static void SetCurrentStackSize(_BR_StackEntries nCurrentByteSize);
	static _BR_StackEntries GetCurrentStackSize();
	static void SetStackBase(_BR_CDeleteEntry * pStackBase);
	static _BR_CDeleteEntry * GetStackBase();
	static void SetStackTop(_BR_CDeleteEntry * pStackTop);
	static _BR_CDeleteEntry * GetStackTop();
	static void SetStackLimit(_BR_CDeleteEntry * pStackLimit);
	static _BR_CDeleteEntry * GetStackLimit();
	
#ifdef BR_DEBUG
	static void CheckClassInvariants();
#endif
};

//========================================================================================
// STRUCT _BR_SThrowGuard
//========================================================================================

struct _BR_SThrowGuard
{
#ifdef BR_DEBUG
	_BR_CMetaClass* fGuardClass;
#endif
	_BR_SThrowGuard();
	_BR_SThrowGuard(_BR_CMetaClass * guard);
	~_BR_SThrowGuard();
};

//========================================================================================
// CLASS _BR_CDeleteEntry INLINE Functions
//========================================================================================

#ifdef _NOSCOPING
    inline __DeleteType _BR_CDeleteEntry::GetType()
#else
    inline _BR_CDeleteEntry::__DeleteType _BR_CDeleteEntry::GetType()
#endif
{
	return fType;
}

inline void _BR_CDeleteEntry::SetType(__DeleteType type)
{
	fType = type;
}

inline _BR_CMetaClass *_BR_CDeleteEntry::GetGuard()
{
	BR_PRIMITIVE_ASSERT(fType == __kGuard);
	return fGuard;
}

inline _BR_CAutoDestructObject *_BR_CDeleteEntry::GetObject()
{
	BR_PRIMITIVE_ASSERT(fType == __kObject);
	return fObject;
}

//========================================================================================
// CLASS _BR_CDeleteStack INLINE Functions (Static Task Globals Versions)
//========================================================================================

#ifdef BR_STATIC_TASK_GLOBALS

inline _BR_StackEntries _BR_CDeleteStack::GetCurrentStackSize()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gCurrentStackSize;
}

inline void _BR_CDeleteStack::SetCurrentStackSize(_BR_StackEntries newStackSize)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gCurrentStackSize = newStackSize;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackBase()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackBase;
}

inline void _BR_CDeleteStack:: SetStackBase(_BR_CDeleteEntry* pStackBase)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackBase = pStackBase;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackTop()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackTop;
}

inline void _BR_CDeleteStack::SetStackTop(_BR_CDeleteEntry* pStackTop)
{
#ifdef BR_DEBUG
	pStackTop->SetType(_BR_CDeleteEntry::__kInvalid);
#endif
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackTop = pStackTop;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackLimit()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackLimit;
}

inline void _BR_CDeleteStack::SetStackLimit(_BR_CDeleteEntry* pStackLimit)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.gBedDeleteStack.gStackLimit = pStackLimit;
}

#endif	// BR_BUILD_MAC

//========================================================================================
// CLASS _BR_CDeleteStack INLINE Functions (Dynamic Task Globals Versions)
//========================================================================================

#ifndef BR_STATIC_TASK_GLOBALS

inline _BR_StackEntries _BR_CDeleteStack::GetCurrentStackSize()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gCurrentStackSize;
}

inline void _BR_CDeleteStack::SetCurrentStackSize(_BR_StackEntries newStackSize)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gCurrentStackSize = newStackSize;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackBase()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackBase;
}

inline void _BR_CDeleteStack:: SetStackBase(_BR_CDeleteEntry* pStackBase)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackBase = pStackBase;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackTop()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackTop;
}

inline void _BR_CDeleteStack::SetStackTop(_BR_CDeleteEntry* pStackTop)
{
#ifdef BR_DEBUG
	pStackTop->SetType(_BR_CDeleteEntry::__kInvalid);
#endif
	BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackTop = pStackTop;
}

inline _BR_CDeleteEntry* _BR_CDeleteStack::GetStackLimit()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackLimit;
}

inline void _BR_CDeleteStack::SetStackLimit(_BR_CDeleteEntry* pStackLimit)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->gBedDeleteStack.gStackLimit = pStackLimit;
}

#endif	// BR_BUILD_WIN

//========================================================================================
// CLASS _BR_CDeleteStack INLINE Functions (Platform independent versions)
//========================================================================================

inline void _BR_CDeleteStack::Push(_BR_CMetaClass* aGuard)
{
	Push((void*) aGuard, _BR_CDeleteEntry::__kGuard);
}

inline void _BR_CDeleteStack::Push(_BR_CAutoDestructObject* anObject)
{
	Push((void*) anObject, _BR_CDeleteEntry::__kObject);
}

#endif
