//////////////////////////////////////////////////////////////////////////////
//
// Asura_MemAllocator.h
//
// Copyright (c) 2007 Rebellion. All rights reserved.
//
// Description:
//
//     class to manage heap allocation from a block of memory e.g. VRAM where
//     you don't want the memory records to be kept in that memory.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ASURA_MEMALLOCATOR_H___
#define ASURA_MEMALLOCATOR_H___ 1

// I N C L U D E S ///////////////////////////////////////////////////////////
#include "Core/Asura_Mempool.h"
#include "Core/Asura_Multithread.h"


// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////
class Asura_MemAllocator_AllocRecord;

// C L A S S E S /////////////////////////////////////////////////////////////
class Asura_MemAllocator
{
public:

	// An alloc record is either an used or a free block of memory (so initially we have one record containing the whole arena in the free list and nothing in the used list).
	// As such, if you have a maximum number of allocations N you can make, the maximum number of records should be 2N + 1.
	Asura_MemAllocator( void* pArena, u_int uSize, u_int uMinAlignment, u_int uMaximumAllocRecords, u_int uMinAllocSize = 0 );
	~Asura_MemAllocator();

	void* Allocate( u_int uBytes )
	{
		return Allocate( uBytes, m_uMinAlignment );
	}
	void* Allocate( u_int uBytes, u_int uAlignment );
	void Free( void* pAddress );

	// functions to get stats about the allocator.
	u_int GetSize() const { return m_uArenaSize; }
	u_int GetUsedSpace() const { return m_uArenaSize - m_uFreeSpace; }
	u_int GetFreeSpace() const { return m_uFreeSpace; }
	u_int GetLargestFreeBlock() const;
	u_int GetNumUsedBlocks() const;
	u_int GetNumFreeBlocks() const;

	bool IntegrityCheck() const;

	void Wipe();

private:

	// internal functions
	Asura_MemAllocator_AllocRecord* CreateAllocRecord( void* pAddress, u_int uSize, Asura_MemAllocator_AllocRecord* pxNext );
	void ReturnAllocRecord( Asura_MemAllocator_AllocRecord* pxRecord );

	void MutexAcquire(void) const;
	void MutexRelease(void) const;

	// initial data
	void* const m_pArena;
	const u_int m_uArenaSize;
	const u_int m_uMinAlignment;
	Asura_Mempool m_xRecordPool;
	const u_int m_uMinAllocSize;

	// runtime data
	Asura_MemAllocator_AllocRecord* m_pxFreeList;
	Asura_MemAllocator_AllocRecord* m_pxUsedList;
	u_int m_uFreeSpace;

	mutable Asura_Mutex	m_xMutex;
};

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ASURA_MEMALLOCATOR_H___
