Skip to content

Commit

Permalink
Added map function (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
djthorpe authored Oct 24, 2023
1 parent 0407114 commit 88f4740
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
3 changes: 2 additions & 1 deletion include/fuse/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
#endif /* FUSE_DEBUG_H */
1 change: 1 addition & 0 deletions include/fuse/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ typedef struct fuse_instance fuse_t;
#include <fuse/debug.h>
#include <fuse/flags.h>
#include <fuse/list.h>
#include <fuse/map.h>
#include <fuse/pool.h>
#include <fuse/sleep.h>
#include <fuse/string.h>
Expand Down
73 changes: 73 additions & 0 deletions include/fuse/map.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions src/fuse/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_library(${NAME} STATIC
debug.c
epoll.c
fuse.c
map.c
panic.c
pool.c
pool_std.c
Expand Down
3 changes: 2 additions & 1 deletion src/fuse/fuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/fuse/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/
#ifndef FUSE_PRIVATE_LIST_H
#define FUSE_PRIVATE_LIST_H

#include <fuse/fuse.h>

/* @brief Represents an instance of a fuse linked list
Expand Down
94 changes: 94 additions & 0 deletions src/fuse/map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <string.h>
#include <fuse/fuse.h>

// 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
}
25 changes: 25 additions & 0 deletions src/fuse/map.h
Original file line number Diff line number Diff line change
@@ -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 <fuse/fuse.h>

/* @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
2 changes: 1 addition & 1 deletion src/fuse/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// PUBLIC METHODS

#ifdef TARGET
#if TARGET != pico
#if TARGET == darwin || TARGET == linux

#include <stdint.h>
#include <time.h>
Expand Down
21 changes: 21 additions & 0 deletions tests/map/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
37 changes: 37 additions & 0 deletions tests/map/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

#include <fuse/fuse.h>

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;
}

0 comments on commit 88f4740

Please sign in to comment.