// VMem.h: interface for the CVMem class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_VMEM_H__6FFF3C69_50F7_4B4B_A40F_D81A0A7713AC__INCLUDED_)
#define AFX_VMEM_H__6FFF3C69_50F7_4B4B_A40F_D81A0A7713AC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <VECTOR>
#include <functional>
#include <algorithm>
//#include "global.h"

#ifndef DBGOUT
#define DBGOUT (void(0))
#endif

using namespace std;


class CVMem
{
public:
	CVMem();
	~CVMem();

public:
	BOOL AllocVMem(DWORD dwTypeSize, DWORD dwPoolCount);
	BOOL FreeAllVMem(void);
	BOOL FreeVMem(void * pVMem);

	inline void *ObjectNew();
	inline void ObjectDelete(void *p);

private:
	inline BOOL CommitVMem(void *pAddr, DWORD dwSize);
	inline BOOL DecommitVMem(void *pAddr, DWORD dwSize);

	inline void LockVMem(void);
	inline void UnlockVMem(void);

	inline BOOL InsertFree(void *p);
	inline void* PopFree();

private:
	CRITICAL_SECTION	m_csLock;						// Virtual Memory의 동기화를 위한 크리티컬 섹션
	DWORD				m_dwSizeObjType;				// Virtual Memory에 할당되는 하나의 객체 사이즈 단위
	DWORD				m_dwCntCommitedObjPool;
	DWORD				m_dwCntCurrentAllocObjPool;		//
	DWORD				m_dwSizeCommitVMem;

	vector<void *>		m_vectorVMemPtr;
	vector<void *>		m_vectorMemoryPointer;
};


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::LockVMem
// 반환되는 형  : void
// 함 수 인 자  : void
// 함 수 설 명  : inline 함수
//					CVMem 객체의 크리티컬섹션을 잠금한다
void CVMem::LockVMem(void)
{
	EnterCriticalSection(&m_csLock);
}


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::UnlockVMem
// 반환되는 형  : void
// 함 수 인 자  : void
// 함 수 설 명  : inline 함수
//					CVMem 객체의 크리티컬섹션을 해제한다
void CVMem::UnlockVMem(void)
{
	LeaveCriticalSection(&m_csLock);
}


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::CommitVMem
// 반환되는 형  : BOOL
// 함 수 인 자  : void *pAddr
// 함 수 인 자  : DWORD dwSize
// 함 수 설 명  : inline 함수
//					예약된 주소를 사용하기 위해 Commit하는 함수
BOOL CVMem::CommitVMem(void *pAddr, DWORD dwSize)
{
	void * pCommit = VirtualAlloc(pAddr, dwSize, MEM_COMMIT, PAGE_READWRITE);
	if(NULL == pCommit)
	{
		int nErr = GetLastError();
		SetLastError(0);
		char	szError[1024];
		sprintf(szError, "CVMem::CommitVMem VirtualAlloc() LastError[%d] pAddr[0x%X] TotalSize[%d]\r\n",
			nErr, pAddr, dwSize);
//		g_pGlobal->WriteSystemLog(szError);
		DBGOUT(szError);

		return FALSE;
	}
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::DecommitVMem
// 반환되는 형  : BOOL
// 함 수 인 자  : void *pAddr
// 함 수 인 자  : DWORD dwSize
// 함 수 설 명  : inline 함수
//					Commit 중인 메모리를 Decommit하기 위한 함수
BOOL CVMem::DecommitVMem(void *pAddr, DWORD dwSize)
{
	BOOL bRet = VirtualFree(pAddr, dwSize, MEM_DECOMMIT);
	if(FALSE == bRet)
	{
		int nErr = GetLastError();
		SetLastError(0);

		char	szError[1024];
		sprintf(szError, "CVMem::DecommitVMem VirtualAlloc() LastError[%d] pAddr[0x%X] TotalSize[%d]\r\n",
			nErr, pAddr, dwSize);
//		g_pGlobal->WriteSystemLog(szError);
		DBGOUT(szError);

		return FALSE;
	}
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::InsertFree
// 반환되는 형  : BOOL
// 함 수 인 자  : DWORD id
// 함 수 설 명  : inline 함수
//					메모리가 해제되면 Stack에 해제된 메모리에 해당하는 id를 추가하는 함수
BOOL CVMem::InsertFree(void *p)
{
//	vector<void *>::iterator itr = find(m_vectorMemoryPointer.begin(), m_vectorMemoryPointer.end(), p);
//	if(itr != m_vectorMemoryPointer.end())
//	{
//		return FALSE;
//	}
	m_vectorMemoryPointer.push_back(p);
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::PopFree
// 반환되는 형  : DWORD
// 함 수 설 명  : inline 함수
//					메모리 할당을 위해 Stack에서 id를 꺼내어 리턴하는 함수
void * CVMem::PopFree()
{
	if(m_vectorMemoryPointer.empty() == true)
	{	// 비어있다. Underflow

		if(AllocVMem(m_dwSizeObjType, m_dwCntCommitedObjPool) == FALSE)
		{
			char	szError[1024];
			sprintf(szError, "CVMem::PopFree Queue Underflow MemoryPointerSize[%d]\r\n",
				m_vectorMemoryPointer.size());
//			g_pGlobal->WriteSystemLog(szError);
			DBGOUT(szError);
			return NULL;
		}
	}
	void *p = m_vectorMemoryPointer.back();
	m_vectorMemoryPointer.pop_back();
	return p;
}



////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::ObjectNew
// 반환되는 형  : void *
// 함 수 설 명  : inline 함수
//					메모리 풀에서 메모리를 하나 할당하여 리턴하는 함수
void * CVMem::ObjectNew()
{
	LockVMem();
	void* pNew = PopFree();					// 쓸수있는 블럭을 주소로 얻는다.
	if(pNew != NULL)
	{
		m_dwCntCurrentAllocObjPool++;
	}
	UnlockVMem();

	return pNew;
}

////////////////////////////////////////////////////////////////////////////////
//
// 함 수 이 름  : CVMem::ObjectDelete
// 반환되는 형  : void
// 함 수 인 자  : void *p
// 함 수 설 명  : inline 함수
//					사용한 메모리를 해제하는 함수(메모리 풀에 추가됨)
void CVMem::ObjectDelete(void *p)
{
	LockVMem();
	if(InsertFree(p))
	{
		m_dwCntCurrentAllocObjPool--;
	}
	UnlockVMem();
}
#endif // !defined(AFX_VMEM_H__6FFF3C69_50F7_4B4B_A40F_D81A0A7713AC__INCLUDED_)
