#ifndef _KILIB_MEMORY_H_
#define _KILIB_MEMORY_H_
#include "types.h"
#include "thread.h"
#ifndef __ccdoc__
namespace ki {
#endif


// W版ではHeapAllocを直接呼び出すバージョンを使う
//#if !defined(_UNICODE) && defined(SUPERTINY)
//	#define USE_ORIGINAL_MEMMAN
//#endif

// 小規模と見なすオブジェクトの最大サイズ
#define SMALL_MAX 64
// 一度に確保するヒープブロックのサイズ
#define BLOCK_SIZ 4096
// 内部実装
struct MemBlock;



//=========================================================================
//@{ @pkg ki.Memory //@}
//@{
//	メモリ割り当て・解放機構
//
//	SUPERTINYオプションを付けてコンパイルすると、標準の
//	mallocやfreeを使えなくなるため、HeapAlloc等のAPIを
//	直接呼び出す必要が出てきます。しかし、こいつらを本当に
//	毎回直に呼んでいると、遅い。もうアホかと、バカかと、
//	って勢いで遅い。そこで、主にnewで動的に小規模メモリを
//	確保することに主眼を据えた簡単なアロケータを使うことにしました。
//
//	<a href="http://cseng.aw.com/book/0,3828,0201704315,00.html">loki</a>
//	ライブラリほぼそのまんまな実装です。
//@}
//=========================================================================

class MemoryManager : public EzLockable
{
public:

	//@{ メモリ割り当て //@}
	void* Alloc( size_t siz );

	//@{ メモリ解放 //@}
	void DeAlloc( void* ptr, size_t siz );

#ifdef USE_ORIGINAL_MEMMAN
private:
	struct FixedSizeMemBlockPool
	{
		void Construct( byte siz );
		void Destruct();
		void*  Alloc();
		void DeAlloc( void* ptr );
		bool isValid();
	private:
		MemBlock* blocks_;
		int       blockNum_;
		int       blockNumReserved_;
		byte      fixedSize_;
		byte      numPerBlock_;
		int       lastA_;
		int       lastDA_;
	};
	FixedSizeMemBlockPool pools_[ SMALL_MAX ];
#endif

private:

	MemoryManager();
	~MemoryManager();

private:

	static MemoryManager* pUniqueInstance_;

private:

	friend void APIENTRY Startup();
	friend inline MemoryManager& mem();
	NOCOPY(MemoryManager);
};



//-------------------------------------------------------------------------

//@{ 唯一のメモリ管理オブジェクトを返す //@}
inline MemoryManager& mem()
	{ return *MemoryManager::pUniqueInstance_; }

//@{ ゼロ埋め作業 //@}
inline void mem00( void* ptrv, int siz )
	{ BYTE* ptr = (BYTE*)ptrv;
	  for(;siz>3;siz-=4,ptr+=4) *(DWORD*)ptr = 0x00000000;
	  for(;siz;--siz,++ptr) *ptr = 0x00; }

//@{ FF埋め作業 //@}
inline void memFF( void* ptrv, int siz )
	{ BYTE* ptr = (BYTE*)ptrv;
	  for(;siz>3;siz-=4,ptr+=4) *(DWORD*)ptr = 0xffffffff;
	  for(;siz;--siz,++ptr) *ptr = 0xff; }



//=========================================================================
//@{
//	標準基底クラス
//
//	JavaのObject や MFCのCObject みたいに使う…わけではなく、
//	単にここから派生すると自動で operator new/delete が高速版に
//	なるので便利だよ、という使い方のための基底クラスです。
//@}
//=========================================================================

class Object
{
#ifdef USE_ORIGINAL_MEMMAN
public:

	static void* operator new( size_t siz )
		{ return mem().Alloc( siz ); }

	static void operator delete( void* ptr, size_t siz )
		{ mem().DeAlloc( ptr, siz ); }
#endif

protected:
	virtual ~Object()
		{}
};



//=========================================================================

}      // namespace ki
#endif // _KILIB_MEMORY_H_
