151 lines
3.5 KiB
C
151 lines
3.5 KiB
C
#ifndef LIST_H
|
|
# define LIST_H
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
|
|
typedef struct node_s {
|
|
void *data;
|
|
struct node_s *next;
|
|
} node_t;
|
|
|
|
typedef struct {
|
|
int size;
|
|
node_t *first;
|
|
node_t *last;
|
|
} list_t;
|
|
|
|
typedef struct {
|
|
node_t *current;
|
|
} list_iter_t;
|
|
|
|
|
|
list_t *ListInit(list_t *lst);
|
|
void ListInsert(list_t *lst, size_t idx, void *data);
|
|
void ListPushBack(list_t *lst, void *data);
|
|
list_iter_t ListGetIter(const list_t *lst);
|
|
void *ListAdvance(list_iter_t *it);
|
|
void *ListPeek(const list_iter_t *it);
|
|
void *ListPeekNext(const list_iter_t *it);
|
|
bool ListAtEnd(const list_iter_t *it);
|
|
void ListReset(list_iter_t *it, const list_t *lst);
|
|
void ListFree(list_t *lst, void (*free_func)(void*));
|
|
void *ListPeekK(const list_iter_t *it, size_t k);
|
|
void ListRestore(list_iter_t *it, const list_iter_t checkpoint);
|
|
bool ListMatch(list_iter_t *it, bool (*predicate)(void*, void*), void *target);
|
|
|
|
# ifdef LIST_IMPLEMENTATION
|
|
|
|
list_t *ListInit(list_t *lst) {
|
|
if (!lst) {
|
|
lst = (list_t *)malloc(sizeof(list_t));
|
|
}
|
|
lst->first = NULL;
|
|
lst->last = NULL;
|
|
lst->size = 0;
|
|
return (lst);
|
|
}
|
|
|
|
void ListInsert(list_t *lst, size_t idx, void *data) {
|
|
node_t *node = (node_t *)malloc(sizeof(node_t));
|
|
node->data = data;
|
|
node->next = 0;
|
|
if (lst->size == 0) {
|
|
lst->first = lst->last = node;
|
|
} else if (idx == 0) {
|
|
node->next = lst->first;
|
|
lst->first = node;
|
|
} else {
|
|
node_t *prev = lst->first;
|
|
for (int i = 0; i < idx - 1 && prev->next; i++) {
|
|
prev = prev->next;
|
|
}
|
|
node->next = prev->next;
|
|
prev->next = node;
|
|
if (node->next == NULL) {
|
|
lst->last = node;
|
|
}
|
|
}
|
|
|
|
lst->size++;
|
|
}
|
|
|
|
void ListPushBack(list_t *lst, void *data) {
|
|
node_t *node = (node_t *)malloc(sizeof(node_t));
|
|
node->data = data;
|
|
node->next = NULL;
|
|
|
|
if (!lst->first) {
|
|
lst->first = node;
|
|
} else {
|
|
lst->last->next = node;
|
|
}
|
|
lst->last = node;
|
|
lst->size++;
|
|
}
|
|
|
|
list_iter_t ListGetIter(const list_t *lst) {
|
|
return ((list_iter_t){.current = lst->first});
|
|
}
|
|
|
|
void *ListAdvance(list_iter_t *it) {
|
|
if (!it->current) return NULL;
|
|
void *data = it->current->data;
|
|
it->current = it->current->next;
|
|
return (data);
|
|
}
|
|
|
|
void *ListPeek(const list_iter_t *it) {
|
|
return (it->current ? it->current->data : NULL);
|
|
}
|
|
|
|
void *ListPeekNext(const list_iter_t *it) {
|
|
return (it->current ? (it->current->next ? it->current->next->data : NULL) : NULL);
|
|
}
|
|
|
|
bool ListAtEnd(const list_iter_t *it) {
|
|
return (it->current == NULL);
|
|
}
|
|
|
|
void ListReset(list_iter_t *it, const list_t *lst) {
|
|
it->current = lst->first;
|
|
}
|
|
|
|
void ListFree(list_t *lst, void (*free_func)(void*)) {
|
|
node_t *current = lst->first;
|
|
while (current) {
|
|
node_t *next = current->next;
|
|
if (free_func) free_func(current->data);
|
|
free(current);
|
|
current = next;
|
|
}
|
|
lst->size = 0;
|
|
lst->first = lst->last = NULL;
|
|
}
|
|
|
|
void *ListPeekK(const list_iter_t *it, size_t k) {
|
|
node_t *current = it->current;
|
|
for (size_t i = 0; i < k && current; i++) {
|
|
current = current->next;
|
|
}
|
|
return (current ? current->data : NULL);
|
|
}
|
|
|
|
void ListRestore(list_iter_t *it, const list_iter_t checkpoint) {
|
|
it->current = checkpoint.current;
|
|
}
|
|
|
|
bool ListMatch(list_iter_t *it, bool (*predicate)(void*, void*), void *target) {
|
|
if (it->current && predicate(it->current->data, target)) {
|
|
ListAdvance(it);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
# endif
|
|
|
|
#endif
|