/*!
	簡単なメモリプール

	chunk単位で確保する
	chunkサイズ*grow数が最大確保サイズとなり、それ以上は内部でnewされる
	マルチスレッド不可、外部で同期する必要あり	
*/
#pragma once
#include "SimpleArrayTemplate.h"

/*!
	メモリチャンク管理構造体
*/
struct SSimpleMemoryPoolSubChunk
{
	//!	使用フラグ、0で未使用ブロック, 1で使用ブロック
	int	m_using;

	//!	ブロックサイズ、>0で最初のブロック、<0で2ブロック目以降
	int	m_blockSize;
};

/*!
	メモリチャンク

	一回のgrowで、このクラスが一個生成される
*/
class CSimpleMemoryPoolChunk
{
public:
	CSimpleMemoryPoolChunk();
	virtual ~CSimpleMemoryPoolChunk();

	//////////////////////////////////////////////////////////////
	//	操作
	//////////////////////////////////////////////////////////////
	//!	初期化
	int Init(int blockSize, int blockCount);

	//!	終了
	void Close();

	//!	確保
	void *Alloc(int blockCount);

	//!	開放
	int Free(void *toFree);

	//!	確保中のメモリブロック数
	int GetAllocedCount()
	{
		return m_usingCount;
	}

	//!	空き容量
	int GetFreeCount()
	{
		return m_poolSize - m_usingCount;
	}

protected:
	//////////////////////////////////////////////////////////////
	//	補助
	//////////////////////////////////////////////////////////////
	//!	ポインタからブロックインデックスを取得
	int GetBlockIndex(void *ptr);

	//!	連続空き容量の取得
	int GetFreeBlockSize(int startIndex, int maxCount);

	//!	連続使用容量の取得
	int GetUsingBlockSize(int startIndex);

	//!	使用中にする
	void *MarkToUsing(int startIndex, int count);

	//!	空きにする
	void MarkToFree(int startIndex);

	//////////////////////////////////////////////////////////////
	//	メンバ変数
	//////////////////////////////////////////////////////////////
	//!	管理
	SSimpleMemoryPoolSubChunk	*m_controlBlock;

	//!	バッファ
	char						*m_buf;

	//!	ブロックサイズ
	int							m_blockSize;

	//!	ブロック数
	int							m_poolSize;

	//!	使用ブロック数
	int							m_usingCount;
};


/*!
	簡単なメモリプール
*/
class CSimpleMemoryPool
{
public:
	CSimpleMemoryPool();
	virtual ~CSimpleMemoryPool(void);

	//////////////////////////////////////////////////////////////
	//	操作
	//////////////////////////////////////////////////////////////
	//!	初期化
	void Init(int blockSize, int growCount);

	//!	確保しておく
	void PreCharge();

	//!	確保
	void *Alloc(int size);

	//!	開放
	void Free(void *toFree);

	//!	開放を試みる
	int TryFree(void *toFree);

	//!	現在のチャンク数取得
	int GetChunkCount();

protected:
	//////////////////////////////////////////////////////////////
	//	補助
	//////////////////////////////////////////////////////////////
	//!	増大させる
	int Grow();

	//!	減少させる
	int Slim();

	//!	現在の完全空きプール数取得
	int GetFreePoolCount();

	//!	解放
	void Close();

	//!	確保を試みる
	void *TryAlloc(int blockCount);

	//!	もし拡張ブロックなら、解放する
	int TryFreeExtBlock(void *ptr);

	//!	解放を試みる
	int TryFreeManaged(void *ptr);

	//////////////////////////////////////////////////////////////
	//	メンバ変数
	//////////////////////////////////////////////////////////////
	//!	メモリプール
	CPtrArrayTemplate<CSimpleMemoryPoolChunk*>		m_memoryPools;

	//!	内部でnewしたメモリブロック
	CPtrArrayTemplate<char *>						m_extBlocks;

	//!	ブロックサイズ
	int												m_blockSize;

	//!	増加ブロック数
	int												m_growCount;

	//!	初期化フラグ
	int												m_init;
};
