///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains all memory-related code.
 *	\file		IceMemoryManager.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEMEMORYMANAGER_H__
#define __ICEMEMORYMANAGER_H__

//#define DONT_TRACK_MEMORY_LEAKS

ICECORE_API udword GetFreeRam();
ICECORE_API udword Alignment(udword address);

#ifndef DONT_TRACK_MEMORY_LEAKS
	#ifdef _DEBUG
	ICECORE_API void* Alloc(udword size, const char* file, sdword line);
	ICECORE_API bool Free(void* addr);
	#else
	ICECORE_API void* Alloc(udword size);
	ICECORE_API void Free(void* addr);
	#endif
#endif

// Ram counters
struct ICECORE_API RamCounter
{
			RamCounter() : RamUsed(0), HighWaterMark(0)	{}
			~RamCounter()								{}

	void	Count(udword nbbytes)	{ RamUsed+=nbbytes; if(RamUsed>HighWaterMark) HighWaterMark=RamUsed; }
	void	Deduct(udword nbbytes)	{ RamUsed-=nbbytes;	}

	udword	RamUsed;
	udword	HighWaterMark;
};

#ifndef DONT_TRACK_MEMORY_LEAKS
	#ifdef _DEBUG
		#define MEMBLOCKSTART		64
		inline void* __cdecl operator new(unsigned int size, const char* file, sdword line)	{	return Alloc(size, file, line);	}	//!< new overload
		inline void operator delete(void* addr, const char* file, sdword line)				{	Free(addr);						}	//!< delete overload
		inline void operator delete(void* addr)												{	Free(addr);						}	//!< delete overload
		#undef NEW_D
		#undef DELETE_D
		#define NEW_D ::new(THIS_FILE, __LINE__)
		#define DELETE_D ::delete
		#define new NEW_D
		#define delete DELETE_D
	#else
		#ifndef DEFAULT_NEWDELETE
			inline void* __cdecl operator new(unsigned int size)							{	return Alloc(size);				}	//!< new overload
			inline void operator delete(void* addr)											{	Free(addr);						}	//!< delete overload
		#endif
	#endif
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	//! The memory manager contains a linked list of memory cells.
	typedef struct ICECORE_API MemoryCell {
		struct MemoryCell*	PreviousCell;				//!< Link to previous cell or null
		struct MemoryCell*	NextCell;					//!< Link to next cell or null
		void*				MallocAddress;				//!< Address of allocated ram
		void*				AlignedMallocAddress;		//!< Aligned address (on 1K bytes boundary)
		udword				ReservedBytes;				//!< Size of allocated ram
	} MEMORY_CELL;

	class ICECORE_API MemoryManager
	{
		private:

		MEMORY_CELL*		mCurrentCell;				//!< Active cell
		MEMORY_CELL*		mInitCell;					//!< Initial cell
		long				mTotal;						//!< Total allocated ram
		bool				mIsAligned;					//!< Is alignment on/off ?

		public:

		//! Constructor
							MemoryManager();
		//! Destructor
							~MemoryManager();

		void*				Malloc(size_t n);								//!< Allocates a buffer and keep track of it.
		bool				Free(void* buffer);								//!< Frees a previously allocated buffer.
		long				RamUsed()			{ return mTotal;		}	//!< Returns total ram used
		void				AlignOn()			{ mIsAligned = true;	}	//!< Set the alignment on
		void				AlignOff()			{ mIsAligned = false;	}	//!< Set the alignment off
	};

#endif // __ICEMEMORYMANAGER_H__
