コンテナライブラリ(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__ */