From 0288983aa782ab13ba13d6fe3d4023457ef942e8 Mon Sep 17 00:00:00 2001 From: Tilo K Date: Sat, 23 Aug 2025 18:23:11 +0200 Subject: [PATCH] feat: add list --- CMakeLists.txt | 13 ++- README.md | 1 - include/tstd/list.h | 133 ++++++++++++++++++++++++++++ list.c | 62 +++++++++++++ test/test_list.c | 63 +++++++++++++ test/{test_main.c => test_string.c} | 0 6 files changed, 267 insertions(+), 5 deletions(-) create mode 100644 include/tstd/list.h create mode 100644 list.c create mode 100644 test/test_list.c rename test/{test_main.c => test_string.c} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 220594d..fb8235c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,15 @@ set(CMAKE_C_STANDARD 23) add_library(tstd STATIC library.c include/tstd/string.h - string.c) + string.c + list.c + include/tstd/list.h) -add_executable(test_tstd test/test_main.c) -target_link_libraries(test_tstd tstd) +add_executable(test_tstd_string test/test_string.c) +add_executable(test_tstd_list test/test_list.c) +target_link_libraries(test_tstd_string tstd) +target_link_libraries(test_tstd_list tstd) target_include_directories(tstd PUBLIC @@ -18,4 +22,5 @@ target_include_directories(tstd ) enable_testing() -add_test(NAME tstd_tests COMMAND test_tstd) \ No newline at end of file +add_test(NAME tstd_tests_string COMMAND test_tstd_string) +add_test(NAME tstd_tests_list COMMAND test_tstd_list) diff --git a/README.md b/README.md index 267ccde..6ebcb82 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,5 @@ FetchContent_Declare( FetchContent_MakeAvailable(tstd) add_executable(myapp src/main.c) - target_link_libraries(myapp PRIVATE tstd) ``` \ No newline at end of file diff --git a/include/tstd/list.h b/include/tstd/list.h new file mode 100644 index 0000000..ce67a50 --- /dev/null +++ b/include/tstd/list.h @@ -0,0 +1,133 @@ +// +// Created by tilok on 23.08.2025. +// + +#ifndef TSTD_LIST_H +#define TSTD_LIST_H +#include +#include + +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; + +/** + * @brief Creates a new list with a default initial capacity. + * + * 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. + * + * @return A pointer to the newly created list, or NULL if memory allocation fails. + */ +list* list_create(); + + +/** + * @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. + */ +list* list_create_with_capacity(size_t capacity); + +/** + * @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); + +#endif //TSTD_LIST_H diff --git a/list.c b/list.c new file mode 100644 index 0000000..2fcce82 --- /dev/null +++ b/list.c @@ -0,0 +1,62 @@ +// +// Created by tilok on 23.08.2025. +// + +#include "tstd/list.h" + +#include + + +list* list_create() { + return list_create_with_capacity(10); +} + +list* list_create_with_capacity(size_t capacity) { + void** data = malloc(capacity * sizeof(void *)); + list* new_list = malloc(sizeof(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 *)); + 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; +} \ No newline at end of file diff --git a/test/test_list.c b/test/test_list.c new file mode 100644 index 0000000..43c3ba7 --- /dev/null +++ b/test/test_list.c @@ -0,0 +1,63 @@ +// +// Created by tilok on 23.08.2025. +// +#include +#include + +#include "tstd/list.h" + +int test_list_create() { + list* list = list_create(); + + assert(list->capacity == 10); + + list_free(list); + return 0; +} + +int test_list_add_element() { + list* list = list_create(); + list_add_element(list, "Hello"); + + assert(list->length == 1); + assert(strcmp(list->data[0], "Hello") == 0); + + list_free(list); + return 0; +} + +int test_add_multiple_elements() { + list* list = list_create(); + for (int i = 0; i < 1000; i++) { + list_add_element(list, "Hello"); + } + assert(list->length == 1000); + assert(list->capacity > 1000); + + list_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); + + assert(list->length == 2); + assert(strcmp(list->data[1], "Test") == 0); + + return 0; +} + +int main() { + int result = 0; + + result += test_list_create(); + result += test_list_add_element(); + result += test_add_multiple_elements(); + result += test_delete_element(); + + return result; +} \ No newline at end of file diff --git a/test/test_main.c b/test/test_string.c similarity index 100% rename from test/test_main.c rename to test/test_string.c