コンテナライブラリ(List)

リストライブラリを更に汎用にした。
なんでも格納できるようにしたが、その分格納したオブジェクトを開放する関数、ノードが格納している
オブジェクトを画面にDumpする関数を登録したり、使い方は難しくなった。
後は、これを利用して、スタックとキューの実装をしたいな。
そのあとはテストユニットを作って、ドキュメントを作るか、、、、。
main.c

#include <stdio.h>
#include <stdlib.h>
#include "container.h"

/* ヒープに確保したintを開放する */
void dispose(void *p)
{
	free(p);
}

void dump(void *p)
{
	int *pData = p;
	
	if (pData) {
		printf("%d\n", *pData);
	}
}

int main(void)
{
	ContainerList *pList;
	ContainerIterator *pIte;
	int *p;
	
	pList = ContainerListCreate(dispose, dump);
	pIte = ContainerIteratorCreate(pList);
	
	/* リストに挿入 */
	p = malloc(sizeof(int)); *p = 0;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 1;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 2;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 3;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 4;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 5;
	ContainerIteratorInsertNext(pIte, p);

	/* ダンプ */
	ContainerDump(pList);

	/* 2つすすめる */
	ContainerIteratorNext(pIte);
	ContainerIteratorNext(pIte);
	
	/* リストに挿入 */
	p = malloc(sizeof(int)); *p = 10;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 11;
	ContainerIteratorInsertNext(pIte, p);
	p = malloc(sizeof(int)); *p = 12;
	ContainerIteratorInsertNext(pIte, p);
	
	/* ダンプ */
	ContainerDump(pList);

	/* 5つすすめる */
	ContainerIteratorNext(pIte);
	ContainerIteratorNext(pIte);
	ContainerIteratorNext(pIte);
	ContainerIteratorNext(pIte);
	ContainerIteratorNext(pIte);
	
	/* 3つリストから削除 */
	ContainerIteratorErase(pIte);
	ContainerIteratorErase(pIte);
	ContainerIteratorErase(pIte);
	
	/* ダンプ */
	ContainerDump(pList);

	/* イテレータ開放 */
	ContainerIteratorDispose(pIte);
	/* リスト開放 */
	ContainerListDispose(pList);
	
	return 0;
}

container.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "container.h"


/* コンテナライブラリ */

/* ============ 非公開構造体 ============ */


/* Node構造体 */
typedef struct M_Node {
	struct M_Node *pPrev;
	struct M_Node *pNext;
	void *pData;
} M_Node;

/* List構造体宣言 */
/* とりあえず格納するのはint */
struct ContainerList {
	M_Node dummyNode;	/* リストの先頭、最後尾を指すダミーノード */
	unsigned size;
	void (*fDispose)(void *p);	/* デストラクタ */
	void (*fToString)(void *p);	/* stdoutに格納objを出力 */
};


/* ============ 外部公開関数 ============ */

/* ---------- 共通関数 ---------- */

/* コンテナに格納されているノード数を返す */
unsigned ContainerSize(ContainerList *p)
{
	if (p == NULL) {
		return 0;
	}
	
	return p->size;
}

/* ダンプ */
void ContainerDump(ContainerList *pList)
{
	ContainerIterator *pIte;
	
	/* NULLチェック */
	if (pList == NULL) {
		return;
	}
	
	/* イテレータ生成 */
	pIte = ContainerIteratorCreate(pList);
	
	printf(" ======== Dump ======== \n");
	
	if (pIte) {
		while (ContainerIteratorHasNext(pIte)) {
			if (pList->fToString) {
				pList->fToString(ContainerIteratorNext(pIte));
			} else {
				break;
			}
		}
	}
	
	/* イテレータ開放 */
	ContainerIteratorDispose(pIte);
}

/* ---------- List ---------- */
/* Listコンストラクタ */
ContainerList *ContainerListCreate(
	void (*fDispose)(void *p),		/* デストラクタ */
	void (*fToString)(void *p)		/* stdoutに格納objを出力 */
)
{
	ContainerList *p = malloc(sizeof(ContainerList));
	
	if (p) {
		/* ダミーノードなのでNULLを設定しておく*/
		p->dummyNode.pData = NULL;
		
		/* ダミーノードを始点終点として循環させる。 */
		p->dummyNode.pPrev = &p->dummyNode;
		p->dummyNode.pNext = &p->dummyNode;
		
		/* サイズ初期化 */
		p->size = 0;
		
		/* デストラクタ、ToString保持 */
		p->fDispose = fDispose;
		p->fToString = fToString;
	}
	
	return p;
}

/* Listデストラクタ */
void ContainerListDispose(ContainerList *pList)
{
	M_Node *pTmp, *pDelete;
	
	/* 引数チェック */
	if (pList == NULL) {
		return;
	}
	
	/* リストの各ノードを開放 */
	pTmp = pList->dummyNode.pNext;
	while (pTmp != &pList->dummyNode) {
		/* 切り離すノードを保持 */
		pDelete = pTmp;
		
		/* ノードをすすめる */
		pTmp = pTmp->pNext;
		
		/* ノードを切り離す */
		pDelete->pNext = pDelete->pPrev = NULL;
		
		/* ノード開放 */
		free(pDelete);
	}
	
	/* リストを開放 */
	free(pList);
}

/* ---------- Iterator ---------- */

/* ContainerIterator構造体宣言 */
/* 実装詳細を隠蔽するため名前のみ公開 */
struct ContainerIterator {
	ContainerList *pList;		/* リストを保持 */
	M_Node *pNode;		/* 現時点のノードを保持 */
};

/* ContainerIteratorコンストラクタ */
ContainerIterator *ContainerIteratorCreate(ContainerList *pList)
{
	ContainerIterator *pIte = malloc(sizeof(ContainerIterator));
	
	/* 引数チェック */
	if (pList == NULL) {
		return NULL;
	}
	
	if (pIte) {
		pIte->pList = pList;
		pIte->pNode = &pList->dummyNode;
	}
	
	return pIte;
}

/* ContainerIteratorデストラクタ */
void ContainerIteratorDispose(ContainerIterator *pIte)
{
	free(pIte);
}

/* Next可能か? */
/* Next可能なら1, 不可なら0を返す */
int ContainerIteratorHasNext(ContainerIterator *pIte)
{
	if (pIte == NULL) {
		return 0;
	}
	
	if (pIte->pNode->pNext != &pIte->pList->dummyNode) {
		return 1;
	} else {
		return 0;
	}
}

/* Nextしてオブジェクトを返す */
void *ContainerIteratorNext(ContainerIterator *pIte)
{
	if (pIte == NULL) {
		assert("Err ContainerIteratorNext");
	}

	pIte->pNode = pIte->pNode->pNext;
	
	return pIte->pNode->pData;
}

/* pIteの次にdataを格納したノードを追加する。 */
void ContainerIteratorInsertNext(ContainerIterator *pIte, void *pData)
{
	M_Node *pNewNode;
	
	/* NULLチェック */
	if (pIte == NULL) {
		return;
	}
	
	pNewNode = malloc(sizeof(M_Node));
	
	if (pNewNode) {
		pNewNode->pData = pData;
		
		/* ノードをつなぐ */
		pNewNode->pPrev = pIte->pNode;
		pNewNode->pNext = pIte->pNode->pNext;
		
		pIte->pNode->pNext = pNewNode;
		pNewNode->pNext->pPrev = pNewNode;
		
		/* リストサイズインクリメント */
		pIte->pList->size++;
	}
}

/* Prev可能か? */
/* Prev可能なら1, 不可なら0を返す */
int ContainerIteratorHasPrev(ContainerIterator *pIte)
{
	if (pIte == NULL) {
		return 0;
	}
	
	if (pIte->pNode->pPrev != &pIte->pList->dummyNode) {
		return 1;
	} else {
		return 0;
	}
}


/* Prevしてオブジェクトを返す */
void *ContainerIteratorPrev(ContainerIterator *pIte)
{
	if (pIte == NULL) {
		assert("Err ContainerIteratorPrev");
	}
	
	pIte->pNode = pIte->pNode->pPrev;
	
	return pIte->pNode->pData;
}


/* pIteの前にdataを格納したノードを追加する。 */
void ContainerIteratorInsertPrev(ContainerIterator *pIte, void *pData)
{
	M_Node *pNewNode;
	
	/* NULLチェック */
	if (pIte == NULL) {
		return;
	}
	
	pNewNode = malloc(sizeof(M_Node));
	
	if (pNewNode) {
		pNewNode->pData = pData;
		
		/* ノードをつなぐ */
		pNewNode->pNext = pIte->pNode;
		pNewNode->pPrev = pIte->pNode->pPrev;
		
		pIte->pNode->pPrev = pNewNode;
		pNewNode->pPrev->pNext = pNewNode;
		
		/* リストサイズインクリメント */
		pIte->pList->size++;
	}
}

/* pIteが指しているノードを切り離し、格納していたオブジェクトを返す。 */
/* ノードは開放される。pIteがは元のノードのprevを指すようになる。 */
/* 切り離しに失敗したら0が返る */
void *ContainerIteratorErase(ContainerIterator *pIte)
{
	M_Node *pPrev, *pNext;
	void *pRtn;
	
	if (pIte == NULL) {
		return 0;
	}
	
	if (pIte->pNode == &pIte->pList->dummyNode) {
		/* ダミーノードは切り離せない */
		return 0;
	}
	
	pPrev = pIte->pNode->pPrev;
	pNext = pIte->pNode->pNext;
	
	/* 前と後ろをつなげる */
	pPrev->pNext = pNext;
	pNext->pPrev = pPrev;
	
	pRtn = pIte->pNode->pData;
	
	/* Node開放 */
	free(pIte->pNode);
	
	/* イテレータはひとつ前を指す */
	pIte->pNode = pPrev;
	
	/* リストサイズデクリメント */
	if (pIte->pList->size) {
		pIte->pList->size--;
	} else {
		assert("Err ContainerIteratorErase\n");
	}
	
	return pRtn;
}

container.h

#ifndef CONTAINER_H__
#define CONTAINER_H__

/* コンテナライブラリ */

/* List構造体宣言 */
/* 実装詳細を隠蔽するため名前のみ公開 */
typedef struct ContainerList ContainerList;


/* ==== リスト・スタック・キュー共通関数 ==== */
/* コンテナに格納されているノード数を返す */
/* p: リスト、スタック、キューを指すポインタ */
unsigned ContainerSize(ContainerList *p);

/* コンテナダンプ */
/* p: リスト、スタック、キューを指すポインタ */
void ContainerDump(ContainerList *p);

/* ==== リスト・スタック・キュー共通関数 ==== */

/* Listコンストラクタ */
/* Listコンストラクタ */
ContainerList *ContainerListCreate(
	void (*fDispose)(void *p);	/* デストラクタ */
	void (*fToString)(void *p);	/* stdoutに格納objを出力 */
);

/* Listデストラクタ */
/* pList: リスト */
void ContainerListDispose(ContainerList *pList);

/* ==== Iterator構造体宣言 ==== */
/* 実装詳細を隠蔽するため名前のみ公開 */
/* Iteratorはリストを走査しながら操作するためのIF */
typedef struct ContainerIterator ContainerIterator;

/* Iteratorコンストラクタ */
ContainerIterator *ContainerIteratorCreate(ContainerList *pList);

/* Iteratorデストラクタ */
void ContainerIteratorDispose(ContainerIterator *pIte);

/* Next可能か? */
/* Next可能なら1, 不可なら0を返す */
int ContainerIteratorHasNext(ContainerIterator *pIte);

/* Nextしてオブジェクトを返す */
void *ContainerIteratorNext(ContainerIterator *pIte);

/* pIteの次にdataを格納したノードを追加する。 */
void ContainerIteratorInsertNext(ContainerIterator *pIte, void *pData);

/* Prev可能か? */
/* Prev可能なら1, 不可なら0を返す */
int ContainerIteratorHasPrev(ContainerIterator *pIte);

/* Prevしてオブジェクトを返す */
void *ContainerIteratorPrev(ContainerIterator *pIte);

/* pIteの前にdataを格納したノードを追加する。 */
void ContainerIteratorInsertPrev(ContainerIterator *pIte, void *pData);

/* pIteが指しているノードを切り離し、格納していたオブジェクトを返す。 */
/* ノードは開放される。pIteがは元のノードのprevを指すようになる。 */
void *ContainerIteratorErase(ContainerIterator *pIte);

#endif	/* CONTAINER_H__ */