I decided to learn generic programming in C (and take a break from templates in C++) by implementing my first simple data structure in C: the singly linked list.What I'm looking to gain out of reviews is:Clarity/qualityAlgorithmic correctnessCode style for CStructure and designAny bugs or issues you can findI'm planning to use this as a basis for implementing a hash-map in C that uses chaining. slist.h#ifndef C_SLIST_H#define C_SLIST_H#include <stdbool.h>#include <stddef.h>struct slist_node;struct slist;typedef bool (*func_cmp)(const void *a, const void *b);struct slist *slist_init(func_cmp cmp);void slist_insert(struct slist *, void *);void slist_free(struct slist *);bool slist_empty(const struct slist *);void *slist_value(const struct slist_node *);struct slist_node *slist_find(const struct slist *, void *);void clear(struct slist *);size_t slist_size(const struct slist *);void slist_remove(struct slist *, void *);#endifslist.c#include <stdlib.h>#include slist.hstruct slist_node {    struct slist_node *next;    void *data;};struct slist {    struct slist_node *head, *tail;    func_cmp compare;};static struct slist_node *create_node(void *value){    struct slist_node *node = calloc(1, sizeof(*node));    if (!node) { return NULL; }    node->data = value;    return node;}static bool default_compare(const void *a, const void *b){    return a == b;}struct slist *slist_init(func_cmp func){    struct slist *l = calloc(1, sizeof(struct slist));    l->compare = func ? func : default_compare;    return l;}void slist_insert(struct slist *l, void *value){    if (!l) { return; }    if (slist_empty(l)) {        l->head = create_node(value);        if (!l->head) { return; }        l->tail = l->head;        return;    }    l->tail->next = create_node(value);    if (!l->tail->next) { return; }    if (l->tail->next) {         l->tail = l->tail->next;     }}void clear(struct slist *l){    if (!l) { return; }    struct slist_node *copy = l->head;    while (copy) {        struct slist_node *after = copy->next;        free(copy);        copy = after;    }    l->head = NULL;    l->tail = NULL;}void slist_free(struct slist *l){    clear(l);}bool slist_empty(const struct slist *l){    return l ? l->head == NULL : true;}void *slist_value(const struct slist_node *n){    return n ? n->data : NULL;}size_t slist_size(const struct slist *l){    if (!l || slist_empty(l)) { return 0; }    const struct slist_node *copy = l->head;    size_t size = 0;    while (copy) {        ++size;        copy = copy->next;    }    return size;}static struct slist_node *slist_find_ahead(const struct slist *l, void *value){        struct slist_node *copy = l->head;    while (copy) {        if ((l->compare)(copy->next->data, value)) {            return copy;        } else {            copy = copy->next;        }    }    return NULL;}struct slist_node *slist_find(const struct slist *l, void *value){    if (!l || slist_empty(l)) { return NULL; }    if ((l->compare)(l->head->data, value)) { return l->head; }    const struct slist_node *found = slist_find_ahead(l, value);    return found ? found->next : NULL;}void slist_remove(struct slist *l, void *value){    if (!l || slist_empty(l)) { return; }    if (l->head->data == value) {        struct slist_node *copy = l->head;        if (l->tail == l->head) {            l->tail = copy->next;        }        l->head = copy->next;        free(copy);        return;    }    struct slist_node *ahead = slist_find_ahead(l, value);    if (!ahead) { return; }    if (ahead->next == l->tail) {        l->tail = ahead;    }    struct slist_node *to_delete = ahead->next;    ahead->next = ahead->next->next;    free(to_delete);}
Generic Singly Linked List in C
c;linked list