Files
ni-linkedlist/nilinkedlist.h

187 lines
4.5 KiB
C
Raw Permalink Normal View History

2026-01-15 20:15:16 +02:00
#include "../ni-arena/niarena.h"
typedef struct _NILinkedListNode {
void *content;
struct _NILinkedListNode *next;
} NILinkedListNode;
typedef struct _NILinkedList {
size_t count;
struct _NILinkedListNode *first;
} NILinkedList;
typedef void(NILinkedListVisitorFunctor)(const void *);
typedef void *(NILinkedListMapFunctor)(const void *, NIArena **arena);
typedef void(NILinkedListReduceFunctor)(void **accumulator, const void *current);
NILinkedList *nilinkedlist_new(NIArena **arena);
bool nilinkedlist_empty(NILinkedList **self);
void nilinkedlist_push(NILinkedList **self, NIArena **arena, void *content);
const void *nilinkedlist_pop(NILinkedList **self);
void nilinkedlist_emplace(NILinkedList **self, NIArena **arena, void *content, const size_t idx);
const void *nilinkedlist_peek(NILinkedList *self, const size_t idx);
void nilinkedlist_enqueue(NILinkedList **self, NIArena **arena, void *content);
const void *nilinkedlist_dequeue(NILinkedList **self);
void nilinkedlist_traverse(NILinkedList *list, NILinkedListVisitorFunctor f);
void nilinkedlist_map(NILinkedList *list, NIArena **arena, NILinkedListMapFunctor f, NILinkedList **out);
void nilinkedlist_reduce(NILinkedList *list, NILinkedListReduceFunctor f, void **out);
#ifdef NILINKEDLIST_IMPLEMENTATION
NILinkedList *
nilinkedlist_new(NIArena **arena)
{
NILinkedList *list =
(NILinkedList *)niarena_alloc(arena, sizeof(NILinkedList));
list->count = 0;
list->first = NULL;
return list;
}
NILinkedListNode *
nilinkedlist_node_new(NIArena **arena)
{
NILinkedListNode *node =
(NILinkedListNode *)niarena_alloc(arena, sizeof(NILinkedListNode));
node->next = NULL;
node->content = NULL;
return node;
}
bool
nilinkedlist_empty(NILinkedList **self)
{
return (*self)->count == 0;
}
void
nilinkedlist_push(NILinkedList **self, NIArena **arena, void *content)
{
NILinkedList *list = *self;
NILinkedListNode *node = nilinkedlist_node_new(arena);
node->content = content;
if(list->first == NULL) {
list->first = node;
} else {
NILinkedListNode *current_node = list->first;
while(current_node->next != NULL) {
current_node = current_node->next;
}
current_node->next = node;
}
list->count++;
}
const void *
nilinkedlist_pop(NILinkedList **self)
{
NILinkedList *list = *self;
if(list->count == 0) {
return NULL;
}
NILinkedListNode *current_node = list->first;
NILinkedListNode *previous_node = NULL;
while(current_node->next != NULL) {
previous_node = current_node;
current_node = current_node->next;
}
if(previous_node == NULL) {
list->first = NULL;
} else {
previous_node->next = NULL;
}
list->count--;
return current_node->content;
}
void
nilinkedlist_emplace(NILinkedList **self, NIArena **arena, void *content, const size_t idx)
{
NILinkedList *list = *self;
NILinkedListNode *node = nilinkedlist_node_new(arena);
node->content = content;
if(list->count == 0 || idx == 0) {
node->next = list->first;
list->first = node;
} else {
NILinkedListNode *aux = list->first;
const size_t real_idx = list->count < idx ? list->count : idx;
for(size_t i = 1; i < real_idx; i++) {
aux = aux->next;
}
node->next = aux->next;
aux->next = node;
}
list->count++;
}
const void *
nilinkedlist_peek(NILinkedList *self, const size_t idx)
{
if(self->count == 0 || idx >= self->count) {
return NULL;
}
size_t real_idx = idx + 1; // 1 indexed
NILinkedListNode *node = self->first;
for(size_t i = 1; i < real_idx; i++) {
node = node->next;
}
return node->content;
}
void
nilinkedlist_enqueue(NILinkedList **self, NIArena **arena, void *content)
{
nilinkedlist_emplace(self, arena, content, 0);
}
const void *
nilinkedlist_dequeue(NILinkedList **self)
{
return nilinkedlist_pop(self);
}
void
nilinkedlist_traverse(NILinkedList *list, NILinkedListVisitorFunctor f)
{
if(list->count == 0) {
return;
}
NILinkedListNode *node = list->first;
while(node->next != NULL) {
f(node->content);
node = node->next;
}
}
void
nilinkedlist_map(NILinkedList *list, NIArena **arena, NILinkedListMapFunctor f, NILinkedList **out)
{
if(list->count > 0) {
void *content;
NILinkedListNode *node = list->first;
while(node->next != NULL) {
content = f(node->content, arena);
nilinkedlist_push(out, arena, content);
node = node->next;
}
content = f(node->content, arena);
nilinkedlist_push(out, arena, content);
}
}
void
nilinkedlist_reduce(NILinkedList *list, NILinkedListReduceFunctor f, void **out)
{
if(list->count > 0) {
NILinkedListNode *node = list->first;
while(node->next != NULL) {
f(out, node->content);
node = node->next;
}
f(out, node->content);
}
}
#endif