I'm reading a data structure and algorithm book in C. I have implemented a generic single linked list in the C programming language, and I want to know your opinion on my implementation:
linked_list.h
#ifndef LINKED_LIST_H_INCLUDED
#define LINKED_LIST_H_INCLUDED
#define list_size(list) (list->size)
#define list_head(list) (list->head)
#define list_tail(list) (list->tail)
#define list_is_head(list, element) (element == list_head(list))
#define list_is_tail(list, element) (element == list_tail(list))
#define list_append(list, data) list_ins_next(list, list->tail, data)
#define list_preprend(list, data) list_ins_next(list, NULL, data)
#define list_data(element) (element->data)
#define list_next(element) (element->nextElmt)
typedef struct ListElmt_{
void *data;
struct ListElmt_ *nextElmt;
} ListElmt;
typedef struct List_{
ListElmt *head;
ListElmt *tail;
size_t size;
void (*destroy)(void *data);
int (*cmp)(const void *fdata,const void *sdata);
}List;
List *list_init(void (*destroy)(void *data),
int (*cmp)(const void *fdata, const void *sdata));
void list_destroy(List *list);
int list_ins_off(List *list, size_t off, void *data);
int list_ins_next(List *list, ListElmt *element, void *data);
int list_drem_next(List *list, ListElmt *element);
int list_rem_next(List *list, ListElmt *element, void ** data);
ListElmt * list_find(List *list, void *data, ListElmt *sElmt);
#endif
linked_list.c
#include <stdlib.h>
#include "linked_list.h"
List * list_init(void (*destroy)(void *data),
int (*cmp)(const void *fdata, const void *data))
{
List *rlist;
if((rlist = malloc(sizeof *rlist)) != NULL) {
rlist->head = NULL;
rlist->tail = NULL;
rlist->size = 0;
rlist->destroy = destroy;
rlist->cmp = cmp;
}
return rlist;
}
void list_destroy(List *list) {
ListElmt * el;
void *data;
while( (el=list_head(list)) != NULL) {
list_rem_next(list, NULL, &data);
list->destroy(data);
}
free(list);
}
int list_ins_next(List *list, ListElmt *elmt, void *data) {
ListElmt *addElmt = malloc(sizeof *addElmt);
if(addElmt == NULL)
return -1;
addElmt->data = data;
if(elmt == NULL) {
addElmt->nextElmt = list->head;
elmt = list->head = addElmt; // using elmt for checking list tail
}
else {
addElmt->nextElmt = elmt->nextElmt;
elmt->nextElmt = addElmt;
}
// updating list->tail if needed
if(elmt == list->tail)
list->tail = addElmt;
list->size++;
return 0;
}
int list_ins_off(List *list, size_t off, void *data) {
if(off < 0 || off >= list->size)
return list_append(list, data);
size_t i;
ListElmt *elmt = NULL;
for(i = 0; i < off; ++i)
elmt = elmt->nextElmt;
list_ins_next(list, elmt, data);
return 0;
}
int list_drem_next(List *list, ListElmt *element) {
void *data;
int ret = list_rem_next(list, element, &data);
if(ret != 0)
return ret;
list->destroy(data);
return 0;
}
int list_rem_next(List *list, ListElmt *element, void **data) {
ListElmt *remElmt;
// the list still not contain any element
if(list->size == 0 || element->nextElmt == NULL)
return -1;
*data = element->nextElmt->data;
remElmt = element->nextElmt;
element->nextElmt = element->nextElmt->nextElmt;
if(remElmt == list->tail)
list->tail = element;
free(remElmt);
list->size--;
return 0;
}
ListElmt * find(List *list, void *data, ListElmt *sElmt) {
if(list->size == 0 || list->cmp == NULL)
return NULL;
sElmt = sElmt ? sElmt : list_head(list);
while(sElmt && list->cmp(sElmt->data, data))
sElmt = sElmt->nextElmt;
return sElmt;
}