diff --git a/CMakeLists.txt b/CMakeLists.txt index 90680a5..3e0d46c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ endif() project(fuse CXX C ASM) message("Set TARGET to ${TARGET}") add_compile_definitions(TARGET=${TARGET}) +add_compile_definitions(DEBUG=1) # Libraries add_subdirectory(src/fuse) @@ -43,6 +44,7 @@ endif() # Tests add_subdirectory(tests/blink) add_subdirectory(tests/fuseapp) +add_subdirectory(tests/map) add_subdirectory(tests/panic) add_subdirectory(tests/pool) add_subdirectory(tests/temperature) diff --git a/include/fuse/debug.h b/include/fuse/debug.h index e0485d9..f2aeee2 100644 --- a/include/fuse/debug.h +++ b/include/fuse/debug.h @@ -31,8 +31,9 @@ void fuse_panic(const char *expr, const char *file, int line); #define assert(e) \ ((void)((e) ? 0 : fuse_panic(#e, __FILE__, __LINE__))) #else +#pragma message("no debugging") #define assert(e) \ ((void)((e) ? 0 : fuse_panic(#e, NULL, 0))) #endif /* DEBUG */ -#endif /* FUSE_DEBUG_H */ \ No newline at end of file +#endif /* FUSE_DEBUG_H */ diff --git a/include/fuse/fuse.h b/include/fuse/fuse.h index 5d15d57..68287f4 100644 --- a/include/fuse/fuse.h +++ b/include/fuse/fuse.h @@ -19,6 +19,7 @@ typedef struct fuse_instance fuse_t; #include #include #include +#include #include #include #include diff --git a/include/fuse/map.h b/include/fuse/map.h new file mode 100644 index 0000000..5b85696 --- /dev/null +++ b/include/fuse/map.h @@ -0,0 +1,73 @@ +/** @file map.h + * @brief Fuse map function prototypes + * + * This file contains the function prototypes for creating and destroying + * maps. A map can be used to store key-value pairs, where both the key and + * the value are void pointers. In a map, all keys are unique. + * + * The size argument provides the inital estimate on the number of key-value + * pairs that will be stored in the map. The map will automatically resize + * itself if the number of key-value pairs exceeds the initial estimate, but + * this will cause a performance penalty. + */ +#ifndef FUSE_MAP_H +#define FUSE_MAP_H +#include "fuse.h" + +/** @brief Map defintion + */ +typedef struct fuse_map_instance fuse_map_t; + +/** @brief Create a new empty map + * @param fuse The fuse application + * @param size The initial size of the map + * @returns A new empty map, or NULL if memory could not be allocated + */ +fuse_map_t *fuse_map_new_ex(fuse_t *fuse, size_t size, const char *file, int line); + +#ifdef DEBUG +#define fuse_map_new(self, size) \ + (fuse_map_new_ex((self), (size), __FILE__, __LINE__)) +#else +#define fuse_map_new(self, size) \ + (fuse_map_new_ex((self), (size), 0, 0)) +#endif + +/** @brief Deallocate a map + * + * @param fuse The fuse application + * @param self The map to deallocate + */ +void fuse_map_destroy(fuse_t *fuse, fuse_map_t *self); + +/** @brief Return statistics about the map + * + * Test for the number of elements in the map. If the size argument is not NULL, + * then the current maximum number of elements in the map is passed back. If this + * equals the count then the map is full. + * + * @param self The map + * @param size A pointer to the current maximum number of elements in the map. If the size + * argument is NULL, the parameter is not passed back. + * @return The number of elements in the map + */ +size_t fuse_map_stats(fuse_map_t *self, size_t *size); + +/** @brief Get a value from the map + * + * @param self The map + * @param key The key, cannot be a NULL value. + * @return The value. Returns NULL if the value does not exist + */ +void *fuse_map_get(fuse_map_t *self, void *key); + +/** @brief Set a key-value pair in the map + * + * @param self The map + * @param key The key to insert. The key cannot be a NULL value. + * @param value The value to insert. If the value is NULL, then the key is removed from the map. + * @return True on success, or false if the map is full + */ +bool fuse_map_set(fuse_map_t *self, void *key, void *value); + +#endif // FUSE_MAP_H diff --git a/src/fuse/CMakeLists.txt b/src/fuse/CMakeLists.txt index 0102e10..be2b3db 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 + map.c panic.c pool.c pool_std.c diff --git a/src/fuse/fuse.c b/src/fuse/fuse.c index ef2ff1f..5eca7bf 100644 --- a/src/fuse/fuse.c +++ b/src/fuse/fuse.c @@ -42,10 +42,11 @@ int fuse_destroy(fuse_t *fuse) int exit_code = fuse->exit_code; // Free the application + fuse_pool_t* pool = fuse->pool; fuse_pool_free(fuse->pool, fuse); // Free the pool - fuse_pool_destroy(fuse->pool); + fuse_pool_destroy(pool); // Return the exit code return exit_code; diff --git a/src/fuse/list.h b/src/fuse/list.h index c7ef880..819c27e 100644 --- a/src/fuse/list.h +++ b/src/fuse/list.h @@ -3,7 +3,6 @@ */ #ifndef FUSE_PRIVATE_LIST_H #define FUSE_PRIVATE_LIST_H - #include /* @brief Represents an instance of a fuse linked list diff --git a/src/fuse/map.c b/src/fuse/map.c new file mode 100644 index 0000000..1c8242b --- /dev/null +++ b/src/fuse/map.c @@ -0,0 +1,94 @@ +#include +#include + +// Private includes +#include "map.h" + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +fuse_map_t *fuse_map_new_ex(fuse_t *fuse, size_t size, const char *file, int line) +{ + assert(fuse); + assert(size > 0); + + // Create the map and the nodes in a single block of memory + size_t alloc_size = sizeof(struct fuse_map_instance) + sizeof(struct fuse_map_node) * size; + struct fuse_map_instance *instance = fuse_alloc_ex(fuse, alloc_size, file, line); + if (instance == NULL) + { + return NULL; + } + + // Set the instance properties + memset(instance, 0, alloc_size); + instance->size = size; + instance->nodes = (struct fuse_map_node *)(instance + 1); + + // Return success + return instance; +} + +void fuse_map_destroy(fuse_t *fuse, fuse_map_t *self) +{ + assert(fuse); + assert(self); + + // Free the instance + fuse_free(fuse, self); +} + +size_t fuse_map_stats(fuse_map_t *self, size_t *size) +{ + assert(self); + if (size) + { + *size = self->size; + } + return self->count; +} + +/** @brief This is the hash function for void* keys + */ +inline size_t fuse_map_hashfunc(void *key) +{ + if (key == 0) + { + return 0; + } + size_t x = (size_t)key; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = (x >> 16) ^ x; + assert(x); + return x; +} + +/** @brief Set a key-value pair in the map + * + * @param self The map + * @param key The key to insert. The key cannot be a NULL value. + * @param value The value to insert. If the value is NULL, then the key is removed from the map. + * @return True on success, or false if the map is full + */ +bool fuse_map_set(fuse_map_t *self, void *key, void *value) +{ + assert(self); + assert(key); + + // TODO +} + +/** @brief Get a value from the map + * + * @param self The map + * @param key The key, cannot be a NULL value. + * @return The value. Returns NULL if the value does not exist + */ +void *fuse_map_get(fuse_map_t *self, void *key) +{ + assert(self); + assert(key); + + // TODO +} diff --git a/src/fuse/map.h b/src/fuse/map.h new file mode 100644 index 0000000..5040417 --- /dev/null +++ b/src/fuse/map.h @@ -0,0 +1,25 @@ +/** @file map.h + * @brief Private function prototypes and structure definitions for maps + */ +#ifndef FUSE_PRIVATE_MAP_H +#define FUSE_PRIVATE_MAP_H +#include + +/* @brief Represents an instance of a map + */ +struct fuse_map_instance +{ + size_t size; ///< The maximum number of nodes in the instance + size_t count; ///< The number of nodes in the instance + struct fuse_map_node *nodes; ///< The nodes in the instance +}; + +/* @brief Represents a node in a map + */ +struct fuse_map_node +{ + void *key; ///< The node key + void *value; ///< The node value +}; + +#endif diff --git a/src/fuse/sleep.c b/src/fuse/sleep.c index 74b7a75..3deb7fc 100644 --- a/src/fuse/sleep.c +++ b/src/fuse/sleep.c @@ -3,7 +3,7 @@ // PUBLIC METHODS #ifdef TARGET -#if TARGET != pico +#if TARGET == darwin || TARGET == linux #include #include diff --git a/tests/map/CMakeLists.txt b/tests/map/CMakeLists.txt new file mode 100644 index 0000000..3b385f9 --- /dev/null +++ b/tests/map/CMakeLists.txt @@ -0,0 +1,21 @@ +set(NAME "map") +add_executable(${NAME} + main.c +) + +target_include_directories(${NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../../include +) + +target_link_libraries(${NAME} + fuse +) + +if(${TARGET} STREQUAL "pico") + target_link_libraries(${NAME} + picofuse + ) + pico_enable_stdio_usb(${NAME} 1) + pico_enable_stdio_uart(${NAME} 0) + pico_add_extra_outputs(${NAME}) +endif() diff --git a/tests/map/main.c b/tests/map/main.c new file mode 100644 index 0000000..28c4515 --- /dev/null +++ b/tests/map/main.c @@ -0,0 +1,37 @@ + +#include + +int TEST_001() +{ + fuse_debugf(NULL, "Creating a fuse application\n"); + fuse_t* fuse = fuse_new(FUSE_FLAG_DEBUG); + assert(fuse); + + // Create a map and then destroy it + fuse_debugf(NULL, "Creating a map of 10 items\n"); + fuse_map_t* map = fuse_map_new(fuse, 10); + assert(map); + + // Number of items should be zero + size_t size; + size_t count = fuse_map_stats(map, NULL); + assert(count == 0); + + count = fuse_map_stats(map, &size); + assert(count == 0); + assert(size == 10); + + // Destroy the map + fuse_map_destroy(fuse, map); + + // Return + return fuse_destroy(fuse); +} + +int main() +{ + assert(TEST_001() == 0); + + // Return success + return 0; +}