157 lines
3.7 KiB
C

#ifndef LIST_H
# define LIST_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.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 (size_t 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;
}
//seems like i got a leak here, but may not be that bad since it is only called when closing
lst->size = 0;
lst->first = lst->last = NULL;
free(lst);
lst = 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