187 lines
4.5 KiB
C
187 lines
4.5 KiB
C
#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
|