/*	
 *	clipwkst.c
 *
 *	ワークシート(多階層ハッシュテーブル)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Mon Jul 13 21:22:16 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Wed Jul 15 01:12:55 JST 2015 Naoyuki Sawa
 *	- Worksheet_ref_l(),Worksheet_ref_a(),Worksheet_ref_v()を追加しました。
 *	- Worksheet_sum_l(),Worksheet_sum_a(),Worksheet_sum_v()を追加しました。
 *	* Thu Jul 16 22:21:18 JST 2015 Naoyuki Sawa
 *	- Worksheet_sort(),Worksheet_sort_l(),Worksheet_sort_a(),Worksheet_sort_v()を追加しました。
 *	* Sun Jul 19 12:59:05 JST 2015 Naoyuki Sawa
 *	- コメントのみ追記:
 *	  当モジュールの関数は、キーや値に指定できるのは数値のみで、文字列は指定できません。
 *	  キーや値に文字列を指定したい場合は、本日clipstr.cモジュールに追加した、quark_from_string(),quark_to_string()を併用してください。
 *	  <例>
 *	  │Worksheet_set_l(ws,quark_from_string("Value"),quark_from_string("Key"),-1);
 *	  │iVal=Worksheet_get_l(ws,quark_from_string("Key"),-1);
 *	  │if(iVal!=-1){puts(quark_to_string(iVal));}
 */
#include "clip.h"
/****************************************************************************
 *	作成/開放
 ****************************************************************************/
//集計表の単一階層を作成する。
// - この階層を列と見なすか行と見なすかは、アプリケーション側の解釈次第です。
ST_Worksheet* Worksheet_new() {
	//集計表の単一階層のメモリを確保する。
	ST_Worksheet* ws = calloc(1, sizeof(ST_Worksheet));
	if(!ws) { DIE(); }
	//ハッシュテーブルを作成する。
	ws->tKey = ght_create(0);		//初期サイズを指定しない。
	ght_set_rehash(ws->tKey, 1);	//自動リサイズを有効とする。
	//集計表の単一階層を返す。
	return ws;
}
/*--------------------------------------------------------------------------*/
//集計表の全階層を開放する。
void Worksheet_free(ST_Worksheet* ws) {
	int iKey;
	ST_Worksheet_Iterator it;
	//ヌルポインタに対して呼出された場合は、何もしない。
	if(!ws) { return; }	//ここまで
	//子階層を全て開放する。
	for(iKey = Worksheet_first_l(ws, &it, -1);
	    iKey != -1;
	    iKey = Worksheet_next(&it)) { Worksheet_unset_l(ws, iKey, -1); }
	//この階層を開放する。
	ght_finalize(ws->tKey);
	free(ws);
}
/****************************************************************************
 *	参照
 ****************************************************************************/
//集計表のノードを参照する。
// - 指定されたノードが存在しない場合は、ヌルポインタを返します。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、引数wsを返します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
ST_Worksheet* Worksheet_ref_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	ST_Worksheet* pChild;
	va_list ap;
	va_start(ap, ws);
	pChild = Worksheet_ref_a(ws, ap);
	va_end(ap);
	return pChild;
}
/*--------------------------------------------------------------------------*/
ST_Worksheet* Worksheet_ref_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	return Worksheet_ref_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
ST_Worksheet* Worksheet_ref_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	int iKey;
	ST_Worksheet* pChild;
	//ヌルポインタに対して呼出された場合は、指定されたノードが存在しないのと同義と見なして、ヌルポインタを返す。
	if(!ws) { return NULL; }	//ここまで
	//次のキーを取得する。
	iKey = *aKey++;
	//キーが終端ならば、引数wsを返す。
	if(iKey == -1) { return ws; }	//ここまで
	//キーに対応する子階層(有れば)を取得する。
	pChild = ght_get(ws->tKey, sizeof(int), &iKey);
	//キーに対応する子階層(有れば)に対して、再帰する。
	// - キーに対応する子階層が無かった場合も、同じ処理で安全である。
	return Worksheet_ref_v(pChild/*ヌル可*/, aKey);
}
/****************************************************************************
 *	取得
 ****************************************************************************/
//集計表のセルの値を取得する。
// - 集計表のセルの値が未設定だった場合は、(0)を返します。
//   未設定の(0)と、明示的に設定された(0)を、区別する方法は有りません。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、この階層の値を返します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
int Worksheet_get_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	int iVal;
	va_list ap;
	va_start(ap, ws);
	iVal = Worksheet_get_a(ws, ap);
	va_end(ap);
	return iVal;
}
/*--------------------------------------------------------------------------*/
int Worksheet_get_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	return Worksheet_get_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
int Worksheet_get_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	//指定されたノード(有れば)を取得する。
	// - ヌルポインタに対して呼出された場合も、同じ処理で安全である。
	ws = Worksheet_ref_v(ws/*ヌル可*/, aKey);
	//指定されたノードが存在しない場合は、値が未設定と同義と見なして、(0)を返す。
	if(!ws) { return 0; }	//ここまで
	//指定されたノードの値を返す。
	return ws->iVal;
}
/****************************************************************************
 *	合計
 ****************************************************************************/
//集計表の、指定されたノード以下のツリーの値を合計する。
// - 指定されたノードが存在しない場合は、(0)を返します。
//   上記の(0)と、明示的に設定された値の合計が(0)である場合とを、区別する方法は有りません。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、このノード以下のツリーの値を合計します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
// - 指定されたノード自身の値も、合計に含みます。
//   ノードが値とキーを両方持っている場合は、どちらも合計に含みます。
//　　　　　 １ 　　　　
//　　　　　／＼　　　　例えは、左図のツリーの最上位のノードを指定した場合、
//　　　　２　　◇　　　合計値は(1+2+3+4+5=15)となります。
//　　　／　＼　　＼　　
//　　３　　　４　　５　
int Worksheet_sum_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	int iSum;
	va_list ap;
	va_start(ap, ws);
	iSum = Worksheet_sum_a(ws, ap);
	va_end(ap);
	return iSum;
}
/*--------------------------------------------------------------------------*/
int Worksheet_sum_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	return Worksheet_sum_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
int Worksheet_sum_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	int iKey, iSum;
	ST_Worksheet_Iterator it;
	//指定されたノード(有れば)を取得する。
	// - ヌルポインタに対して呼出された場合も、同じ処理で安全である。
	ws = Worksheet_ref_v(ws/*ヌル可*/, aKey);
	//指定されたノードの値を取得する。
	// - 指定されたノードが無かった場合も、同じ処理で安全である。
	iSum = Worksheet_get_l(ws/*ヌル可*/, -1);
	//子階層のキーに対して再帰し、値を加算する。
	// - 指定されたノードが無かった場合も、同じ処理で安全である。
	for(iKey = Worksheet_first_l(ws/*ヌル可*/, &it, -1);
	    iKey != -1;
	    iKey = Worksheet_next(&it)) { iSum += Worksheet_sum_l(ws, iKey, -1); }
	return iSum;
}
/****************************************************************************
 *	設定
 ****************************************************************************/
//集計表のセルの値を設定する。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、この階層の値を設定します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
// - 値には、任意の整数を指定出来ます。
void Worksheet_set_l(ST_Worksheet* ws, int iVal, ... /*,(-1)*/) {
	va_list ap;
	va_start(ap, iVal);
	Worksheet_set_a(ws, iVal, ap);
	va_end(ap);
}
/*--------------------------------------------------------------------------*/
void Worksheet_set_a(ST_Worksheet* ws, int iVal, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	Worksheet_set_v(ws, iVal, aKey);
}
/*--------------------------------------------------------------------------*/
void Worksheet_set_v(ST_Worksheet* ws, int iVal, const int* aKey/*={key,key,...,key,-1}*/) {
	int iKey;
	ST_Worksheet* pChild;
	//ヌルポインタに対して呼出された場合は、エラー停止する。
	if(!ws) { DIE(); }
	//次のキーを取得する。
	iKey = *aKey++;
	//キーが終端ならば、この階層の値を設定する。
	if(iKey == -1) { ws->iVal = iVal; return; }	//ここまで
	//キーに対応する子階層(有れば)を取得する。
	pChild = Worksheet_ref_l(ws, iKey, -1);
	//キーに対応する子階層が無ければ…
	if(!pChild) {
		//集計表の単一階層を作成する。
		pChild = Worksheet_new();
		//キーに対応する子階層として、追加する。
		ght_insert(ws->tKey, pChild, sizeof(int), &iKey);
	}
	//キーに対応する子階層に対して、再帰する。
	Worksheet_set_v(pChild, iVal, aKey);
}
/****************************************************************************
 *	削除
 ****************************************************************************/
//集計表の指定されたノード,及び,それ以下の階層を開放する。
// - 可変引数は、(1)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、エラー停止します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
void Worksheet_unset_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	va_list ap;
	va_start(ap, ws);
	Worksheet_unset_a(ws, ap);
	va_end(ap);
}
/*--------------------------------------------------------------------------*/
void Worksheet_unset_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	Worksheet_unset_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
void Worksheet_unset_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	ST_Worksheet* pChild;
	//ヌルポインタに対して呼出された場合は、何もしない。
	if(!ws) { return; }	//ここまで
	//少なくとも(1)個以上のキーが指定されていなければならない。
	if(aKey[0] == -1) { DIE(); }
	//aKey[0]が最後のキーならば…
	if(aKey[1] == -1) {
		//aKey[0]に対応する子階層(有れば)を取り外す。
		pChild = ght_remove(ws->tKey, sizeof(int), &aKey[0]);
		//取り外した子階層(有れば)を開放する。
		// - キーに対応する子階層が無かった場合も、同じ処理で安全である。
		Worksheet_free(pChild/*ヌル可*/);
		return;	//ここまで
	}
	//aKey[0]に対応する子階層(有れば)を取得する。
	pChild = Worksheet_ref_l(ws, aKey[0], -1);
	//aKey[0]に対応する子階層(有れば)に対して、再帰する。
	// - aKey[0]に対応する子階層が無かった場合も、同じ処理で安全である。
	Worksheet_unset_v(pChild/*ヌル可*/, &aKey[1]);
}
/****************************************************************************
 *	計数
 ****************************************************************************/
//集計表のセルの値を(1)増加する。
// - 集計表のセルの値が未設定だった場合は、(1)増加後の値は(1)になります。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、この階層の値を(1)増加します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
void Worksheet_incr_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	va_list ap;
	va_start(ap, ws);
	Worksheet_incr_a(ws, ap);
	va_end(ap);
}
/*--------------------------------------------------------------------------*/
void Worksheet_incr_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	Worksheet_incr_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
void Worksheet_incr_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	//現在の値を取得する。
	int iVal = Worksheet_get_v(ws, aKey);
	//(1)増加後の値を設定する。
	Worksheet_set_v(ws, iVal + 1, aKey);
}
/****************************************************************************
 *	走査開始
 ****************************************************************************/
//集計表の子階層の最初のキーを取得します。
// - 子階層が無ければ、(-1)を返します。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、この階層の子階層の最初のキーを取得します。
// - キーには、(-1)以外の任意の整数を指定出来ます。
int Worksheet_first_l(ST_Worksheet* ws, ST_Worksheet_Iterator* it, ... /*,(-1)*/) {
	int iKey;
	va_list ap;
	va_start(ap, it);
	iKey = Worksheet_first_a(ws, it, ap);
	va_end(ap);
	return iKey;
}
/*--------------------------------------------------------------------------*/
int Worksheet_first_a(ST_Worksheet* ws, ST_Worksheet_Iterator* it, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	return Worksheet_first_v(ws, it, aKey);
}
/*--------------------------------------------------------------------------*/
int Worksheet_first_v(ST_Worksheet* ws, ST_Worksheet_Iterator* it, const int* aKey/*={key,key,...,key,-1}*/) {
	int iKey, *pKey;
	ST_Worksheet* pChild;
	//ヌルポインタに対して呼出された場合は、子階層が無いのと同義と見なして、(-1)を返す。
	if(!ws) { return -1; }	//ここまで
	//次のキーを取得する。
	iKey = *aKey++;
	//キーが終端ならば、この階層の子階層を走査開始する。
	if(iKey == -1) {
		//イテレータを初期化すると同時に、子階層の最初のキーを取得する。
		it->p_ht = ws->tKey;
		if(!ght_first(it->p_ht, &it->it, (const void**)&pKey)) { return -1; }	//子階層の最初のキーが無ければ、(-1)を返す。
		//子階層の最初のキーを返す。
		return *pKey;	//ここまで
	}
	//キーに対応する子階層(有れば)を取得する。
	pChild = Worksheet_ref_l(ws, iKey, -1);
	//キーに対応する子階層に対して、再帰する。
	return Worksheet_first_v(pChild, it, aKey);
}
/****************************************************************************
 *	走査継続
 ****************************************************************************/
//集計表の子階層の次のキーを取得します。
// - 次のキーが無ければ、(-1)を返します。
int Worksheet_next(ST_Worksheet_Iterator* it) {
	int* pKey;
	//子階層の次のキーを取得する。
	if(!ght_next(it->p_ht, &it->it, (const void**)&pKey)) { return -1; }	//子階層の次のキーが無ければ、(-1)を返す。
	//子階層の次のキーを返す。
	return *pKey;
}
/****************************************************************************
 *	ソート
 ****************************************************************************/
//集計表の全階層をソートする。
void Worksheet_sort(ST_Worksheet* ws) {
	int iKey;
	ST_Worksheet_Iterator it;
	//この階層をソートする。
	// - ヌルポインタに対して呼出された場合も、同じ処理で安全である。
	Worksheet_sort_l(ws/*ヌル可*/, -1);
	//子階層を全てソートする。
	// - ヌルポインタに対して呼出された場合も、同じ処理で安全である。
	for(iKey = Worksheet_first_l(ws/*ヌル可*/, &it, -1);
	    iKey != -1;
	    iKey = Worksheet_next(&it)) {
		ST_Worksheet* pChild = Worksheet_ref_l(ws, iKey, -1);
		Worksheet_sort(pChild);
	}
}
/*--------------------------------------------------------------------------*/
//集計表の単一階層をソートする。
// - 可変引数は、(0)個以上のキーの並びと、終端の(-1)です。
//   キーの並びが(0)個だった場合は、この階層の子階層をソートします。
// - キーには、(-1)以外の任意の整数を指定出来ます。
void Worksheet_sort_l(ST_Worksheet* ws, ... /*,(-1)*/) {
	va_list ap;
	va_start(ap, ws);
	Worksheet_sort_a(ws, ap);
	va_end(ap);
}
/*--------------------------------------------------------------------------*/
void Worksheet_sort_a(ST_Worksheet* ws, va_list ap) {
	int aKey[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aKey[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aKey)) { DIE(); }	//ここで停止した場合は、aKey[]不足か,又は,呼出し側が終端を忘れている。たぶん後者だろう。
	}
	Worksheet_sort_v(ws, aKey);
}
/*--------------------------------------------------------------------------*/
static int Worksheet_sort_Compare(LIST_ENTRY* _x, LIST_ENTRY* _y) {
	//当関数の処理は、ght_hash_table.h/cモジュールの動作に依存しています。
	//外部からght_hash_table_t.le_iteratorの順番を並び替えても、動作上問題有りません。
	ght_hash_entry_t* x = CONTAINING_RECORD(_x, ght_hash_entry_t, le_iterator);
	ght_hash_entry_t* y = CONTAINING_RECORD(_y, ght_hash_entry_t, le_iterator);
	if((x->i_key_size != sizeof(int)) || (y->i_key_size != sizeof(int))) { DIE(); }
	if(*(int*)x->key_data < *(int*)y->key_data) { return -1; }
	if(*(int*)x->key_data > *(int*)y->key_data) { return  1; }
	DIE();	//同一階層に同じ値のキーが存在する事は無いはず。ここで停止したらバグです。
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void Worksheet_sort_v(ST_Worksheet* ws, const int* aKey/*={key,key,...,key,-1}*/) {
	ws = Worksheet_ref_v(ws/*ヌル可*/, aKey);
	if(!ws) { return; }	//ここまで
	//ワークシートの内部の、ハッシュテーブルの内部の、ダブルリンクリストをソートする。
	SortList(&ws->tKey->le_iterator, Worksheet_sort_Compare);
}
/****************************************************************************
 *	ダンプ
 ****************************************************************************/
static void Worksheet_dump_indent(int indent) {
	while(indent--) { putchar('\t'); }
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void Worksheet_dump_iter(ST_Worksheet* ws, int indent) {
	int iKey;
	ST_Worksheet_Iterator it;
	//子階層を走査する。
	// - ヌルポインタに対して呼出された場合も、同じ処理で安全である。
	for(iKey = Worksheet_first_l(ws/*ヌル可*/, &it, -1);
	    iKey != -1;
	    iKey = Worksheet_next(&it)) {
		ST_Worksheet* pChild = Worksheet_ref_l(ws, iKey, -1);
		//子階層の値が設定されていたら、値を出力する。
		if(pChild->iVal) {
			Worksheet_dump_indent(indent);
			printf("%d\t=\t%d\n", iKey, pChild->iVal);
		}
		//子階層のキーが空でなければ、キーを出力する。
		if(ght_size(pChild->tKey)) {
			Worksheet_dump_indent(indent);
			printf("%d\n", iKey);
			Worksheet_dump_iter(pChild, indent + 1);
			Worksheet_dump_indent(indent);
			printf("end\n");
		}
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//集計表の全階層を、レジストリトクリプト形式でダンプします。
// - レジストリスクリプトの制限は考慮しません。
//   具体的には、レジストリスクリプトのキーと値の範囲は(0)〜(65535)であるのに対し、
//   当モジュールのキーの範囲は(-1)を除く任意の整数,値の範囲は(-1)も含む任意の整数です。
//   レジストリスクリプトの制限から外れるこれらの値も、そのまま出力します。
//   その場合、レジストリスクリプトをコンパイルした時点でエラーとなります。
// - ルート階層に直接設定した値は出力しません。
//   レジストリスクリプトの構造上、'ルート階層の値'は表現出来ないからです。
void Worksheet_dump(ST_Worksheet* ws) {
	Worksheet_sort(ws);	//キーの昇順にダンプする事にした。必須ではない。
	Worksheet_dump_iter(ws, 0);
}
/****************************************************************************
 *	使用例
 ****************************************************************************/
//※TODO:
