#pragma once
//===========================================================================//
// File:	 MemoryManager.cpp												 //
// Project:  GameOS					                                         //
// Contents: MemoryManager subsyystem										 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 12/12/97  JTR    Created													 //
// 12/27/97  JTR	Documented												 //
// 01/07/98  JTR	Cleaned up reporting. Added timestamp.					 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

//#include <psapi.h>

namespace Gos2 {

struct _MEMORYPOOL;
struct _HEAPHEADER;
struct _LARGEBLOCKHEADER;

//
// Single byte before allocations
//
// 0	 = Invalid (duplicate free detection)
// 1-252 = Heap number for a 'pool' allocated block
// 253   = Large block (not in pools)
// 254   = Block allocated before init.
// 255   = Unused
//
//
const int Magic_LargeBlock=253;					// Larger than 4k memory block (no in pools)
const int Magic_BeforeInit=254;					// Allocated before inited  (was 0xabadcafe)

//
// This is the largest 'pool' size - blocks larger than this use the system allocator
//
const int LargestMemoryBlock=1024;				// Largest memory block managed
//
// This is the total number of pools being managed
//
const int MemoryPools = 18;

//
// Magic number placed after allocations in DEBUG/ARMOR
//
const int MemoryEndMarker=0x7fb1deaf;			// Placed at the end of allocations in _ARMOR builds





#pragma pack(push,1)
#pragma warning(disable: 4200)
//
// Information block for all blocks in pools with < 256 bytes
//
typedef struct
{
#ifdef _DEBUG
	BYTE			Size;						// Size of block (note pools are always <64K)
	const _TCHAR *	pAllocString;
	DOUBLE			dTimeStamp;					// at what time was the block alloc'd
	DWORD			pContext[0];				// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} SMALLPOOLBLOCK;

//
// Information block for all blocks in pools with >= 256 bytes
//
typedef struct
{
#ifdef _DEBUG
	WORD			Size;						// Size of block (note pools are always <64K)
	const _TCHAR *	pAllocString;
	DOUBLE			dTimeStamp;					// at what time was the block alloc'd
	DWORD			pContext[0];				// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} POOLBLOCK;

//
// Header for large blocks or blocks before memory manager inited.
//
typedef struct _LARGEBLOCK
{
	DWORD				Size;					// Size of block (note can be any size)
	_LARGEBLOCKHEADER*	pLast;					// Pointer to previous large memory block
	_LARGEBLOCKHEADER*	pNext;					// Pointer to next large memory block
	BYTE				Heap;
#ifdef _DEBUG
	const _TCHAR *		pAllocString;
	DOUBLE				dTimeStamp;				// at what time was the block alloc'd
	DWORD				pContext[0];			// we'll allocate the right size based on gMemoryStackWalkLevel
#endif
} LARGEBLOCK;

//
// Structure placed directly BEFORE each memory block
//
typedef struct _LARGEBLOCKHEADER
{
	LARGEBLOCK*		pLargeBlockInfo;
	BYTE			LargeMagicNumber;			// Magic_LargeBlock or Magic_BeforeInit
} LARGEBLOCKHEADER;

//
// Structure used to hold information about 'pools' of memory blocks
//
typedef struct _MEMORYPOOL
{
	DWORD				HeapTag;				// Tag so that memory is easily spotted in VM viewers
	_MEMORYPOOL*		pLast;					// Points to the last heap of the SAME block size
	_MEMORYPOOL*		pNext;					// Points to the next heap of the SAME block size
	POOLBLOCK*			pInfoBlocks;			// an array of blocks which describe particular memory blocks (may point to a SMALLPOOLBLOCK header for >256 bytes)
	BYTE*				pMemoryPool;			// Pointer to the base of the memory blocks (pointer to header byte before allocation)
	WORD				wBlockSize;				// what is the size of the individual blocks?
	WORD				wTotalBlocks;			// Total blocks available
	#ifdef _DEBUG
	WORD				wUserBytes;				// the amount of memory in the pool that is actual user data
	#endif
	WORD				AllocCount[16];			// Number of blocks allocated in each 4K page (when 0, block can be decommitted)
	WORD				FreeBlockPtr;			// Next available block in FreeBlockStack
	WORD				FreeBlockStack[0];		// Free block offsets (from base of pool - pointer to header byte before allocation)
} MEMORYPOOL;

//
// Used to hold GameOS level heap information
//
class Heap : public GosHeap
{
public:
	static bool	g_MMInitialized;
	static bool InConstructor;
	static bool InDestructor;
	static WORD PoolSizes[];
	static DWORD LargeMemorySize;
	static DWORD LargeMemoryAllocations;
	static DWORD gMemoryBlockOverhead;
	static CRITICAL_SECTION CriticalSection;

	static Heap * HeapList[];
	static Heap * AllHeaps;
	static Heap * CurrentHeap;

	static Heap * GameOSHeap;
	static Heap * ClientHeap;


	static MEMORYPOOL* gMemoryPool[];
	static HANDLE HWSProcess;
	static int AgressiveManager;
	
	static bool gShowAllocations;
	static bool gShowMemoryUseage;

	static DWORD gNoFree;
	static DWORD MemoryLeaks;
	static DWORD LeakedMemory;
	static DWORD MemoryAllocs;
	static DWORD MemoryFrees;
	static DWORD MemoryAllocated;
	static DWORD MemoryFreed;
	static DWORD SystemMemoryAllocated;
	static DWORD SystemMemoryAllocs;



	Heap*		pNext;
	DWORD		Magic;
	int			Instances;
	_TCHAR 		m_Name[128];
#ifdef _DEBUG
	int			MaximumSize;
	int			BytesAllocated;
	int			TotalAllocatedLastLoop;
	int			BytesAllocatedThisLoop;
	int			BytesFreedThisLoop;
	int			AllocationsThisLoop;
	int			AllocationsLastLoop;
	int			TotalAllocations;
	int			PeakSize;
	bool		bExpanded;							// this is used for collapsing tree in debugger
	bool		bExamined;							// this is used for collapsing tree in debugger
	int			LargeAllocations;
	int			LargeAllocated;
	int			DXAllocations;
	int			DXAllocated;
#endif
	BYTE		HeapNumber;							// Heap number in HeapList[]  (<<24)
public:
	Heap( _TCHAR * Name, DWORD maxBytes );
	~Heap();
	void* Malloc( DWORD bytes, const TCHAR * pDesc = NULL);
	void* Realloc( void* MemoryPtr, int NewSize );
	void ChangeSize( int Change, bool SystemAllocation = 0 );
	void Walk( bool vociferous );
	void VerifyEmpty();
	void UpdateStatistics();
	static DWORD			GetID( void *pData );
	virtual DWORD			GetIDLocal( void *pData );
	virtual void			FreeLocal( void *pData );
	virtual _TCHAR * Name() { return m_Name; }
	static void Free( void * MemoryPtr);
	static void CheckRegistered();
	static void Shutdown();
	static void Initialize();
	static void SpewAndFreeHeapAllocs(Heap * pHeap, bool vociferous);
	static void DestroySelf(Heap * toDestroy, bool vociferous);
	
	static GosHeap * Create( _TCHAR *name, DWORD bytesMax );
	
	static void Destroy(GosHeap *);
	static void PushCurrent( GosHeap *pHeap );
	static void	PopCurrent();
	static GosHeap * Current();




protected:
	void WalkSelf( bool vociferous );
	void WalkAllocs( bool vociferous );


};
#pragma pack(pop)


};