Compare commits
6 Commits
e7f2d6cdeb
...
21806e77a7
| Author | SHA1 | Date | |
|---|---|---|---|
| 21806e77a7 | |||
| a56d5b396b | |||
| 1628b3bf74 | |||
| f729463ab3 | |||
| d777b9be7f | |||
| a6740769b9 |
@@ -5,13 +5,21 @@ A small, personal C library for learning and experimentation.
|
||||
|
||||
## Features
|
||||
|
||||
All the features listed are Thread-safe.
|
||||
Most core containers use internal locks for single-object operations.
|
||||
Cross-object operations can still require caller-side synchronization.
|
||||
|
||||
- Hashmaps
|
||||
- Strings
|
||||
- Circular queues
|
||||
- Vectors
|
||||
- Stack
|
||||
- Set
|
||||
|
||||
### Notes
|
||||
|
||||
- Hashmap keys/values are copied as raw bytes (`memcpy`) using `key_size`/`value_size`.
|
||||
- For C-string keys, provide a readable key buffer of at least `key_size` bytes.
|
||||
- The set module is basic and intentionally minimal.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ void hm_free_bucket(bucket_s *bucket);
|
||||
* If the key already exists, the old value is freed (if free_value_fn is provided)
|
||||
* and replaced with the new value. If the key doesn't exist, a new entry is created.
|
||||
* Both key and value are copied into the hashmap using memcpy.
|
||||
* The caller must pass buffers that are readable for at least key_size/value_size bytes.
|
||||
* For C-string keys, use a fixed-size key buffer (or set key_size to the exact copied size).
|
||||
*
|
||||
* @param[in] hashmap Pointer to the hash map.
|
||||
* @param[in] key Pointer to the key to insert (will be copied, must not be NULL).
|
||||
|
||||
+8
-9
@@ -14,7 +14,7 @@ add_global_arguments('-D_POSIX_C_SOURCE=200112L', language: 'c')
|
||||
lib_src = files(
|
||||
'hashmap/myhashmap.c',
|
||||
'queue/myqueue.c',
|
||||
'socket/mysocket.c',
|
||||
'set/myset.c',
|
||||
'stack/mystack.c',
|
||||
'string/mystring.c',
|
||||
'vector/myvector.c',
|
||||
@@ -24,7 +24,7 @@ lib_src = files(
|
||||
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',
|
||||
@@ -33,11 +33,8 @@ test_src = files(
|
||||
'test/vector/vec1.c',
|
||||
)
|
||||
|
||||
# Windows Socket lib
|
||||
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', 'set')
|
||||
if host_machine.system() == 'windows'
|
||||
win_inc_dir = include_directories('c:/include/')
|
||||
else
|
||||
@@ -60,17 +57,19 @@ install_headers(
|
||||
'queue/myqueue.h',
|
||||
'string/mystring.h',
|
||||
'vector/myvector.h',
|
||||
'set/myset.h',
|
||||
'stack/mystack.h',
|
||||
'socket/mysocket.h',
|
||||
],
|
||||
subdir: 'myclib',
|
||||
)
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
#include "mysocket.h"
|
||||
#include <errno.h>
|
||||
|
||||
int sock_platform_init(void) {
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
|
||||
WSACleanup();
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sock_close(socket_t socket) {
|
||||
int ret = 0;
|
||||
#ifdef _WIN32
|
||||
ret = closesocket(socket);
|
||||
#else
|
||||
ret = close(socket);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sock_platform_shutdown(void) {
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sock_readall(socket_t sockfd, void *buf, size_t bufsize) {
|
||||
char *p = (char *)buf;
|
||||
size_t total_read = 0;
|
||||
|
||||
while (total_read < bufsize) {
|
||||
int n = recv(sockfd, p, bufsize - total_read, 0);
|
||||
|
||||
if (n > 0) {
|
||||
/* Data received */
|
||||
p += n;
|
||||
total_read += n;
|
||||
} else if (n == 0) {
|
||||
/* Connection closed */
|
||||
break;
|
||||
} else {
|
||||
/* Error */
|
||||
if (errno == EINTR) {
|
||||
/* Try again */
|
||||
continue;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
/* Socket non-blocking, no data right now */
|
||||
/* Returns what has read */
|
||||
return total_read;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
int sock_writeall(socket_t socket, const void *buf, size_t n) {
|
||||
const char *p = (const char *)buf;
|
||||
size_t bytes_to_write = n;
|
||||
int bytes_written;
|
||||
|
||||
while (bytes_to_write > 0) {
|
||||
bytes_written = send(socket, p, bytes_to_write, 0);
|
||||
|
||||
if (bytes_written >= 0) {
|
||||
p += bytes_written;
|
||||
bytes_to_write -= bytes_written;
|
||||
} else {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return n - bytes_to_write;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef MYCLIB_SOCKET_H
|
||||
#define MYCLIB_SOCKET_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef int socket_t;
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
/* Initialize the socket system */
|
||||
int sock_platform_init(void);
|
||||
|
||||
/* Close a socket */
|
||||
int sock_close(socket_t socket);
|
||||
|
||||
/* Clean the socket system */
|
||||
int sock_platform_shutdown(void);
|
||||
|
||||
/*
|
||||
* Read 'bufsize' bytes from socket
|
||||
* Returns the read bytes, -1 on failure, 0 connection closed without issues
|
||||
*/
|
||||
int sock_readall(socket_t sockfd, void *buf, size_t bufsize);
|
||||
|
||||
/*
|
||||
* Writes 'n' bytes to socket
|
||||
*/
|
||||
int sock_writeall(socket_t socket, const void *buf, size_t n);
|
||||
|
||||
#endif
|
||||
+10
-1
@@ -21,6 +21,7 @@ stack_s *stack_new(size_t initial_capacity, size_t element_size) {
|
||||
/* Allocate the vec data */
|
||||
stack->data = vec_new(initial_capacity, element_size);
|
||||
if (stack->data == NULL) {
|
||||
mtx_destroy(&stack->lock);
|
||||
free(stack);
|
||||
return NULL;
|
||||
}
|
||||
@@ -71,7 +72,14 @@ void *stack_top(stack_s *stack) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *elem = vec_get(stack->data, stack->data->size - 1);
|
||||
size_t size = vec_size(stack->data);
|
||||
if (size == 0) {
|
||||
mtx_unlock(&stack->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *elem = vec_get(stack->data, size - 1);
|
||||
|
||||
mtx_unlock(&stack->lock);
|
||||
|
||||
@@ -84,5 +92,6 @@ void stack_free(stack_s *stack) {
|
||||
}
|
||||
|
||||
vec_free(stack->data);
|
||||
mtx_destroy(&stack->lock);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
+6
-4
@@ -53,7 +53,7 @@ void test_hm1(void) {
|
||||
/* Pass your custom hash, equal and free functions */
|
||||
/* This hashmap will contain names as keys and a custom type as value */
|
||||
size_t key_size = sizeof(char) * MAX_STR_LEN;
|
||||
size_t value_size = sizeof(int) + sizeof(char) * MAX_STR_LEN;
|
||||
size_t value_size = sizeof(struct my_custom_type);
|
||||
hashmap_s *map =
|
||||
hm_new(my_hash_func, my_equal_fun, my_free_key, my_free_value, key_size, value_size);
|
||||
assert(map != NULL);
|
||||
@@ -65,11 +65,13 @@ void test_hm1(void) {
|
||||
strncpy(p1.favourite_brand, "Ferrari", sizeof(p1.favourite_brand));
|
||||
|
||||
/* Insert a new pair */
|
||||
assert(hm_set(map, "John", &p1));
|
||||
char john_key[MAX_STR_LEN] = {0};
|
||||
strncpy(john_key, "John", sizeof(john_key) - 1);
|
||||
assert(hm_set(map, john_key, &p1));
|
||||
|
||||
/* Retrieve the data */
|
||||
/* Remember to free the value from the get function */
|
||||
bucket_s *john = hm_get(map, "John");
|
||||
bucket_s *john = hm_get(map, john_key);
|
||||
assert(john != NULL);
|
||||
|
||||
char *name = (char *)john->key;
|
||||
@@ -85,7 +87,7 @@ void test_hm1(void) {
|
||||
hm_free_bucket(john);
|
||||
|
||||
/* Remove a key from hash map */
|
||||
assert(hm_remove(map, "John"));
|
||||
assert(hm_remove(map, john_key));
|
||||
|
||||
/* Deallocate */
|
||||
hm_free(map);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "../socket/mysocket.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void test_socket1(void) {
|
||||
sock_platform_init();
|
||||
struct addrinfo hints, *res, *p;
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
char hostname[1024];
|
||||
printf("hostname> ");
|
||||
fscanf(stdin, "%s", hostname);
|
||||
|
||||
if (getaddrinfo(hostname, NULL, &hints, &res) != 0) {
|
||||
fprintf(stderr, "getaddrinfo() failed\n");
|
||||
sock_platform_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
for (p = res; p != NULL; p = p->ai_next) {
|
||||
void *addr = 0;
|
||||
char *ipver = 0;
|
||||
struct sockaddr_in *ipv4;
|
||||
if (p->ai_family == AF_INET) {
|
||||
ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
addr = &(ipv4->sin_addr);
|
||||
ipver = "IPv4";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
printf("%s: %s\n", ipver, ipstr);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
sock_platform_shutdown();
|
||||
}
|
||||
+3
-3
@@ -17,7 +17,7 @@ void test_vec1(void);
|
||||
|
||||
void test_stack1(void);
|
||||
|
||||
void test_socket1(void);
|
||||
void test_set1(void);
|
||||
|
||||
int main(void) {
|
||||
puts("==== [Running Hashmap tests] ====");
|
||||
@@ -47,8 +47,8 @@ int main(void) {
|
||||
puts("OK!");
|
||||
puts("");
|
||||
|
||||
puts("==== [Running Socket tests] ====");
|
||||
test_socket1();
|
||||
puts("==== [Running Set tests] ====");
|
||||
test_set1();
|
||||
puts("OK!");
|
||||
puts("");
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef struct my_elem {
|
||||
|
||||
/* Functions used to iterate for each vector's element */
|
||||
static void multiply(size_t index, void *elem) {
|
||||
(void)index;
|
||||
my_elem_s *e = (my_elem_s *)elem;
|
||||
e->age = e->age * 2;
|
||||
}
|
||||
@@ -65,12 +66,40 @@ void test_vec1(void) {
|
||||
vec_push(v, &last);
|
||||
my_elem_s *lastv = (my_elem_s *)vec_pop(v);
|
||||
free(lastv);
|
||||
assert(vec_get(v, vec_size(v)) == NULL);
|
||||
assert(vec_remove(v, vec_size(v)) == -1);
|
||||
|
||||
/* Remove from the middle and validate shifted content for elem_size > 1 */
|
||||
assert(vec_remove(v, 1) == 0);
|
||||
my_elem_s *shifted = (my_elem_s *)vec_get(v, 1);
|
||||
assert(shifted != NULL);
|
||||
assert(shifted->age == 19);
|
||||
free(shifted);
|
||||
|
||||
my_elem_s replacement = {
|
||||
.age = 40,
|
||||
.name = "Updated",
|
||||
};
|
||||
assert(vec_set(v, 1, &replacement) == 0);
|
||||
assert(vec_set(v, vec_size(v), &replacement) == -1);
|
||||
my_elem_s *updated = (my_elem_s *)vec_get(v, 1);
|
||||
assert(updated != NULL);
|
||||
assert(updated->age == 40);
|
||||
free(updated);
|
||||
|
||||
/* Iterate for each element */
|
||||
vec_foreach(v, multiply);
|
||||
/* Print each element */
|
||||
// vec_foreach(v, print);
|
||||
|
||||
/* Shrink to fit current size and ensure data is still readable */
|
||||
size_t before_shrink_size = vec_size(v);
|
||||
assert(vec_shrink(v) == 0);
|
||||
assert(vec_cap(v) == before_shrink_size);
|
||||
my_elem_s *shrink_elem = (my_elem_s *)vec_get(v, 1);
|
||||
assert(shrink_elem != NULL);
|
||||
free(shrink_elem);
|
||||
|
||||
/* Sort */
|
||||
vec_sort(v, my_cmp);
|
||||
|
||||
|
||||
+83
-28
@@ -22,6 +22,10 @@ static size_t next_power_two(size_t len) {
|
||||
}
|
||||
|
||||
vec_s *vec_new(size_t initial_capacity, size_t element_size) {
|
||||
if (element_size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec_s *vec = (vec_s *)malloc(sizeof(vec_s));
|
||||
if (vec == NULL) {
|
||||
return NULL;
|
||||
@@ -30,6 +34,11 @@ vec_s *vec_new(size_t initial_capacity, size_t element_size) {
|
||||
vec->capacity = next_power_two(initial_capacity);
|
||||
vec->elem_size = element_size;
|
||||
vec->size = 0;
|
||||
if (vec->capacity > SIZE_MAX / vec->elem_size) {
|
||||
free(vec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
vec->data = malloc(vec->capacity * vec->elem_size);
|
||||
if (vec->data == NULL) {
|
||||
free(vec);
|
||||
@@ -58,14 +67,21 @@ int vec_push(vec_s *vec, void *elem) {
|
||||
|
||||
if (vec->size + 1 > vec->capacity) {
|
||||
/* Reallocate buffer */
|
||||
vec->capacity = next_power_two(vec->size + 1);
|
||||
void *tmp = realloc(vec->data, vec->capacity * vec->elem_size);
|
||||
size_t new_capacity = next_power_two(vec->size + 1);
|
||||
if (new_capacity > SIZE_MAX / vec->elem_size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *tmp = realloc(vec->data, new_capacity * vec->elem_size);
|
||||
if (tmp == NULL) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
vec->data = tmp;
|
||||
vec->capacity = new_capacity;
|
||||
}
|
||||
|
||||
/* Add the new element */
|
||||
@@ -86,16 +102,18 @@ void vec_free(vec_s *vec) {
|
||||
free(vec->data);
|
||||
}
|
||||
|
||||
mtx_destroy(&vec->lock);
|
||||
|
||||
free(vec);
|
||||
}
|
||||
|
||||
size_t vec_size(vec_s *vec) {
|
||||
if (vec == NULL) {
|
||||
return (size_t)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return (size_t)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t size = vec->size;
|
||||
@@ -107,11 +125,11 @@ size_t vec_size(vec_s *vec) {
|
||||
|
||||
size_t vec_cap(vec_s *vec) {
|
||||
if (vec == NULL) {
|
||||
return (size_t)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return (size_t)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t cap = vec->capacity;
|
||||
@@ -122,7 +140,7 @@ size_t vec_cap(vec_s *vec) {
|
||||
}
|
||||
|
||||
void *vec_get(vec_s *vec, size_t index) {
|
||||
if (vec == NULL || index > vec->size) {
|
||||
if (vec == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -130,8 +148,16 @@ void *vec_get(vec_s *vec, size_t index) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= vec->size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *elem = malloc(vec->elem_size);
|
||||
if (elem == NULL) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -151,7 +177,14 @@ int vec_shrink(vec_s *vec) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *tmp = realloc(vec->data, vec->size);
|
||||
size_t new_capacity = (vec->size == 0) ? 1 : vec->size;
|
||||
if (new_capacity > SIZE_MAX / vec->elem_size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *tmp = realloc(vec->data, new_capacity * vec->elem_size);
|
||||
if (tmp == NULL) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
@@ -159,7 +192,7 @@ int vec_shrink(vec_s *vec) {
|
||||
}
|
||||
|
||||
vec->data = tmp;
|
||||
vec->capacity = vec->size;
|
||||
vec->capacity = new_capacity;
|
||||
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
@@ -175,7 +208,7 @@ int vec_clear(vec_s *vec) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(vec->data, 0, vec->size);
|
||||
memset(vec->data, 0, vec->size * vec->elem_size);
|
||||
vec->size = 0;
|
||||
|
||||
mtx_unlock(&vec->lock);
|
||||
@@ -188,15 +221,23 @@ void *vec_pop(vec_s *vec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vec->size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vec->size == 0) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *e = malloc(vec->elem_size);
|
||||
if (e == NULL) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec->size--;
|
||||
memcpy(e, (char *)vec->data + (vec->size * vec->elem_size), vec->elem_size);
|
||||
|
||||
@@ -210,29 +251,39 @@ int vec_insert(vec_s *vec, size_t index, void *value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index > vec->size) {
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
if (index > vec->size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vec->size + 1 > vec->capacity) {
|
||||
/* No space, realloc */
|
||||
void *tmp = realloc(vec->data, next_power_two(vec->size + 1));
|
||||
size_t new_capacity = next_power_two(vec->size + 1);
|
||||
if (new_capacity > SIZE_MAX / vec->elem_size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *tmp = realloc(vec->data, new_capacity * vec->elem_size);
|
||||
if (tmp == NULL) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
vec->data = tmp;
|
||||
vec->capacity = new_capacity;
|
||||
}
|
||||
|
||||
/* Shift memory and copy the new value */
|
||||
size_t tmp_size = vec->size - index + 1;
|
||||
memmove((char *)vec->data + (index * vec->elem_size),
|
||||
(char *)vec->data + ((index + 1) * vec->elem_size), tmp_size * vec->elem_size);
|
||||
size_t elements_to_move = vec->size - index;
|
||||
memmove((char *)vec->data + ((index + 1) * vec->elem_size),
|
||||
(char *)vec->data + (index * vec->elem_size), elements_to_move * vec->elem_size);
|
||||
memcpy((char *)vec->data + (index * vec->elem_size), value, vec->elem_size);
|
||||
vec->size++;
|
||||
|
||||
@@ -246,18 +297,20 @@ int vec_remove(vec_s *vec, size_t index) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index > vec->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t size = vec->size - index;
|
||||
if (index >= vec->size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t size = vec->size - index - 1;
|
||||
/* Overwrite bytes */
|
||||
memmove((char *)vec->data + (index * vec->elem_size),
|
||||
(char *)vec->data + ((index + 1) * vec->elem_size), size);
|
||||
(char *)vec->data + ((index + 1) * vec->elem_size), size * vec->elem_size);
|
||||
vec->size--;
|
||||
|
||||
mtx_unlock(&vec->lock);
|
||||
@@ -270,11 +323,13 @@ int vec_set(vec_s *vec, size_t index, void *value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index > vec->size) {
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock), thrd_success) {
|
||||
if (index >= vec->size) {
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user