From a6740769b96f751611fb40fd85d9b309647d4324 Mon Sep 17 00:00:00 2001 From: Francesco Date: Mon, 16 Mar 2026 23:06:29 +0100 Subject: [PATCH] feat(set): add set --- meson.build | 11 ++-- set/myset.c | 135 +++++++++++++++++++++++++++++++++++++++++++++--- set/myset.h | 14 +++-- test/set/set1.c | 31 +++++++++++ 4 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 test/set/set1.c diff --git a/meson.build b/meson.build index 651ffa3..ff622e5 100644 --- a/meson.build +++ b/meson.build @@ -15,6 +15,7 @@ lib_src = files( 'hashmap/myhashmap.c', 'queue/myqueue.c', 'socket/mysocket.c', + 'set/myset.c', 'stack/mystack.c', 'string/mystring.c', 'vector/myvector.c', @@ -25,6 +26,7 @@ test_src = files( 'test/hashmap/hm1.c', 'test/queue/queue1.c', 'test/socket/socket1.c', + 'test/set/set1.c', 'test/stack/stack1.c', 'test/string/str1.c', 'test/string/str2.c', @@ -37,7 +39,7 @@ test_src = files( winsock_dep = cc.find_library('ws2_32', required: false) # Include directories -inc_dir = include_directories('string', 'queue', 'hashmap', 'vector', 'stack', 'socket') +inc_dir = include_directories('string', 'queue', 'hashmap', 'vector', 'stack', 'socket', 'set') if host_machine.system() == 'windows' win_inc_dir = include_directories('c:/include/') else @@ -60,6 +62,7 @@ install_headers( 'queue/myqueue.h', 'string/mystring.h', 'vector/myvector.h', + 'set/myset.h', 'stack/mystack.h', 'socket/mysocket.h', ], @@ -67,10 +70,12 @@ install_headers( ) # Test executable -executable( +testlib_exe = executable( 'testlib', - lib_src + test_src, + test_src, include_directories: [inc_dir, win_inc_dir], dependencies: winsock_dep, link_with: myclib_lib, ) + +test('testlib', testlib_exe) diff --git a/set/myset.c b/set/myset.c index 8e897ae..e8677cb 100644 --- a/set/myset.c +++ b/set/myset.c @@ -1,6 +1,30 @@ #include "myset.h" +#include #include +#include + +static int set_find_index_locked(set_s *set, void *elem, size_t *index_out) { + size_t size = vec_size(set->data); + + for (size_t i = 0; i < size; ++i) { + void *current = vec_get(set->data, i); + if (current == NULL) { + return -1; + } + + int equal = (memcmp(current, elem, set->elem_size) == 0); + free(current); + + if (equal) { + *index_out = i; + return 0; + } + } + + *index_out = SIZE_MAX; + return 0; +} set_s *set_new(size_t element_size) { if (element_size == 0) { @@ -12,17 +36,116 @@ set_s *set_new(size_t element_size) { return NULL; } - // TODO: think about how to deal the free_value for each element + if (mtx_init(&set->lock, mtx_plain) != thrd_success) { + free(set); + return NULL; + } + + set->data = vec_new(8, element_size); + if (set->data == NULL) { + mtx_destroy(&set->lock); + free(set); + return NULL; + } + + set->elem_size = element_size; return set; } -int set_add(set_s *set, void *elem); +int set_add(set_s *set, void *elem) { + if (set == NULL || elem == NULL) { + return -1; + } -int set_remove(set_s *set, void *elem); + if (mtx_lock(&set->lock) != thrd_success) { + return -1; + } -int set_clear(set_s *set); + size_t index; + if (set_find_index_locked(set, elem, &index) != 0) { + mtx_unlock(&set->lock); + return -1; + } -int set_contains(set_s *set, void *elem); + if (index != SIZE_MAX) { + mtx_unlock(&set->lock); + return 0; + } -void set_free(set_s *set); + int ret = vec_push(set->data, elem); + + mtx_unlock(&set->lock); + return ret; +} + +int set_remove(set_s *set, void *elem) { + if (set == NULL || elem == NULL) { + return -1; + } + + if (mtx_lock(&set->lock) != thrd_success) { + return -1; + } + + size_t index; + if (set_find_index_locked(set, elem, &index) != 0) { + mtx_unlock(&set->lock); + return -1; + } + + if (index == SIZE_MAX) { + mtx_unlock(&set->lock); + return -1; + } + + int ret = vec_remove(set->data, index); + + mtx_unlock(&set->lock); + return ret; +} + +int set_clear(set_s *set) { + if (set == NULL) { + return -1; + } + + if (mtx_lock(&set->lock) != thrd_success) { + return -1; + } + + int ret = vec_clear(set->data); + + mtx_unlock(&set->lock); + return ret; +} + +int set_contains(set_s *set, void *elem) { + if (set == NULL || elem == NULL) { + return -1; + } + + if (mtx_lock(&set->lock) != thrd_success) { + return -1; + } + + size_t index; + if (set_find_index_locked(set, elem, &index) != 0) { + mtx_unlock(&set->lock); + return -1; + } + + mtx_unlock(&set->lock); + + return (index == SIZE_MAX) ? 0 : 1; +} + +void set_free(set_s *set) { + if (set == NULL) { + return; + } + + vec_free(set->data); + mtx_destroy(&set->lock); + free(set); +} diff --git a/set/myset.h b/set/myset.h index 59174ea..650a79a 100644 --- a/set/myset.h +++ b/set/myset.h @@ -1,27 +1,33 @@ #ifndef MYCLIB_SET_H #define MYCLIB_SET_H -// TODO: WIP - +#include #include -#include "../hashmap/myhashmap.h" +#include "../vector/myvector.h" typedef struct set { - hashmap_s *map; + vec_s *data; + size_t elem_size; mtx_t lock; } set_s; +/* Create a new set for fixed-size elements. */ set_s *set_new(size_t element_size); +/* Add a new element to the set (no-op if already present). */ int set_add(set_s *set, void *elem); +/* Remove an element from the set. */ int set_remove(set_s *set, void *elem); +/* Remove all elements from the set. */ int set_clear(set_s *set); +/* Returns 1 if present, 0 if absent, -1 on error. */ int set_contains(set_s *set, void *elem); +/* Free the set and all related resources. */ void set_free(set_s *set); #endif diff --git a/test/set/set1.c b/test/set/set1.c new file mode 100644 index 0000000..54e0b79 --- /dev/null +++ b/test/set/set1.c @@ -0,0 +1,31 @@ +#include "../set/myset.h" + +#include + +void test_set1(void) { + set_s *set = set_new(sizeof(int)); + assert(set != NULL); + + int a = 10; + int b = 20; + int another_a = 10; + int missing = 99; + + assert(set_add(set, &a) == 0); + assert(set_add(set, &b) == 0); + /* Duplicate values are ignored and treated as success. */ + assert(set_add(set, &another_a) == 0); + + assert(set_contains(set, &a) == 1); + assert(set_contains(set, &another_a) == 1); + assert(set_contains(set, &missing) == 0); + + assert(set_remove(set, &a) == 0); + assert(set_contains(set, &a) == 0); + assert(set_remove(set, &a) == -1); + + assert(set_clear(set) == 0); + assert(set_contains(set, &b) == 0); + + set_free(set); +}