From 3db20558688746f17e688dc98026c398c205d4b9 Mon Sep 17 00:00:00 2001 From: Tilo-K Date: Mon, 5 Jan 2026 22:11:06 +0100 Subject: [PATCH] feat: make list dynamic --- CHANGELOG.txt | 2 + CMakeLists.txt | 3 +- include/tstd/list.h | 219 ++++++++++++++++++-------------------------- list.c | 77 ---------------- test/test_list.c | 41 +++++---- 5 files changed, 111 insertions(+), 231 deletions(-) create mode 100644 CHANGELOG.txt delete mode 100644 list.c diff --git a/CHANGELOG.txt b/CHANGELOG.txt new file mode 100644 index 0000000..f0a7f48 --- /dev/null +++ b/CHANGELOG.txt @@ -0,0 +1,2 @@ +1.1.0: + - Made list dynamic diff --git a/CMakeLists.txt b/CMakeLists.txt index b2abdff..1db5a9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(TSTD_SOURCES library.c string.c - list.c ) # Shared library: libtstd.so @@ -21,7 +20,7 @@ target_include_directories(tstd ) set_target_properties(tstd PROPERTIES OUTPUT_NAME tstd - VERSION 1.0.0 + VERSION 1.1.0 SOVERSION 1 POSITION_INDEPENDENT_CODE ON ) diff --git a/include/tstd/list.h b/include/tstd/list.h index 6a22393..25ace10 100644 --- a/include/tstd/list.h +++ b/include/tstd/list.h @@ -1,5 +1,5 @@ /** -* @file list.h + * @file list.h * @brief List utilities * @date 2025-08-23 * @author Tilo @@ -7,146 +7,101 @@ #ifndef TSTD_LIST_H #define TSTD_LIST_H +#include #include #include -#include +#include +#include "../../helper.h" -typedef struct { - /** - * @brief Pointer to the list's underlying data storage. - * - * This member variable represents the dynamic array used to store the actual - * elements of the list. Each element is a pointer, allowing the list to - * store arbitrary data types. The size of this array is managed by the - * capacity member, and its content can grow or shrink dynamically when - * elements are added or removed. - * - * The memory for this array is allocated dynamically and should be freed - * appropriately to avoid memory leaks when the list is no longer needed. - */ - void** data; - /** - * @brief Represents the number of elements currently stored in the list. - * - * This member tracks the current count of valid elements within the list. It - * increases when elements are added and decreases when elements are removed. - * It is always less than or equal to the list's capacity. - */ - size_t length; - /** - * @brief Represents the current capacity of the list. - * - * This member defines the maximum number of elements the list can hold - * before needing to reallocate memory for additional space. It dynamically - * increases as needed when elements are added beyond the current capacity. - */ - size_t capacity; -} list; +typedef char* charptr; /** - * @brief Creates a new list with a default initial capacity. + * @brief Defines a type-safe list implementation for the specified type. * - * This function initializes a new empty list using a pre-defined default - * capacity. The created list can later hold elements and be resized - * dynamically as needed. + * Generated functions: + * - list_T_create_with_capacity(size_t): Create list with specified capacity + * - list_T_create(): Create list with default capacity + * - list_T_resize(list_T*): Resize the list + * - list_T_add(list_T*, T): Add element to the list + * - list_T_free(list_T*): Free the list + * - list_T_delete(list_T*, size_t): Delete element at index + * - list_T_contains(list_T*, T): Check if list contains element * - * @return A pointer to the newly created list, or NULL if memory allocation fails. + * @param T The type of elements the list will hold */ -list* list_create(); - +#define DEFINE_LIST(T) \ + typedef struct { \ + T *data; \ + size_t length; \ + size_t capacity; \ + } list_##T; \ + \ + static inline list_##T *list_##T##_create_with_capacity(size_t capacity) { \ + T *data = malloc(capacity * sizeof(T)); \ + OOM(data); \ + list_##T *new_list = malloc(sizeof(list_##T)); \ + OOM(new_list); \ + new_list->data = data; \ + new_list->length = 0; \ + new_list->capacity = capacity; \ + return new_list; \ + } \ + \ + static inline list_##T *list_##T##_create(void) { \ + return list_##T##_create_with_capacity(10); \ + } \ + \ + static inline void list_##T##_resize(list_##T *list) { \ + size_t new_capacity = (list->capacity + 1) * 1.5; \ + T *new_data = malloc(new_capacity * sizeof(T)); \ + OOM(new_data); \ + memcpy(new_data, list->data, list->length * sizeof(T)); \ + free(list->data); \ + list->data = new_data; \ + list->capacity = new_capacity; \ + } \ + \ + static inline void list_##T##_add(list_##T *list, T element) { \ + if (list->length == list->capacity) { \ + list_##T##_resize(list); \ + } \ + list->data[list->length++] = element; \ + } \ + \ + static inline void list_##T##_free(list_##T *list) { \ + free(list->data); \ + free(list); \ + } \ + \ + static inline T list_##T##_delete(list_##T *list, size_t index) { \ + T element = list->data[index]; \ + list->length--; \ + for (size_t i = index; i < list->length; i++) { \ + list->data[i] = list->data[i + 1]; \ + } \ + return element; \ + } \ + \ + static inline uint8_t list_##T##_contains(list_##T *list, T element) { \ + for (size_t i = 0; i < list->length; i++) { \ + if (list->data[i] == element) { \ + return 1; \ + } \ + } \ + return 0; \ + } /** - * @brief Creates a new list with a specified initial capacity. - * - * This function initializes an empty list with the given capacity. The capacity - * determines the maximum number of elements the list can initially hold before - * requiring a resize operation. The list supports dynamic resizing as more - * elements are added beyond its current capacity. - * - * @param capacity The initial number of elements the list can hold. - * @return A pointer to the newly created list, or NULL if memory allocation fails. + * @brief Defines a list implementation for pointer types with element freeing. */ -list* list_create_with_capacity(size_t capacity); +#define DEFINE_LIST_PTR(T) \ + DEFINE_LIST(T) \ + static inline void list_##T##_free_elements(list_##T *list) { \ + for (size_t i = 0; i < list->length; i++) { \ + free(list->data[i]); \ + } \ + free(list->data); \ + free(list); \ + } -/** - * @brief Resizes the capacity of the list to accommodate more elements. - * - * This function dynamically increases the capacity of a list when needed. - * A new memory block is allocated, existing elements are copied to the - * new block, and the old memory is freed. The new capacity is determined - * based on a growth factor to optimize memory usage. - * - * @param list A pointer to the list structure to be resized. - */ -void list_resize(list* list); - -/** - * @brief Adds a new element to the end of the list. - * - * This function appends the provided element to the list. If the list has - * reached its current capacity, it will automatically resize to ensure - * there is enough space for the new element. - * - * @param list A pointer to the list structure where the element will be added. - * @param element A pointer to the element being inserted into the list. - */ -void list_add_element(list* list, void* element); - -/** - * @brief Frees the memory allocated for the list and its elements. - * - * This function releases all resources associated with the provided list. - * It deallocates the memory reserved for the list's data and the list - * structure itself. After calling this function, the list pointer will - * no longer be valid. - * - * @param list A pointer to the list to be freed. Must be a valid pointer - * to a list created with `list_create`, or NULL. - */ -void list_free(list* list); - -/** - * @brief Frees all elements and associated memory in the given list. - * - * This function deallocates the memory of each element contained in the list, - * as well as the list's internal data structure and the list itself. After - * calling this function, the given list pointer becomes invalid and should not - * be used further. - * - * @param list A pointer to the list to be freed. Passing a NULL pointer is undefined behavior. - */ -void list_free_elements(list* list); - -/** - * @brief Deletes an element from the list at a specified index. - * - * This function removes the element at the given index from the list, reducing - * the list's length by one. The subsequent elements in the list are shifted - * to fill the gap left by the removed element. The memory for the removed - * element is not freed by this function; it is the caller's responsibility to - * manage the memory of the deleted element. - * - * @param list A pointer to the list from which the element will be deleted. - * @param index The index of the element to remove. It must be a valid index - * within the list's current length. - * @return A pointer to the removed element. The caller is responsible for managing - * the returned pointer, including deallocating memory if necessary. - */ -void* list_delete_element(list* list, int index); - - -/** -* @brief Checks if the list contains a specific element. -* -* This function checks if the list contains the specified element. It iterates -* through the list's elements and compares each one with the given element -* using the `==` operator. If a match is found, the function returns 1, otherwise -* it returns 0. -* -* @param list A pointer to the list to search. -* @param element A pointer to the element to search for. -* @return 1 if the list contains the element, 0 otherwise. -*/ -uint8_t list_contains(list* list, void* element); - -#endif //TSTD_LIST_H +#endif // TSTD_LIST_H diff --git a/list.c b/list.c deleted file mode 100644 index 83ecba8..0000000 --- a/list.c +++ /dev/null @@ -1,77 +0,0 @@ -// -// Created by tilok on 23.08.2025. -// - -#include "tstd/list.h" - -#include -#include - -#include "helper.h" - - -list* list_create() { - return list_create_with_capacity(10); -} - -list* list_create_with_capacity(size_t capacity) { - void** data = malloc(capacity * sizeof(void *)); - OOM(data); - list* new_list = malloc(sizeof(list)); - OOM(new_list); - - new_list->data = data; - new_list->length = 0; - new_list->capacity = capacity; - - return new_list; -} - -void list_resize(list* list) { - size_t new_capacity = (list->capacity + 1) * 1.5; - void** new_data = malloc(new_capacity * sizeof(void *)); - OOM(new_data); - memcpy(new_data, list->data, list->length * sizeof(void *)); - free(list->data); - list->data = new_data; - list->capacity = new_capacity; -} - -void list_add_element(list* list, void* element) { - if (list->length == list->capacity) { - list_resize(list); - } - - list->data[list->length++] = element; -} - -void list_free(list* list) { - free(list->data); - free(list); -} - -void list_free_elements(list* list) { - for (int i = 0; i < list->length; i++) { - free(list->data[i]); - } - free(list->data); - free(list); -} - -void* list_delete_element(list* list, int index) { - void* element = list->data[index]; - list->length--; - for (int i = index; i < list->length; i++) { - list->data[i] = list->data[i + 1]; - } - return element; -} - -uint8_t list_contains(list* list, void* element) { - for (int i = 0; i < list->length; i++) { - if (list->data[i] == element) { - return 1; - } - } - return 0; -} diff --git a/test/test_list.c b/test/test_list.c index 8443ad1..eabc860 100644 --- a/test/test_list.c +++ b/test/test_list.c @@ -2,48 +2,49 @@ // Created by tilok on 23.08.2025. // #include -#include #include "tstd/list.h" -int test_list_create() { - list* list = list_create(); +DEFINE_LIST(int) +DEFINE_LIST_PTR(charptr) +int test_list_int_create() { + list_int* list = list_int_create(); assert(list->capacity == 10); - list_free(list); + list_int_free(list); return 0; } int test_list_add_element() { - list* list = list_create(); - list_add_element(list, "Hello"); + list_charptr* list = list_charptr_create(); + list_charptr_add(list, "Hello"); assert(list->length == 1); assert(strcmp(list->data[0], "Hello") == 0); - list_free(list); + list_charptr_free(list); return 0; } int test_add_multiple_elements() { - list* list = list_create(); + list_charptr* list = list_charptr_create(); for (int i = 0; i < 1000; i++) { - list_add_element(list, "Hello"); + list_charptr_add(list, "Hello"); } assert(list->length == 1000); assert(list->capacity > 1000); - list_free(list); + list_charptr_free(list); return 0; } int test_delete_element() { - list* list = list_create(); - list_add_element(list, "Hello"); - list_add_element(list, "World"); - list_add_element(list, "Test"); - list_delete_element(list, 1); + list_charptr* list = list_charptr_create(); + list_charptr_add(list, "Hello"); + list_charptr_add(list, "World"); + list_charptr_add(list, "Test"); + list_charptr_delete(list, 1); assert(list->length == 2); assert(strcmp(list->data[1], "Test") == 0); @@ -52,10 +53,10 @@ int test_delete_element() { } int test_list_contains() { - list* list = list_create(); - list_add_element(list, "Hello"); - list_add_element(list, "World"); - list_add_element(list, "Test"); + list_charptr* list = list_charptr_create(); + list_charptr_add(list, "Hello"); + list_charptr_add(list, "World"); + list_charptr_add(list, "Test"); assert(list_contains(list, "Hello") == 1); assert(list_contains(list, "World") == 1); @@ -68,7 +69,7 @@ int test_list_contains() { int main() { int result = 0; - result += test_list_create(); + result += test_list_int_create(); result += test_list_add_element(); result += test_add_multiple_elements(); result += test_delete_element();