mirror of
https://github.com/Tilo-K/tstd.git
synced 2026-01-09 14:31:01 +00:00
feat: make list dynamic
This commit is contained in:
2
CHANGELOG.txt
Normal file
2
CHANGELOG.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
1.1.0:
|
||||||
|
- Made list dynamic
|
||||||
@@ -9,7 +9,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||||||
set(TSTD_SOURCES
|
set(TSTD_SOURCES
|
||||||
library.c
|
library.c
|
||||||
string.c
|
string.c
|
||||||
list.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Shared library: libtstd.so
|
# Shared library: libtstd.so
|
||||||
@@ -21,7 +20,7 @@ target_include_directories(tstd
|
|||||||
)
|
)
|
||||||
set_target_properties(tstd PROPERTIES
|
set_target_properties(tstd PROPERTIES
|
||||||
OUTPUT_NAME tstd
|
OUTPUT_NAME tstd
|
||||||
VERSION 1.0.0
|
VERSION 1.1.0
|
||||||
SOVERSION 1
|
SOVERSION 1
|
||||||
POSITION_INDEPENDENT_CODE ON
|
POSITION_INDEPENDENT_CODE ON
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @file list.h
|
* @file list.h
|
||||||
* @brief List utilities
|
* @brief List utilities
|
||||||
* @date 2025-08-23
|
* @date 2025-08-23
|
||||||
* @author Tilo
|
* @author Tilo
|
||||||
@@ -7,146 +7,101 @@
|
|||||||
|
|
||||||
#ifndef TSTD_LIST_H
|
#ifndef TSTD_LIST_H
|
||||||
#define TSTD_LIST_H
|
#define TSTD_LIST_H
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdlib.h>
|
#include <string.h>
|
||||||
|
#include "../../helper.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef char* charptr;
|
||||||
/**
|
|
||||||
* @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.
|
* @brief Defines a type-safe list implementation for the specified type.
|
||||||
*
|
*
|
||||||
* This function initializes a new empty list using a pre-defined default
|
* Generated functions:
|
||||||
* capacity. The created list can later hold elements and be resized
|
* - list_T_create_with_capacity(size_t): Create list with specified capacity
|
||||||
* dynamically as needed.
|
* - 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.
|
* @brief Defines a list implementation for pointer types with element freeing.
|
||||||
*
|
|
||||||
* 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);
|
#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); \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
#endif // TSTD_LIST_H
|
||||||
* @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
|
|
||||||
|
|||||||
77
list.c
77
list.c
@@ -1,77 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by tilok on 23.08.2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "tstd/list.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -2,48 +2,49 @@
|
|||||||
// Created by tilok on 23.08.2025.
|
// Created by tilok on 23.08.2025.
|
||||||
//
|
//
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "tstd/list.h"
|
#include "tstd/list.h"
|
||||||
|
|
||||||
int test_list_create() {
|
DEFINE_LIST(int)
|
||||||
list* list = list_create();
|
DEFINE_LIST_PTR(charptr)
|
||||||
|
|
||||||
|
int test_list_int_create() {
|
||||||
|
list_int* list = list_int_create();
|
||||||
assert(list->capacity == 10);
|
assert(list->capacity == 10);
|
||||||
|
|
||||||
list_free(list);
|
list_int_free(list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_list_add_element() {
|
int test_list_add_element() {
|
||||||
list* list = list_create();
|
list_charptr* list = list_charptr_create();
|
||||||
list_add_element(list, "Hello");
|
list_charptr_add(list, "Hello");
|
||||||
|
|
||||||
assert(list->length == 1);
|
assert(list->length == 1);
|
||||||
assert(strcmp(list->data[0], "Hello") == 0);
|
assert(strcmp(list->data[0], "Hello") == 0);
|
||||||
|
|
||||||
list_free(list);
|
list_charptr_free(list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_add_multiple_elements() {
|
int test_add_multiple_elements() {
|
||||||
list* list = list_create();
|
list_charptr* list = list_charptr_create();
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
list_add_element(list, "Hello");
|
list_charptr_add(list, "Hello");
|
||||||
}
|
}
|
||||||
assert(list->length == 1000);
|
assert(list->length == 1000);
|
||||||
assert(list->capacity > 1000);
|
assert(list->capacity > 1000);
|
||||||
|
|
||||||
list_free(list);
|
list_charptr_free(list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_delete_element() {
|
int test_delete_element() {
|
||||||
list* list = list_create();
|
list_charptr* list = list_charptr_create();
|
||||||
list_add_element(list, "Hello");
|
list_charptr_add(list, "Hello");
|
||||||
list_add_element(list, "World");
|
list_charptr_add(list, "World");
|
||||||
list_add_element(list, "Test");
|
list_charptr_add(list, "Test");
|
||||||
list_delete_element(list, 1);
|
list_charptr_delete(list, 1);
|
||||||
|
|
||||||
assert(list->length == 2);
|
assert(list->length == 2);
|
||||||
assert(strcmp(list->data[1], "Test") == 0);
|
assert(strcmp(list->data[1], "Test") == 0);
|
||||||
@@ -52,10 +53,10 @@ int test_delete_element() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int test_list_contains() {
|
int test_list_contains() {
|
||||||
list* list = list_create();
|
list_charptr* list = list_charptr_create();
|
||||||
list_add_element(list, "Hello");
|
list_charptr_add(list, "Hello");
|
||||||
list_add_element(list, "World");
|
list_charptr_add(list, "World");
|
||||||
list_add_element(list, "Test");
|
list_charptr_add(list, "Test");
|
||||||
|
|
||||||
assert(list_contains(list, "Hello") == 1);
|
assert(list_contains(list, "Hello") == 1);
|
||||||
assert(list_contains(list, "World") == 1);
|
assert(list_contains(list, "World") == 1);
|
||||||
@@ -68,7 +69,7 @@ int test_list_contains() {
|
|||||||
int main() {
|
int main() {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
result += test_list_create();
|
result += test_list_int_create();
|
||||||
result += test_list_add_element();
|
result += test_list_add_element();
|
||||||
result += test_add_multiple_elements();
|
result += test_add_multiple_elements();
|
||||||
result += test_delete_element();
|
result += test_delete_element();
|
||||||
|
|||||||
Reference in New Issue
Block a user