//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * メモリチェッカヘッダ
 * @author Junpee
 */

#ifndef MEMORY_CHECKER_H_
#define MEMORY_CHECKER_H_

//------------------------------------------------------------------------------
// デバッグ時
#ifdef _DEBUG

/// デバッグ版メモリアロケータを有効にする。
#include <memory>
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

/// newにデバッグ情報を付加する。
#define new  ::new(_NORMAL_BLOCK, __FILE__, __LINE__)

namespace Lamp{

/**
 * メモリチェッカ
 *
 * メモリリークを検出する為のクラスです。<br>
 * システム初期化時に MemoryChecker::initialize()を呼んで下さい。
 * <pre>
 * サンプルコード
 *
 * // 初期化
 * MemoryChecker::initialize();
 *
 * // メモリの詳細な情報をダンプ
 * MemoryChecker::dumpDetail();
 * // メモリの統計情報をダンプ
 * MemoryChecker::dumpStatistics();
 *
 * // 現在のメモリステートを取得
 * MemoryChecker::State state = MemoryChecker::getState();
 *
 * // メモリを使用する処理
 * allocateMemoryMethod();
 *
 * // allocateMemoryMethod()で使用したメモリの詳細な情報をダンプ
 * MemoryChecker::dumpDetail(state);
 * // allocateMemoryMethod()で使用したメモリの統計情報をダンプ
 * MemoryChecker::dumpStatistics(state);
 *
 * // メモリを解放する処理
 * freeMemoryMethod();
 *
 * // freeMemoryMethodでちゃんとメモリが解放されているかチェックする
 * MemoryChecker::leakCheck(state);
 * </pre>
 */
//------------------------------------------------------------------------------
class MemoryChecker{
public:
	/**
	 * メモリ初期化
	 *
	 * システムの初期化時に一度だけ呼んで下さい。
	 */
	static void initialize();

	/**
	 * メモリステート
	 *
	 * メモリの状態をクラス内部に保存します。
	 */
	class State{
	friend class MemoryChecker;
	private:
		_CrtMemState state;
	};

	/**
	 * メモリステートの取得
	 * @return メモリステート
	 */
	static State getState();

	/**
	 * 詳細ダンプ
	 *
	 * メモリの詳細な情報ををデバッグ出力にダンプします。
	 */
	static void dumpDetail();

	/**
	 * 詳細の差分ダンプ
	 *
	 * メモリ差分の詳細な情報ををデバッグ出力にダンプします。
	 * @param oldState 差分を取る以前のステート
	 */
	static void dumpDetail(const State& oldState);

	/**
	 * 統計のダンプ
	 *
	 * メモリの統計情報をデバッグ出力にダンプします。
	 */
	static void dumpStatistics();

	/**
	 * 統計の差分ダンプ
	 *
	 * メモリ差分の統計情報をデバッグ出力にダンプします。
	 * @param oldState 差分を取る以前のステート
	 */
	static void dumpStatistics(const State& oldState);

	/**
	 * メモリリークチェック
	 *
	 * メモリリークをチェックします。
	 * メモリ使用量が同じ場合はリークを検出できません。
	 * メモリ使用量が同じでリークを検出するにはdumpDetailを使用してください。
	 * @param oldState 差分を取る以前のステート
	 @ @return trueならメモリリークが発生している。
	 */
	static bool leakCheck(const State& oldState);

private:
	// コンストラクタ隠蔽
	MemoryChecker(){}

	// 初期化フラグ
	static bool initialized_;
};

} // End of namespace Lamp

//------------------------------------------------------------------------------
// 非デバッグ時
#else // ! _DEBUG

// デバッグを切った時にコンパイルエラーが多発する状態への対策
#include <memory>

namespace Lamp{

/// メモリ
class MemoryChecker{
public:
	/// メモリ初期化ダミー
	inline static void initialize(){}

	/// メモリステート
	class State{};

	/// ステートの取得ダミー
	inline static State getState(){
		State state;
		return state;
	}

	/// 詳細ダンプダミー
	inline static void dumpDetail(){}

	/// 詳細の差分ダンプダミー
	inline static void dumpDetail(State oldState){}

	/// 統計のダンプダミー
	inline static void dumpStatistics(){}

	/// 統計の差分ダンプダミー
	inline static void dumpStatistics(State oldState){}

	/// メモリリークチェックダミー
	inline static bool leakCheck(State oldState){ return false; }

private:
	// コンストラクタ隠蔽
	MemoryChecker(){}
};

} // End of namespace Lamp

#endif // End of _DEBUG

//------------------------------------------------------------------------------
#endif // End of MEMORY_CHECKER_H_
//------------------------------------------------------------------------------
