別のアプローチを提案したいと思います。さまざまな種類のデータに対して複数のリストタイプを作成し、キャストまたはマクロ体操を使用して同じアルゴリズムをそれらに適用する代わりに、タイプ固有の動作をさまざまな関数に委任する単一のジェネリックリストタイプを作成し、それらの関数を関数付きのリストタイプにアタッチしますポインタ。例えば:
struct generic_node {
void *data;
struct generic_node *next;
};
struct generic_list {
struct generic_node head;
int (*cmp)(void * const a, void * const b);
void *(*cpy)(void * const);
void (*del)(void *);
};
cmpは、* a <* bの場合は-1、* a == * bの場合は0、* a> * bの場合は1を返す関数を指します。ここで、aとbはvoid*から適切なポインター型に変換されています。 。例えば、
int compareInts(void * const a, void * const b)
{
int * const la = a;
int * const lb = b;
if (*a < *b) return -1;
if (*a == *b) return 0;
if (*a > *b) return 1;
}
int compareMyStruct(void * const a, void * const b)
{
struct myStruct * const la = a;
struct myStruct * const lb = b;
if (la->foo < lb->foo && strcmp(la->bar,lb->bar) < 0 && ...) return -1;
if (la->foo == lb->foo && strcmp(la->bar,lb->bar) == 0 && ...) return 0;
if (la->foo > lb->foo && strcmp(la->bar, lb->bar) > 0 && ...) return 1;
}
cpyは、入力パラメーターのディープコピーを作成する関数を指します。
void *copyInt(void * const data)
{
int *theCopy = malloc(sizeof *theCopy);
*theCopy = *((int *) data);
return theCopy;
}
void *copyMyStruct(void * const data)
{
struct myStruct * const lData = data;
struct myStruct *newStruct = malloc(sizeof *newStruct);
newStruct->foo = lData->foo;
newStruct->bar = malloc(strlen(lData->bar) + 1);
strcpy(newStruct->bar, lData->bar);
...
return newStruct;
}
そして最後に、delはデータ項目の割り当てを解除する関数を指します。
void delInt(void * data)
{
free(data);
}
void delMyStruct(void * data)
{
struct myStruct * lData = data;
free(lData->bar);
...
free(lData);
}
これで、リストアルゴリズムは、タイプ固有の動作について心配する必要がなくなりました。関数ポインタを介して適切な関数を呼び出すだけです。
void listAdd(struct generic_list * const theList, void * const data)
{
struct generic_node *cur = &(theList->head);
struct generic_node *entry = malloc(sizeof *entry);
entry->data = theList->cpy(data);
while (cur->next != NULL && theList->cmp(cur->next->data, entry->data) < 0)
cur = cur->next;
entry->next = cur->next;
cur->next = entry;
}
/** */
void listClear(struct generic_list * const theList)
{
struct generic_node *cur = theList->head.next;
while (cur != NULL)
{
struct generic_node *entry = cur;
cur = cur->next;
theList->del(entry->data);
free(entry);
}
}