From c5155078fc085ed47de07dc11fe8334abe315939 Mon Sep 17 00:00:00 2001 From: David Thorpe Date: Tue, 24 Oct 2023 18:09:19 +0200 Subject: [PATCH] Added list (#10) --- CMakeLists.txt | 1 + Doxyfile | 2 +- include/fuse/list.h | 18 +++++++++++-- include/fuse/map.h | 9 +++++++ src/fuse/CMakeLists.txt | 1 + src/fuse/list.c | 44 ++++++++++++++++++++++++++++++ src/fuse/map.c | 2 +- tests/list/CMakeLists.txt | 12 +++++++++ tests/list/main.c | 57 +++++++++++++++++++++++++++++++++++++++ tests/map/main.c | 53 ++++++++++++++++++++++++++++++++++++ 10 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 src/fuse/list.c create mode 100644 tests/list/CMakeLists.txt create mode 100644 tests/list/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ec8c194..78b6b1b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ endif() # Tests - fuse add_subdirectory(tests/fuseapp) +add_subdirectory(tests/list) add_subdirectory(tests/map) add_subdirectory(tests/panic) add_subdirectory(tests/pool) diff --git a/Doxyfile b/Doxyfile index 028986d..a99ec15 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2370,7 +2370,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = NO_DOC # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/include/fuse/list.h b/include/fuse/list.h index 03262a7..7cdbcdd 100644 --- a/include/fuse/list.h +++ b/include/fuse/list.h @@ -12,24 +12,38 @@ */ typedef struct fuse_list_instance fuse_list_t; +/** @brief Create a new empty linked list + * @param fuse The fuse application + * @param file The file from which the linked list is allocated + * @param line The line in the file from which the linked list is allocated + * @returns A new empty linked list, or NULL if memory could not be allocated + */ +fuse_list_t *fuse_list_new_ex(fuse_t *fuse, const char *file, int line); + /** @brief Create a new empty linked list * @param fuse The fuse application * @returns A new empty linked list, or NULL if memory could not be allocated */ fuse_list_t *fuse_list_new(fuse_t *fuse); +#ifndef NO_DOC +#define fuse_list_new(self) \ + (fuse_list_new_ex((self), __FILE__, __LINE__)) +#endif /* NO_DOC */ + /** @brief Deallocate a fuse linked list * + * @param fuse The fuse application * @param self The linked list to deallocate */ -void fuse_list_destroy(fuse_list_t *self); +void fuse_list_destroy(fuse_t *fuse, fuse_list_t *self); /** @brief Return the number of nodes in the list * * @param self The linked list * @returns The number of nodes in the list */ -void fuse_list_count(fuse_list_t *self); +size_t fuse_list_count(fuse_list_t *self); /** @brief Return the next node in the list * diff --git a/include/fuse/map.h b/include/fuse/map.h index 30a27b9..195e6ab 100644 --- a/include/fuse/map.h +++ b/include/fuse/map.h @@ -64,6 +64,15 @@ void fuse_map_destroy(fuse_t *fuse, fuse_map_t *self); */ size_t fuse_map_stats(fuse_map_t *self, size_t *size); + +/** @brief Return the number of elements in the map + * + * @param self The map + * @return The number of elements in the map + */ +#define fuse_map_count(self) \ + (fuse_map_stats((self), NULL)) + /** @brief Get a value from the map * * @param self The map diff --git a/src/fuse/CMakeLists.txt b/src/fuse/CMakeLists.txt index 1db0c50..ecde86c 100644 --- a/src/fuse/CMakeLists.txt +++ b/src/fuse/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(${NAME} STATIC debug.c epoll.c fuse.c + list.c map.c panic.c pool.c diff --git a/src/fuse/list.c b/src/fuse/list.c new file mode 100644 index 0000000..59c9590 --- /dev/null +++ b/src/fuse/list.c @@ -0,0 +1,44 @@ +#include +#include + +// Private includes +#include "list.h" + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +fuse_list_t *fuse_list_new_ex(fuse_t *fuse, const char *file, int line) +{ + assert(fuse); + + // Create the list + struct fuse_list_instance *self = fuse_alloc_ex(fuse, sizeof(struct fuse_list_instance), file, line); + if (self == NULL) + { + return NULL; + } + + // Set the instance properties + self->count = 0; + self->first = NULL; + self->last = NULL; + + // Return success + return self; +} + +void fuse_list_destroy(fuse_t *fuse, fuse_list_t *self) +{ + assert(fuse); + assert(self); + + // Free the instance + fuse_free(fuse, self); +} + +inline size_t fuse_list_count(fuse_list_t *self) +{ + assert(self); + return self->count; +} + diff --git a/src/fuse/map.c b/src/fuse/map.c index dc16a78..3c68c6f 100644 --- a/src/fuse/map.c +++ b/src/fuse/map.c @@ -40,7 +40,7 @@ void fuse_map_destroy(fuse_t *fuse, fuse_map_t *self) fuse_free(fuse, self); } -size_t fuse_map_stats(fuse_map_t *self, size_t *size) +inline size_t fuse_map_stats(fuse_map_t *self, size_t *size) { assert(self); if (size) diff --git a/tests/list/CMakeLists.txt b/tests/list/CMakeLists.txt new file mode 100644 index 0000000..ccc30de --- /dev/null +++ b/tests/list/CMakeLists.txt @@ -0,0 +1,12 @@ +set(NAME "list") +add_executable(${NAME} + main.c +) + +target_include_directories(${NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../../include +) + +target_link_libraries(${NAME} + fuse +) diff --git a/tests/list/main.c b/tests/list/main.c new file mode 100644 index 0000000..1afe402 --- /dev/null +++ b/tests/list/main.c @@ -0,0 +1,57 @@ + +#include + +int TEST_001() +{ + fuse_debugf(NULL, "Creating a fuse application\n"); + fuse_t *fuse = fuse_new(FUSE_FLAG_DEBUG); + assert(fuse); + + // Create a list + fuse_debugf(NULL, "Creating an empty list\n"); + fuse_list_t *list = fuse_list_new(fuse); + assert(list); + assert(fuse_list_count(list) == 0); + + // Destroy the list + fuse_list_destroy(fuse, list); + + // Return + return fuse_destroy(fuse); +} + +int TEST_002() +{ + fuse_debugf(NULL, "Creating a fuse application\n"); + fuse_t *fuse = fuse_new(FUSE_FLAG_DEBUG); + assert(fuse); + + // Create a list + fuse_debugf(NULL, "Creating a list\n"); + fuse_list_t *list = fuse_list_new(fuse); + assert(list); + assert(fuse_list_count(list) == 0); + + // Push 10 items into the list + fuse_debugf(NULL, "Pushing 10 items into the list\n"); + for (int i = 0; i < 10; i++) + { + fuse_list_push(list, (void *)(i + 1)); + assert(fuse_list_count(list) == i + 1); + } + + // Destroy the list + fuse_list_destroy(fuse, list); + + // Return + return fuse_destroy(fuse); +} + +int main() +{ + assert(TEST_001() == 0); + assert(TEST_002() == 0); + + // Return success + return 0; +} diff --git a/tests/map/main.c b/tests/map/main.c index c745e0c..aeb5a35 100644 --- a/tests/map/main.c +++ b/tests/map/main.c @@ -72,12 +72,65 @@ int TEST_002(uint64_t sz) return fuse_destroy(fuse); } + +int TEST_003(uint64_t sz) +{ + fuse_debugf(NULL, "Creating a fuse application\n"); + fuse_t *fuse = fuse_new(FUSE_FLAG_DEBUG); + assert(fuse); + + // Generate some random numbers between 0 and sz + uint64_t *numbers = fuse_alloc(fuse, sizeof(uint64_t) * sz); + assert(numbers); + for(uint64_t i = 0; i < sz; i++) { + uint64_t r = 0; + while(r==0) { + r = rand_u64(); + } + numbers[i] = r; + fuse_debugf(NULL, " number[%lu]=%lu\n",i,numbers[i]); + } + + // Create a map + fuse_debugf(NULL, "Creating a map of %lu items\n",sz); + fuse_map_t *map = fuse_map_new(fuse, sz); + assert(map); + + // Set the numbers + for(uint64_t i = 0; i < sz; i++) { + fuse_debugf(NULL, " Setting number[%lu]=%lu\n",i,numbers[i]); + assert(fuse_map_set(map, (void *)i+1, (void *)numbers[i])); + } + + // Assert count + assert(fuse_map_stats(map, NULL) == sz); + + // Get the numbers + for(uint64_t i = 0; i < sz; i++) { + fuse_debugf(NULL, " Getting number[%lu]\n",i); + assert(fuse_map_get(map, (void *)i+1) == (void *)numbers[i]); + } + + // Randomly delete numbers until the map is empty + while(fuse_map_stats(map, NULL) > 0) { + uint64_t i = rand_u64() % sz; + fuse_debugf(NULL, " Deleting number[%lu]\n",i); + fuse_debugf(NULL, " Count is %lu\n",fuse_map_stats(map, NULL)); + assert(fuse_map_set(map, (void *)i+1, 0)); + } + + // Return + return fuse_destroy(fuse); +} + + int main() { assert(TEST_001() == 0); assert(TEST_002(10) == 0); assert(TEST_002(100) == 0); assert(TEST_002(1000) == 0); + assert(TEST_003(1000) == 0); // Return success return 0;