feat(set): add set
This commit is contained in:
+8
-3
@@ -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)
|
||||
|
||||
+129
-6
@@ -1,6 +1,30 @@
|
||||
#include "myset.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+10
-4
@@ -1,27 +1,33 @@
|
||||
#ifndef MYCLIB_SET_H
|
||||
#define MYCLIB_SET_H
|
||||
|
||||
// TODO: WIP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <threads.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "../set/myset.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user