/*	
 *	clipcoll.h
 *
 *	コレクション
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Tue Jan 06 21:26:41 JST 2015 Naoyuki Sawa
 *	- 新規作成。
 *	- コレクション関連の宣言を、clipmisc.hからclipcoll.hへ分離しました。
 *	  コレクション関連の実装は既に、clipmisc.cからclipcoll.cへ分離してあったので、今回分離したのは宣言のみです。
 *	  宣言も分離することにした理由は、宣言と実装のファイルの対応付けを、分り易くするためです。
 */
#ifndef __CLIP_COLL_H__
#define __CLIP_COLL_H__

/*****************************************************************************
 *	ユーティリティ：コレクションのヘルパ関数
 *****************************************************************************/

/* ヘルパ関数の実装例: コレクションがメモリ管理を行わないポインタ、または、数値
 */
void* ptr_copy(void* a);
void  ptr_delete(void* a);
int   ptr_equals(void* a, void* b);

/* ヘルパ関数の実装例: コレクションがメモリ管理を行う文字列
 * * map_put()は、渡された文字列をコピーして、コレクションに保持します。
 * // * map_get()は、文字列をコピーせず、保持している文字列のポインタをそのまま返します。
 * //   必要に応じて、map_get()の呼び出し元が、文字列のコピーを作成してください。
 * ↓2005/12/11 仕様変更
 * * map_get()は、保持している文字列のコピーを作成して、呼び出し元に返します。
 *   map_get()の呼び出し元は、文字列の使用が終了したら、str_delete()を使って文字列を解放してください。
 *   str_delete()の実装は、単にfree()を行っているだけなので、直接free()を使って解放しても構いません。
 */
void* str_copy(void* a);
void  str_delete(void* a);
int   str_equals(void* a, void* b);

/* ヘルパ関数の実装例: インターフェイスポインタ (UNKNOWN_INTERFACE**)
 * * キーとして用いた場合の等価判定は、オブジェクト比較です。
 *   オブジェクトが複数のインターフェイスをサポートしている場合、
 *   そのオブジェクトに対するUNKNOWNインターフェイスポインタは、複数存在します。
 *   unk_equals()は、それらの異なるインターフェイスポインタを等価と見なします。
 *   このような挙動が必要ない場合(単なるポインタ比較で良い場合)は、
 *   unk_equals()の代りに、ptr_equals()を使ってください。
 * * map_put()は、渡されたインターフェイスポインタをaddref()して、コレクションに保持します。
 * // * map_get()は、インターフェイスポインタをaddref()せず、そのまま返します。
 * //   この挙動は、参照カウントの増減ルール[ルール1-1]に反する、特例です。
 * //   必要に応じて、map_get()の呼び出し元が、addref()を行ってください。
 * //   呼び出し元が、addref()を行わなかった場合は、release()も不要です。
 * ↓2005/12/11 仕様変更
 * * map_get()が、インターフェイスポインタをaddref()して、呼び出し元に返すようになりました。
 *   呼び出し元が、map_get()から返されたインターフェイスポインタに対し、addref()する必要はありません。
 *   呼び出し元は、返されたインターフェイスポインタの使用が終了したら、release()を行う必要があります。
 *   以上の挙動は、参照カウントの増減ルール[ルール1-1]に準拠しています。
 *   すなわち、2005/12/11の仕様変更により、map_get()の挙動だけを特別扱いする必要が無くなりました。
 */
void* unk_copy(void* a);
void  unk_delete(void* a);
int   unk_equals(void* a, void* b);

/*****************************************************************************
 *	ユーティリティ：マップ (コレクション)
 *****************************************************************************/

/* マップ情報 */
typedef struct _MAP_INFO {
	void* (*key_copy)(void* key);			/* キーを複製する、ヘルパ関数 */
	void  (*key_delete)(void* key);			/* キーを削除する、ヘルパ関数 */
	int   (*key_equals)(void* key1, void* key2);	/* キーを比較する、ヘルパ関数 */
	void* (*val_copy)(void* val);			/* 値  を複製する、ヘルパ関数 */
	void  (*val_delete)(void* val);			/* 値  を削除する、ヘルパ関数 */
} MAP_INFO;

/* マップ */
typedef struct _MAP {
	LIST_ENTRY list_head;	/* MAP_NODEのリストヘッダ */
	MAP_INFO map_info;	/* マップ情報 */
} MAP;

/* マップ要素
 * * ガベージコレクションを使用可能とするために、マップ要素とリストエントリの先頭アドレスを揃えてあります。
 *   両者のアドレスが違っていると、ガベージコレクタが未開放のマップ要素を誤って開放してしまうためです。
 * - ガベージコレクションの使用は必須ではありません。
 *   MAP構造体やMAP_NODE構造体のメモリ開放は、ライブラリが明示的に行っています。
 *   キーと値のメモリ管理は、アプリケーション定義のヘルパ関数にて、明示的に行うことが可能です。
 * - ガベージコレクションを使うと、明示的な、キーと値のメモリ解放を省略し、ヘルパ関数を簡略化できます。
 */
typedef struct _MAP_NODE {
	LIST_ENTRY list_entry;	/* MAP_NODEのリストエントリ */
	void* key;		/* キー (実際の型はアプリケーション定義) */
	void* val;		/* 値   (実際の型はアプリケーション定義) */
} MAP_NODE;

/* マップを作成します。
 * [in]
 *	map_info	マップ情報。
 * [out]
 *	戻り値		マップ。
 */
MAP* map_create(const MAP_INFO* map_info);

/* マップを削除します。
 * [in]
 *	map		マップ。
 * [note]
 *	* 自動的にmap_clear()を呼び、残っているマップ要素をすべて削除します。
 *	  明示的にmap_clear()を呼んでおく必要はありません。
 */
void map_delete(MAP* map);

/* マップの全要素を削除します。
 * [in]
 *	map		マップ。
 * [note]
 *	* 各マップ要素について、key_delete()ヘルパ関数を用いて、キーを削除します。
 *	                        val_delete()ヘルパ関数を用いて、値  を削除します。
 */
void map_clear(MAP* map);

/* 指定されたキーに対応するマップ要素が有るか、判定します。
 * [in]
 *	map		マップ。
 *	key		キー。
 * [out]
 *	戻り値		マップ要素が有れば、  0以外の値を返します。
 *			マップ要素が無ければ、0を返します。
 */
int map_contains(MAP* map, void* key);

/* 指定されたキーに対応するマップ要素を作成し、値を格納します。
 * [in]
 *	map		マップ。
 *	key		キー。
 *	val		値。
 * [note]
 *	* key_copy()ヘルパ関数を用いて、キーを複製し、マップ要素に格納します。
 *	  アプリケーションは、呼び出し時に指定したkeyを維持する必要はありません。
 *	  ただし、key_copy()ヘルパ関数が複製を行わない場合は、この限りではありません。
 *	* val_copy()ヘルパ関数を用いて、値を複製し、マップ要素に格納します。
 *	  アプリケーションは、呼び出し時に指定したvalを維持する必要はありません。
 *	  ただし、val_copy()ヘルパ関数が複製を行わない場合は、この限りではありません。
 *	* 既に、指定されたキーに対応する値が存在する場合は、既存の値を削除します。
 *	  既存の値の削除には、val_delete()ヘルパ関数が利用されます。
 */
void map_put(MAP* map, void* key, void* val);

/* 指定されたキーに対応するマップ要素の、値を取得します。
 * [in]
 *	map		マップ。
 *	key		キー。
 * [out]
 *	戻り値		値。
 * [note]
 *	* 指定されたキーに対応するマップ要素が存在しない場合は、アサートします。
 *	  先にmap_contains()を用いて、キーに対応するマップ要素が存在することを確認してください。
 *	  <例>	if(map_contains(map, key)) {
 *			val = map_get(map, key);
 *			...
 *			free(val); // 2005/12/11の仕様変更により、値の解放が必要となりました。
 *		}
 *	// * 返される値は、複製ではなく、マップ要素が保持している値をそのまま返します。
 *	//   呼び出し側アプリケーションにて、返された値を削除してはいけません。
 *	//↓2005/12/11 仕様変更
 *	* map_get()は、val_copy()ヘルパ関数を用いて値の複製を作成し、その複製を返します。
 *	  返された値の所有権は、map_get()を呼び出した側のみに有ります。
 *	  map_get()を呼び出した側は、返された値を適切に解放することを忘れないでください。
 */
void* map_get(MAP* map, void* key);

/* 指定されたキーに対応するマップ要素を削除します。
 * [in]
 *	map		マップ。
 *	key		キー。
 * [note]
 *	* 指定されたキーに対応するマップ要素が存在しない場合は、アサートします。
 *	  先にmap_contains()を用いて、キーに対応するマップ要素が存在することを確認してください。
 *	  <例>	if(map_contains(map, key)) {
 *			map_remove(map, key);
 *		}
 *	* 削除するマップ要素のキーは、key_delete()ヘルパ関数を用いて、自動的に削除されます。
 *	  削除するマップ要素の値  は、val_delete()ヘルパ関数を用いて、自動的に削除されます。
 */
void map_remove(MAP* map, void* key);

/* マップを複製します。
 * [in]
 *	map		複製元のマップ。
 * [out]
 *	戻り値		複製したマップ。
 * [note]
 *	* この関数が行う処理は、以下のとおりです。
 *	  1. 複製元のマップと同じマップ情報を持つ、空のマップを作成します。
 *	     これが、複製先のマップとなります。
 *	  2. 複製元のマップの各要素のキーと値について、key_copyとval_copy()ヘルパ関数を用いて複製し、
 *	     複製先のマップへ追加します。
 *	  3. 複製先のマップを返します。
 */
MAP* map_duplicate(MAP* map);

/* マップ要素に含まれている、すべてのキーから成る、リストを作成します。
 * [in]
 *	map		マップ。
 * [out]
 *	戻り値		リスト。
 * [note]
 *	* 作成されたリストのヘルパ関数は、作成元のマップのヘルパ関数の一部と同一となります。
 *	  リスト情報のヘルパ関数と、マップのヘルパ関数との対応は、以下のとおりです。
 *		==== 作成元のマップ ====    ==== 作成されたリスト ====
 *		map->map_info.key_copy   → list->list_info.val_copy  
 *		map->map_info.key_delete → list->list_info.val_delete
 *		map->map_info.key_equals → 使いません
 *		map->map_info.val_copy   → 使いません
 *		map->map_info.val_delete → 使いません
 *	* 返されたリストが不要になったら、呼び出し元にてlist_delete()を実行し、リストを削除してください。
 */
struct _LIST* map_keys(MAP* map);

/* マップが空か否か調べます。
 * [in]
 *	map		マップ。
 * [out]
 *	戻り値		空ならば0以外を返します。
 *			空でなければ0を返します。
 */
int map_empty(MAP* map);

/*****************************************************************************
 *	ユーティリティ：リスト (コレクション)
 *****************************************************************************/

/* リスト情報 */
typedef struct _LIST_INFO {
	void* (*val_copy)(void* val);	/* 値を複製する、ヘルパ関数 */
	void  (*val_delete)(void* val);	/* 値を削除する、ヘルパ関数 */
} LIST_INFO;

/* リスト */
typedef struct _LIST {
	LIST_ENTRY list_head;	/* LIST_NODEのリストヘッダ */
	LIST_INFO list_info;	/* リスト情報 */
} LIST;

/* リスト要素
 * * ガベージコレクションを使用可能とするために、リスト要素とリストエントリの先頭アドレスを揃えてあります。
 *   両者のアドレスが違っていると、ガベージコレクタが未開放のリスト要素を誤って開放してしまうためです。
 * - ガベージコレクションの使用は必須ではありません。
 *   LIST構造体やLIST_NODE構造体のメモリ開放は、ライブラリが明示的に行っています。
 *   値のメモリ管理は、アプリケーション定義のヘルパ関数にて、明示的に行うことが可能です。
 * - ガベージコレクションを使うと、明示的な、値のメモリ解放を省略し、ヘルパ関数を簡略化できます。
 */
typedef struct _LIST_NODE {
	LIST_ENTRY list_entry;	/* LIST_NODEのリストエントリ */
	void* val;		/* 値 (実際の型はアプリケーション定義) */
} LIST_NODE;

/* リストを作成します。
 * [in]
 *	list_info	リスト情報。
 * [out]
 *	戻り値		リスト。
 */
LIST* list_create(const LIST_INFO* list_info);

/* リストを削除します。
 * [in]
 *	list		リスト。
 * [note]
 *	* 自動的にlist_clear()を呼び、残っているマップ要素をすべて削除します。
 *	  明示的にlist_clear()を呼んでおく必要はありません。
 */
void list_delete(LIST* list);

/* リストの全要素を削除します。
 * [in]
 *	list		リスト。
 * [note]
 *	* 各リスト要素について、val_delete()ヘルパ関数を用いて、値を削除します。
 */
void list_clear(LIST* list);

/* リストの要素数を取得します。
 * [in]
 *	list		リスト。
 * [out]
 *	戻り値		要素数。
 */
int list_size(LIST* list);

/* インデクスにて指定された位置に、値を格納します。
 * [in]
 *	list		リスト。
 *	index		インデクス。(0～size-1)
 *	val		値。
 * [note]
 *	* インデクスは、有効な位置(0以上、配列サイズ未満)でなければなりません。
 *	  この範囲外のインデクスが指定された場合は、アサートします。
 *	  空のリストに対してこの関数を呼び出した場合は、常にアサートします。
 *	* val_copy()ヘルパ関数を用いて、値を複製し、リスト要素に格納します。
 *	  アプリケーションは、呼び出し時に指定したvalを維持する必要はありません。
 *	  ただし、val_copy()ヘルパ関数が複製を行わない場合は、この限りではありません。
 *	* 指定された位置に存在する既存の値は、自動的に削除されます。
 *	  既存の値の削除には、val_delete()ヘルパ関数が利用されます。
 */
void list_set(LIST* list, int index, void* val);

/* インデクスにて指定された位置の、値を取得します。
 * [in]
 *	list		リスト。
 *	index		インデクス。(0～size-1)
 * [out]
 *	戻り値		値。
 * [note]
 *	* インデクスは、有効な位置(0以上、配列サイズ未満)でなければなりません。
 *	  この範囲外のインデクスが指定された場合は、アサートします。
 *	  空のリストに対してこの関数を呼び出した場合は、常にアサートします。
 *	* list_get()は、val_copy()ヘルパ関数を用いて値の複製を作成し、その複製を返します。
 *	  返された値の所有権は、list_get()を呼び出した側のみに有ります。
 *	  list_get()を呼び出した側は、返された値を適切に解放することを忘れないでください。
 */
void* list_get(LIST* list, int index);

/* リストの末尾に、値を追加します。
 * [in]
 *	list		リスト。
 *	val		値。
 * [note]
 *	* "list_insert(list, list_size(list), val)"と等価です。
 */
void list_add(LIST* list, void* val);

/* インデクスにて指定された位置に、値を追加します。
 * [in]
 *	list		リスト。
 *	index		インデクス。(0～size)
 *	val		値。
 * [note]
 *	* インデクスは、有効な位置(0以上、配列サイズ未満)、または、末尾(=配列サイズ)でなければなりません。
 *	  この範囲外のインデクスが指定された場合は、アサートします。
 *	* val_copy()ヘルパ関数を用いて、値を複製し、リスト要素に格納します。
 *	  アプリケーションは、呼び出し時に指定したvalを維持する必要はありません。
 *	  ただし、val_copy()ヘルパ関数が複製を行わない場合は、この限りではありません。
 *	* インデクスに、配列サイズ未満を指定した場合、追加した位置よりも後の要素は、ひとつづつ、後へ移動します。
 */
void list_insert(LIST* list, int index, void* val);

/* インデクスにて指定された位置の、値を削除します。
 * [in]
 *	list		リスト。
 *	index		インデクス。(0～size-1)
 * [note]
 *	* インデクスは、有効な位置(0以上、配列サイズ未満)でなければなりません。
 *	  この範囲外のインデクスが指定された場合は、アサートします。
 *	  空のリストに対してこの関数を呼び出した場合は、常にアサートします。
 *	* 指定された位置に存在する既存の値は、自動的に削除されます。
 *	  既存の値の削除には、val_delete()ヘルパ関数が利用されます。
 *	* 削除した位置よりも後の要素は、ひとつづつ、前へ移動します。
 */
void list_remove(LIST* list, int index);

/* リストを複製します。
 * [in]
 *	list		複製元のリスト。
 * [out]
 *	戻り値		複製したリスト。
 * [note]
 *	* この関数が行う処理は、以下のとおりです。
 *	  1. 複製元のリストと同じリスト情報を持つ、空のリストを作成します。
 *	     これが、複製先のリストとなります。
 *	  2. 複製元のリストの各要素の値について、val_copy()ヘルパ関数を用いて複製し、
 *	     複製先のリストへ追加します。
 *	  3. 複製先のリストを返します。
 */
LIST* list_duplicate(LIST* list);

/* リストが空か否か調べます。
 * [in]
 *	list		リスト。
 * [out]
 *	戻り値		空ならば0以外を返します。
 *			空でなければ0を返します。
 * [note]
 *	* リストが空か否かを調べるだけならば、
 *		if(!list_size(list)) { 空の場合の処理 } else { 空でない場合の処理 }
 *	  とするよりも、
 *		if(list_empty(list)) { 空の場合の処理 } else { 空でない場合の処理 }
 *	  とする方が高速です。
 */
int list_empty(LIST* list);

/*****************************************************************************
 *	ユーティリティ：プール (コレクション)
 *****************************************************************************/

#if 0 /*{{2006/12/06:pool_free()から返却先プールの引数を不要とする変更により削除*/
///* * Mon Dec 04 16:24:06 JST 2006 Naoyuki Sawa
// * - malloc()、free()のオーバーヘッドを避けるための、メモリブロックプールです。
// *   明示的な、プールの初期化とクリーンアップを行わなくて良いのが特徴です。
// * - 以下のように利用してください。
// *
// * ①POOL構造体を、グローバル変数(またはstatic変数)として定義してください。
// *   定義と同時に、sizeメンバをメモリブロック単位のサイズに初期化してください。
// *
// *	POOL foo_pool = { sizeof(FOO) };
// *
// * ②pool_alloc()を呼び出して、メモリブロックを確保してください。
// *   適切に、ヒープまたはプールからメモリブロックが割り当てられます。
// *   割り当てに失敗した場合は、pool_alloc()内部でアサートするので、戻り値を検査する必要はありません。
// *   返されたメモリブロックは、pool_alloc()によってゼロクリアされています。
// *
// *	int main(int argc, char* argv[]) {
// *		FOO* foo1 = pool_alloc(&foo_pool);
// *
// * ③pool_free()を呼び出して、不要になったメモリブロックをプールに返してください。
// *
// *		pool_free(&foo_pool, foo1);
// *
// * ④最終的な、プールのクリーンアップは不要です。
// *   割り当てたメモリブロックが全てプールに返されたタイミングで、自動的に全てヒープに返されます。
// *
// *		foo1 = pool_alloc(&foo_pool);	// 割り当て数1、プール数0 (ヒープから確保)
// *		foo2 = pool_alloc(&foo_pool);	// 割り当て数2、プール数0 (ヒープから確保)
// *		pool_free(&foo_pool, foo1);	// 割り当て数1、プール数1 (プールへ返す)
// *		foo3 = pool_alloc(&foo_pool);	// 割り当て数2、プール数0 (プールから確保)
// *		pool_free(&foo_pool, foo2);	// 割り当て数1、プール数1 (プールへ返す)
// *		pool_free(&foo_pool, foo3);	// 割り当て数0、プール数2 (プールへ返す)→(ヒープへ返す)→プール数0
// *
// * - 上では構造体FOOだけのためにfoo_poolを用意していますが、複数の構造体で一つのプールを共有することも可能です。
// *   たとえば、構造体FOOとBARで一つのプールを共有する場合、大きい方の構造体サイズをPOOL.sizeに設定してください。
// * - 割り当て数がひんぱんに0に戻るような割り当て/開放パターンの場合、オーバーヘッドが低減されない場合があります。
// *
// *		foo1 = pool_alloc(&foo_pool);	// 割り当て数1、プール数0 (ヒープから確保)
// *		pool_free(&foo_pool, foo1);	// 割り当て数0、プール数1 (プールへ返す)→(ヒープへ返す)→プール数0
// *		foo2 = pool_alloc(&foo_pool);	// 割り当て数1、プール数0 (ヒープから確保)
// *		pool_free(&foo_pool, foo2);	// 割り当て数0、プール数1 (プールへ返す)→(ヒープへ返す)→プール数0
// *		foo3 = pool_alloc(&foo_pool);	// 割り当て数1、プール数0 (ヒープから確保)
// *		pool_free(&foo_pool, foo3);	// 割り当て数0、プール数1 (プールへ返す)→(ヒープへ返す)→プール数0
// *
// * - 4バイト余計に割り当てて先頭に返却先プールへのポインタを格納し、ユーザーには+4の位置を示す方法もあります。
// *   そのようにすれば、pool_free()から返却先プールの引数が不要になり便利なのですが、今回は採用しませんでした。
// *   ユーザーが保持するポインタがメモリブロック先頭を指していないと、ガーベージコレクタと併用できなくなるからです。
// */
//typedef struct _POOL {
//	int size;			/* 割り当てるメモリブロック単位のバイト数 */
//	int cnt;			/* (割り当て回数 - 開放回数) */
//	struct _POOL_NODE* first;	/* プール内の最初のメモリブロックへのリンク (NULL=空) */
//} POOL;
//
//typedef struct _POOL_NODE {
//	struct _POOL_NODE* next;	/* プール内の次のメモリブロックへのリンク (NULL=終端) */
//} POOL_NODE;
//
///* メモリブロックを確保します。
// * [in]
// *	pool		プール。
// * [out]
// *	戻り値		メモリブロック。
// */
//void* pool_alloc(POOL* pool);
//
///* メモリブロックを開放します。
// * [in]
// *	pool		プール。
// *	ptr		メモリブロック。
// */
//void pool_free(POOL* pool, void* ptr);
#endif /*}}2006/12/06:pool_free()から返却先プールの引数を不要とする変更により削除*/
//↓ * Wed Dec 06 03:36:51 JST 2006 Naoyuki Sawa
//↓ - pool_free()から返却先プールの引数を不要としました。
//↓   メモリブロック当り12バイトのオーバーヘッドが増えましたが、使い易さを優先してこのような仕様に変更しました。
//↓ - 割り当て中のメモリブロック先頭をチェインすることで、ガーベージコレクションの対象となることを防いでいます。
//↓   なぜこのような対策が必要かは、上のコメントアウトしたブロック内のコメントの、最後の部分を参照してください。
//↓ - pool_free()から返却先プールの引数を不要としたこと以外は、使用方法は変わっていません。
//↓   上のコメントアウトしたブロック内のコメントを参照してください。

/* * Tue Jan 02 22:11:35 JST 2007 Naoyuki Sawa
 * - プールに、参照カウント式ガーベージコレクションの機能を内包しました。
 * - プールから確保したメモリブロックは、常にプールにチェインにされているため、不要になったブロックを判断できず、通常のGCで回収できません。
 *   そこで、参照カウント式ガーベージコレクションの機能を内包することにしました。
 * - この機能はプールに直接関係のある機能ではなく、単純な確保と解放だけの管理ならば、ガーベージコレクションの仕組みは不要です。
 *   しかし、複数の箇所からメモリブロックを共有するような使い方をする場合、いずれ必要になる機能でもあります。
 *   必要な場合だけ、アプリケーション側で参照カウントの管理を行う方法もありますが、簡単のため、プールの機能に内包してしまうことにしました。
 * - この機能追加によるアプリケーションインターフェイスの変化は、pool_lock()が増えたことだけです。
 *   pool_alloc()直後の参照カウントは1であり、pool_free()すれば0になって解放されるので、既存のアプリケーションへの影響はありません。
 *   メモリブロック毎に4バイトのオーバーヘッド(参照カウントの分)が増えてしまいましたが、まあ、許容範囲だと思います。
 * - NULLポインタに対するpool_lock()とpool_free()は何も行わないようにしました。
 *   従って、あるメモリブロックpの参照カウントを増やす場合に、pがNULLであるか否かを判断する必要はありません。
 *   pがNULLならば、何も行いません。
 *
 *	<例>
 *		void MyClass_constructor(MyClass* This, void* p) {
 *			This->p = p;
 *			pool_lock(This->p); // pがNULLでも大丈夫
 *		}
 *		void MyClass_destructor(MyClass* This) {
 *			pool_free(This->p); // pがNULLでも大丈夫
 *		}
 *
 * - 通常のGCとの併用も可能です。
 *   その場合、malloc()/free()で確保・解放するオブジェクトはマーク&スイープ方式のGC、
 *   pool_alloc()/pool_free()/pool_lock()で確保・解放するオブジェクトは参照カウント式のGC、と、二方式のGCが混在することに注意してください。
 * - 以下に、使用例を示します。
 *
 *	void main() {
 *		void* p;
 *		p = pool_alloc(&pool);	// 参照カウント=1
 *		foo1(p);		// 参照カウント=2
 *		foo2(p);		// 参照カウント=3
 *		pool_free(p);		// 参照カウント=2
 *		bar1(p);		// 参照カウント=1
 *		bar2(p);		// 参照カウント=0 -> 解放
 *	}
 *
 *	void* g_ptr1;
 *	void foo1(void* p) {
 *		g_ptr1 = p;
 *		pool_lock(g_ptr1);	// 参照カウント+1
 *	}
 *	void bar1() {
 *		pool_free(g_ptr1);	// 参照カウント-1
 *		g_ptr1 = NULL;
 *	}
 *
 *	void* g_ptr2;
 *	void foo2(void* p) {
 *		g_ptr2 = p;
 *		pool_lock(g_ptr2);	// 参照カウント+1
 *	}
 *	void bar2() {
 *		pool_free(g_ptr2);	// 参照カウント-1
 *		g_ptr2 = NULL;
 *	}
 *
 */

/* * Sat Mar 14 21:13:42 JST 2009 Naoyuki Sawa
 * - プールに、確保時コールバックと解放時コールバックを追加しました。
 * - 以下に、使用例を示します。
 *
 *	void foo_init_proc(void* data) {
 *		// 確保したメモリブロックの、共通初期化処理など
 *	}
 *	void foo_free_proc(void* data) {
 *		// 解放するメモリブロックの、共通クリーンアップ処理など
 *	}
 *	POOL foo_pool = { sizeof(FOO), foo_init_proc, foo_free_proc };
 *	void main() {
 *		FOO* foo = pool_alloc(&foo_pool);	// foo_init_proc()が呼び出されます。
 *		pool_lock(foo);		// 参照カウント=2
 *		pool_free(foo);		// 参照カウント=1
 *		pool_free(foo);		// 参照カウント=0。foo_free_proc()が呼び出されます。
 *	}
 */

//{{2009/03/14:確保時コールバックと解放時コールバックを追加するために変更
//typedef struct _POOL {
//	int size;		/* このフィールドだけ、ユーザーが設定してください */
//	int init;		/* (内部使用: 初期化済み or 未初期化の判断用) */
//	LIST_ENTRY alloc_list;	/* (内部使用: 割り当て中メモリブロックの先頭をチェインし、GCを防ぐ) */
//	LIST_ENTRY free_list;	/* (内部使用: 解放されたメモリブロックの先頭をチェインして保持する) */
//} POOL;
//↓2009/03/14:確保時コールバックと解放時コールバックを追加するために変更
typedef struct _POOL {
	int size;			/* 割り当てるメモリブロックのバイト数。(ユーザーが設定してください) */
	void (*init)(void* data);	/* 確保時コールバック。(ユーザーが設定してください。不要ならばNULL) */
	void (*free)(void* data);	/* 解放時コールバック。(ユーザーが設定してください。不要ならばNULL) */
	int mark;			/* (内部使用: 初期化済み or 未初期化の判断用) */
	LIST_ENTRY alloc_list;		/* (内部使用: 割り当て中メモリブロックの先頭をチェインし、GCを防ぐ) */
	LIST_ENTRY free_list;		/* (内部使用: 解放されたメモリブロックの先頭をチェインして保持する) */
} POOL;
//}}2009/03/14:確保時コールバックと解放時コールバックを追加するために変更

typedef struct _POOL_NODE {			/* (内部使用) */
	LIST_ENTRY list_entry;			/* POOL.alloc_list、または、POOL.free_listにチェインする */
	POOL* pool;				/* このメモリブロックの割り当て元プールへのポインタ */
	/*{{2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包*/
	int ref_cnt;				/* 参照カウント */
	/*}}2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包*/
	/*unsigned char data[pool->size];*/	/* ユーザーには、この領域の先頭アドレスが返されます */
} POOL_NODE;

/* メモリブロックを確保します。
 * [in]
 *	pool		プール。
 * [out]
 *	戻り値		メモリブロック。
 * [note]
 *	{{2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包
 *	- メモリブロックを確保した直後の、参照カウントの初期値は1です。
 *	}}2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包
 */
void* pool_alloc(POOL* pool);

/* メモリブロックを開放します。
 * [in]
 *	data		メモリブロック。
 *			NULLならば、何も行いません。
 * [note]
 *	{{2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包
 *	- 参照カウントを減らし、参照カウントが残っていたら解放しません。
 *	}}2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包
 */
void pool_free(void* data/*NULLOK*/);

/*{{2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包*/
/* 参照カウントを増やします。
 * [in]
 *	data		メモリブロック。
 *			NULLならば、何も行いません。
 */
void pool_lock(void* data/*NULLOK*/);
/*}}2007/01/02追加: 参照カウント式ガーベージコレクションの機能を内包*/

#endif//__CLIP_COLL_H__
