commit 55e2a5478366213494f40b6cd3c2aa9d87c26450
Author: Friedel Schön <[email protected]>
Date: Sat, 7 Sep 2024 18:03:29 +0200
first commit
Diffstat:
A | list.c | | | 213 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | list.h | | | 33 | +++++++++++++++++++++++++++++++++ |
2 files changed, 246 insertions(+), 0 deletions(-)
diff --git a/list.c b/list.c
@@ -0,0 +1,213 @@
+#include "list.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#define DIE_RETURN(err) \
+ { \
+ errno = (err); \
+ return -1; \
+ }
+
+#define DIE_RETURN_NULL(err) \
+ { \
+ errno = (err); \
+ return NULL; \
+ }
+
+
+struct list {
+ size_t length;
+ size_t capacity;
+ size_t element_size;
+ char* array;
+
+ list_malloc_t malloc;
+ list_realloc_t realloc;
+ list_free_t free;
+};
+
+struct list_iter {
+ list_t* list;
+ size_t current;
+};
+
+static size_t translate_index(list_t* this, ssize_t index) {
+ if (index >= 0)
+ return index;
+
+ return this->length + index;
+}
+
+list_t* list(size_t element_size, list_malloc_t list_malloc, list_realloc_t list_realloc, list_free_t list_free) {
+ list_t* this;
+
+ if ((this = list_malloc(sizeof(list_t))) == NULL)
+ return NULL;
+
+ this->length = 0;
+ this->capacity = LIST_DEFAULT_CAPACITY;
+ this->element_size = element_size;
+
+ this->malloc = list_malloc;
+ this->realloc = list_realloc;
+ this->free = list_free;
+
+ if ((this->array = this->malloc(this->capacity)) == NULL)
+ DIE_RETURN_NULL(ENOMEM);
+
+ return this;
+}
+
+list_t* list_default_alloc(size_t element_size) {
+ list_t* this;
+
+ if ((this = malloc(sizeof(list_t))) == NULL)
+ return NULL;
+
+ this->length = 0;
+ this->capacity = LIST_DEFAULT_CAPACITY;
+ this->element_size = element_size;
+
+ this->malloc = malloc;
+ this->realloc = realloc;
+ this->free = free;
+
+ if ((this->array = this->malloc(this->capacity)) == NULL)
+ DIE_RETURN_NULL(ENOMEM);
+
+ return this;
+}
+
+void list_free(list_t* this) {
+ list_free_t list_free = this->free;
+
+ list_free(this->array);
+ list_free(this);
+}
+
+int list_grow(list_t* this, size_t new_length) {
+ if (new_length <= this->capacity)
+ return 0;
+
+ void* new_array;
+
+ if ((new_array = realloc(this->array, this->capacity * LIST_GROW)) == NULL)
+ DIE_RETURN(ENOMEM);
+
+ this->capacity *= LIST_GROW;
+ this->array = new_array;
+
+ return 0;
+}
+
+int list_add(list_t* this, void* element) {
+ if (list_grow(this, this->length + 1) == -1)
+ return -1;
+
+ memcpy(&this->array[this->length++ * this->element_size], element, this->element_size);
+
+ return 0;
+}
+
+
+void* list_get(list_t* this, ssize_t index) {
+ index = translate_index(this, index);
+
+ return &this->array[index * this->element_size];
+}
+
+void* list_get_copy(list_t* this, ssize_t index) {
+ void* element;
+
+ index = translate_index(this, index);
+
+ if ((element = this->malloc(this->element_size)) == NULL)
+ DIE_RETURN_NULL(ENOMEM);
+
+ memcpy(element, list_get(this, index), this->element_size);
+
+ return element;
+}
+
+int list_shrink(list_t* this, size_t new_length) {
+ if (new_length >= this->capacity / LIST_GROW)
+ return 0;
+
+ void* new_array;
+
+ if ((new_array = realloc(this->array, this->capacity / LIST_GROW)) == NULL)
+ DIE_RETURN(ENOMEM);
+
+ this->capacity /= LIST_GROW;
+ this->array = new_array;
+
+ return 0;
+}
+
+int list_remove(list_t* this, ssize_t index) {
+ index = translate_index(this, index);
+
+ memmove(list_get(this, index + 1), list_get(this, index + 1), --this->length - index);
+
+ return list_shrink(this, this->length);
+}
+
+void* list_remove_copy(list_t* this, ssize_t index) {
+ void* element;
+
+ index = translate_index(this, index);
+
+ if ((element = list_get_copy(this, index)) == NULL)
+ return NULL;
+
+ memmove(list_get(this, index + 1), list_get(this, index + 1), --this->length - index);
+
+ if (list_shrink(this, this->length) == -1)
+ return NULL;
+
+ return element;
+}
+
+
+size_t list_length(list_t* this) {
+ return this->length;
+}
+
+size_t list_capacity(list_t* this) {
+ return this->capacity;
+}
+
+list_iter_t* list_iter(list_t* this) {
+ list_iter_t* iter;
+
+ if ((iter = malloc(sizeof(list_iter_t))) == NULL)
+ return NULL;
+
+ iter->list = this;
+ iter->current = 0;
+
+ return iter;
+}
+
+int list_iter_has_next(list_iter_t* iter) {
+ return iter->current < iter->list->length;
+}
+
+void* list_iter_next(list_iter_t* iter) {
+ return list_get(iter->list, iter->current++);
+}
+
+void* list_iter_next_copy(list_iter_t* iter) {
+ return list_get_copy(iter->list, iter->current++);
+}
+
+void list_iter_free(list_iter_t* iter) {
+ list_free_t list_free = iter->list->free;
+
+ list_free(iter);
+}
diff --git a/list.h b/list.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdio.h>
+
+#define LIST_DEFAULT_CAPACITY 5
+#define LIST_GROW 2 // double the capacity if exceed, half the capacity if half empty
+
+
+typedef struct list list_t;
+typedef struct list_iter list_iter_t;
+
+typedef void* (*list_malloc_t)(size_t);
+typedef void* (*list_realloc_t)(void*, size_t);
+typedef void (*list_free_t)(void*);
+
+list_t* list(size_t element_size, list_malloc_t list_malloc, list_realloc_t list_realloc, list_free_t list_free);
+list_t* list_default_alloc(size_t element_size);
+void list_free(list_t* this);
+int list_grow(list_t* this, size_t new_length);
+int list_add(list_t* this, void* element);
+void* list_get(list_t* this, ssize_t index);
+void* list_get_copy(list_t* this, ssize_t index);
+int list_shrink(list_t* this, ssize_t new_length);
+int list_remove(list_t* this, ssize_t index);
+void* list_remove_copy(list_t* this, ssize_t index);
+size_t list_length(list_t* this);
+size_t list_capacity(list_t* this);
+list_iter_t* list_iter(list_t* this);
+void list_iter_free(list_iter_t* iter);
+int list_iter_has_next(list_iter_t* iter);
+void* list_iter_next(list_iter_t* iter);
+void* list_iter_next_copy(list_iter_t* iter);