#ifndef COMMON_FUNCS_H_INCLUDED
#define COMMON_FUNCS_H_INCLUDED

#include <windows.h>
#include "java_utf8.h"

/**
 * 致命的エラー発生時に表示するメッセージ定数
 */
#define	FATAL_ERROR_NO_MEMORY	((_TCHAR*)0x80000001)

/**
 * 致命的なエラーが発生したことを示すダイアログボックスを表示後、
 * プログラムを終了させる
 */
void fatal_error(const _TCHAR* msg);

/**
 * デバッグ出力マクロ
 */
#ifdef DEBUG

extern void dbg_utf8(java_utf8* msg);
extern void dbg_int(int);
extern void dbg_uint(unsigned int);

#define	DBG(s)			OutputDebugString(s)
#define DBG_UTF8(utf8)	dbg_utf8(utf8)
#define DBG_INT(i)		dbg_int(i)
#define DBG_UINT(i)		dbg_uint(i)

#else

#define DBG(s)			__noop
#define DBG_UTF8(utf8)	__noop
#define DBG_INT			__noop
#define DBG_UINT		__noop

#endif


/**
 * big-endian から little-endian に変換する
 */
#define TO_LITTLE_ENDIAN(value) \
	(((value) << 24) | (((value) & 0xff00) << 8) | (((value) & 0xff0000) >> 8) | ((value & 0xff000000) >> 24))

/**
 * 指定された変数のうち、"1"となっているビットの数を数える
 *
 * http://www.nminoru.jp/~nminoru/programming/bitcount.html
 * からの引用
 */
inline int count_bits(__int32 bits) {
  bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555);
  bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333);
  bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f);
  bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff);
  return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff);
}

/**
 * 指定された変数のNTZ (Number of Training Zero)を求める
 *
 * http://www.nminoru.jp/~nminoru/programming/bitcount.html
 * からの引用
 */
inline int get_number_of_training_zero(__int32 bits) {
	return count_bits((bits & (-bits)) - 1);
}

/**
 * 最下位ビットをクリアする
 */
inline __int32 clear_LSB(__int32 bits) {
	return bits & ((unsigned __int32) bits - 1);
}

/**
 * JVMのバージョンを返す
 */
LARGE_INTEGER get_jvm_version();

/**
 * PermanentHeapクラス
 * internした文字列やClassFile構造体など、細かい単位で確保し、かつJVM終了まで開放されないメモリ領域を
 * 効率よく管理するためのクラス。
 * ToDo: ClassFileのロード失敗時に「ロールバック」する仕組みを作成する
 */
struct permanent_heap_block;
class PermanentHeap {
private:
	/**
	 * ヒープブロック本体
	 */
	permanent_heap_block* head;

	/**
	 * ヒープブロックのサイズ
	 */
	size_t blockSize;

	/**
	 * 最小確保サイズ
	 */
	size_t minimumAllocationSize;

	/**
	 * ブロックを確保する
	 */
	permanent_heap_block* allocateBlock();

	/**
	 * ブロックサイズを返す
	 */
	inline size_t getBlockSize() { return blockSize; }

public:
	PermanentHeap(size_t blockSize);
	~PermanentHeap();

	/**
	 * 指定されたサイズのメモリを確保する
	 */
	void* allocate(size_t size);

	/**
	 * 最小確保サイズを設定する。
	 * 空き領域の検索を高速化するため、１ブロック内の空き領域がここで指定したサイズよりも
	 * 小さくなると、そのブロックは空き領域の検索対象からはずす
	 */
	inline size_t getMinimumAllocationSize() { return this->minimumAllocationSize; }

	/**
	 * 最小確保サイズを返す。
	 */
	inline void setMinimumAllocationSize(size_t size) { this->minimumAllocationSize = size; }
};
#endif