diff --git a/README.md b/README.md index a5d16cb..e1231eb 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,16 @@ All the features listed are Thread-safe. - Vectors - Stack +## Installation + +Clone the repo, and then using `meson` install it: + +``` +$ meson setup build +$ cd build +$ meson install +``` + ## Usage See the `test/` folder for examples. diff --git a/meson.build b/meson.build index 58abcc0..cbe0fbb 100644 --- a/meson.build +++ b/meson.build @@ -5,27 +5,42 @@ project( default_options: ['c_std=c17','warning_level=3'], ) -src = files( +cc = meson.get_compiler('c') + +# Sources without test files +lib_src = files( 'hashmap/myhashmap.c', 'queue/myqueue.c', 'string/mystring.c', 'vector/myvector.c', 'stack/mystack.c', + 'socket/mysocket.c', ) -testlib = files( +# Test files +test_src = files( 'test/test.c', 'test/hashmap/hm1.c', - 'test/queue/q1.c', + 'test/queue/queue1.c', 'test/string/str1.c', 'test/string/str2.c', 'test/string/str3.c', - 'test/vector/v1.c', - 'test/stack/s1.c', + 'test/vector/vec1.c', + 'test/stack/stack1.c', + 'test/socket/socket1.c', ) -sources = src + testlib +# Windows Socket lib +winsock_dep = cc.find_library('ws2_32', required: false) -inc_dir = include_directories('string', 'queue', 'hashmap', 'vector') +# Include directories +inc_dir = include_directories('string', 'queue', 'hashmap', 'vector', 'stack', 'socket') -executable('testlib', sources, include_directories: inc_dir) +# Static library +myclib_lib = static_library('myclib', lib_src, include_directories: inc_dir, dependencies: winsock_dep, install: true) + +# Install headers +install_headers(['hashmap/myhashmap.h', 'queue/myqueue.h', 'string/mystring.h', 'vector/myvector.h', 'stack/mystack.h', 'socket/mysocket.h'], subdir: 'myclib') + +# Test executable +executable('testlib', lib_src + test_src, include_directories: inc_dir, dependencies: winsock_dep) diff --git a/set/myset.c b/set/myset.c new file mode 100644 index 0000000..1dafe9e --- /dev/null +++ b/set/myset.c @@ -0,0 +1,28 @@ +#include "myset.h" + +#include + +set_s *set_new(size_t element_size) { + if (element_size == 0) { + return NULL; + } + + set_s *set = (set_s *)malloc(sizeof(set_s)); + if (set == NULL) { + return NULL; + } + + // TODO: think about how to deal the free_value for each element + + return set; +} + +int set_add(set_s *set, void *elem); + +int set_remove(set_s *set, void *elem); + +int set_clear(set_s *set); + +int set_contains(set_s *set, void *elem); + +void set_free(set_s *set); diff --git a/set/myset.h b/set/myset.h new file mode 100644 index 0000000..549519d --- /dev/null +++ b/set/myset.h @@ -0,0 +1,27 @@ +#ifndef MYCLIB_SET_H +#define MYCLIB_SET_H + +// TODO: WIP + +#include + +#include "../hashmap/myhashmap.h" + +typedef struct set { + hashmap_s *map; + mtx_t lock; +} set_s; + +set_s *set_new(size_t element_size); + +int set_add(set_s *set, void *elem); + +int set_remove(set_s *set, void *elem); + +int set_clear(set_s *set); + +int set_contains(set_s *set, void *elem); + +void set_free(set_s *set); + +#endif diff --git a/socket/mysocket.c b/socket/mysocket.c new file mode 100644 index 0000000..a9646ef --- /dev/null +++ b/socket/mysocket.c @@ -0,0 +1,39 @@ +#include "mysocket.h" + +#include + +int sock_platform_init() { +#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(int socket) { + int ret = 0; + +#ifdef _WIN32 + ret = closesocket(socket); +#else + ret = close(socket); +#endif + + return ret; +} + +int sock_platform_shutdown() { +#ifdef _WIN32 + WSACleanup(); +#endif + + return 0; +} diff --git a/socket/mysocket.h b/socket/mysocket.h new file mode 100644 index 0000000..b50ed10 --- /dev/null +++ b/socket/mysocket.h @@ -0,0 +1,27 @@ +#ifndef MYCLIB_SOCKET_H +#define MYCLIB_SOCKET_H + +#ifdef _WIN32 +/* Windows */ +#include +#include +#else +/* Unix */ +#include +#include +#include +#include +#include + +#endif + +/* Run this before everything */ +int sock_platform_init(); + +/* Use this to close a socket */ +int sock_close(int socket); + +/* Use at exit */ +int sock_platform_shutdown(); + +#endif diff --git a/string/mystring.c b/string/mystring.c index f9d24a4..2dde00f 100644 --- a/string/mystring.c +++ b/string/mystring.c @@ -363,7 +363,7 @@ int string_tolower(string_s *string) { /* Build Longest Prefix Suffix array */ static void build_lps(int *lps, const char *substring, size_t sub_len) { - size_t len = 0; + int len = 0; size_t i = 1; while (i < sub_len) { @@ -396,8 +396,9 @@ int string_find(string_s *string, const char *substring) { } size_t sub_len = strlen(substring); - int lps[sub_len]; - memset(lps, 0, sizeof(lps)); + + int *lps = (int *)malloc(sub_len * sizeof(int)); + memset(lps, 0, sub_len * sizeof(int)); build_lps(lps, substring, sub_len); size_t i = 0; /* string iterator */ @@ -407,9 +408,10 @@ int string_find(string_s *string, const char *substring) { i++; j++; if (j == sub_len) { + free(lps); mtx_unlock(&string->lock); - return i - j; + return (int)(i - j); } } else { if (j != 0) { @@ -420,6 +422,8 @@ int string_find(string_s *string, const char *substring) { } } + free(lps); + mtx_unlock(&string->lock); return -1; diff --git a/test/queue/q1.c b/test/queue/queue1.c similarity index 93% rename from test/queue/q1.c rename to test/queue/queue1.c index 936c549..2df7eaf 100644 --- a/test/queue/q1.c +++ b/test/queue/queue1.c @@ -1,49 +1,49 @@ -#include - -#include "../../queue/myqueue.h" - -void test_q1(void) { - /* Allocate a new queue */ - queue_s *queue = queue_new(3, sizeof(int)); - assert(queue != NULL); - - int val, out; - - /* Push value to the ring buffer */ - val = 1; - assert(queue_push(queue, &val) == 0); - - val = 2; - assert(queue_push(queue, &val) == 0); - - /* Retrieve values */ - int front, rear; - assert(queue_get_front(queue, &front) == 0); - assert(queue_get_rear(queue, &rear) == 0); - assert(front == 1); - assert(rear == 2); - - /* Remove an element from the buffer */ - assert(queue_pop(queue, &out) == 0); - assert(out == 1); - - assert(queue_get_front(queue, &front) == 0); - assert(front == 2); - - val = 3; - assert(queue_push(queue, &val) == 0); - - assert(queue_get_rear(queue, &rear) == 0); - assert(rear == 3); - - val = 4; - assert(queue_push(queue, &val) == 0); - - /* Clear queue */ - while (queue_pop(queue, &out) == 0) { - } - assert(queue->size == 0); - - /* Deallocate memory */ - queue_free(queue); -} +#include + +#include "../../queue/myqueue.h" + +void test_queue1(void) { + /* Allocate a new queue */ + queue_s *queue = queue_new(3, sizeof(int)); + assert(queue != NULL); + + int val, out; + + /* Push value to the ring buffer */ + val = 1; + assert(queue_push(queue, &val) == 0); + + val = 2; + assert(queue_push(queue, &val) == 0); + + /* Retrieve values */ + int front, rear; + assert(queue_get_front(queue, &front) == 0); + assert(queue_get_rear(queue, &rear) == 0); + assert(front == 1); + assert(rear == 2); + + /* Remove an element from the buffer */ + assert(queue_pop(queue, &out) == 0); + assert(out == 1); + + assert(queue_get_front(queue, &front) == 0); + assert(front == 2); + + val = 3; + assert(queue_push(queue, &val) == 0); + + assert(queue_get_rear(queue, &rear) == 0); + assert(rear == 3); + + val = 4; + assert(queue_push(queue, &val) == 0); + + /* Clear queue */ + while (queue_pop(queue, &out) == 0) { + } + assert(queue->size == 0); + + /* Deallocate memory */ + queue_free(queue); +} diff --git a/test/socket/socket1.c b/test/socket/socket1.c new file mode 100644 index 0000000..524dfcc --- /dev/null +++ b/test/socket/socket1.c @@ -0,0 +1,40 @@ +#include + +#include "../../socket/mysocket.h" + +void test_socket1() { + 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()\n"); + sock_platform_shutdown(); + } + + 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); + } + + sock_platform_shutdown(); +} diff --git a/test/stack/s1.c b/test/stack/stack1.c similarity index 88% rename from test/stack/s1.c rename to test/stack/stack1.c index a26902a..7fb4630 100644 --- a/test/stack/s1.c +++ b/test/stack/stack1.c @@ -3,7 +3,7 @@ #include "../../stack/mystack.h" -void test_s1(void) { +void test_stack1(void) { stack_s *stack = stack_new(32, sizeof(int)); int num = 10; stack_push(stack, &num); diff --git a/test/test.c b/test/test.c index 1d98e09..45653d7 100644 --- a/test/test.c +++ b/test/test.c @@ -7,15 +7,17 @@ void test_hm1(void); -void test_q1(void); +void test_queue1(void); void test_str1(void); void test_str2(void); void test_str3(void); -void test_v1(void); +void test_vec1(void); -void test_s1(void); +void test_stack1(void); + +void test_socket1(); int main(void) { puts("==== [Running Hashmap tests] ===="); @@ -24,7 +26,7 @@ int main(void) { puts(""); puts("==== [Running Queue tests] ===="); - test_q1(); + test_queue1(); puts("OK!"); puts(""); @@ -36,12 +38,17 @@ int main(void) { puts(""); puts("==== [Running Vector tests] ===="); - test_v1(); + test_vec1(); puts("OK!"); puts(""); puts("==== [Running Stack tests] ===="); - test_s1(); + test_stack1(); + puts("OK!"); + puts(""); + + puts("==== [Running Socket tests] ===="); + test_socket1(); puts("OK!"); puts(""); diff --git a/test/vector/v1.c b/test/vector/vec1.c similarity index 94% rename from test/vector/v1.c rename to test/vector/vec1.c index e3ff79c..1d6271e 100644 --- a/test/vector/v1.c +++ b/test/vector/vec1.c @@ -1,80 +1,80 @@ -#include -#include - -#include "../../vector/myvector.h" - -typedef struct my_elem { - char name[32]; - int age; -} my_elem_s; - -/* Functions used to iterate for each vector's element */ -static void multiply(size_t index, void *elem) { - my_elem_s *e = (my_elem_s *)elem; - e->age = e->age * 2; -} - -/* Another way to use foreach -static void print(size_t index, void *elem) { - my_elem_s *e = (my_elem_s *)elem; - printf("%s (%d)\n", e->name, e->age); -} -*/ - -/* Compare function used to sort */ -int my_cmp(const void *a, const void *b) { - /* Sort by age */ - my_elem_s *ma = (my_elem_s *)a; - my_elem_s *mb = (my_elem_s *)b; - - return ma->age - mb->age; -} - -void test_v1() { - /* Allocate a new vector */ - size_t elem_size = sizeof(my_elem_s); - vec_s *v = vec_new(10, elem_size); - assert(vec_size(v) == 0); - assert(vec_cap(v) == 16); - - /* Push an element */ - my_elem_s e1 = { - .age = 21, - .name = "John", - }; - vec_push(v, &e1); - assert(vec_size(v) == 1); - - /* Retrieve an element (Remember to free) */ - my_elem_s *e1_v = (my_elem_s *)vec_get(v, 0); - free(e1_v); - - /* Pop last element (Remember to free) */ - my_elem_s *pop = (my_elem_s *)vec_pop(v); - free(pop); - - /* Insert an element */ - vec_push(v, &e1); - e1.age = 25; - vec_push(v, &e1); - e1.age = 19; - vec_insert(v, 2, &e1); - my_elem_s last = { - .age = 33, - .name = "Last", - }; - vec_push(v, &last); - my_elem_s *lastv = (my_elem_s *)vec_pop(v); - free(lastv); - - /* Iterate for each element */ - vec_foreach(v, multiply); - /* Print each element */ - // vec_foreach(v, print); - - /* Sort */ - vec_sort(v, my_cmp); - - /* Deallocate the vector */ - vec_free(v); -} +#include +#include + +#include "../../vector/myvector.h" + +typedef struct my_elem { + char name[32]; + int age; +} my_elem_s; + +/* Functions used to iterate for each vector's element */ +static void multiply(size_t index, void *elem) { + my_elem_s *e = (my_elem_s *)elem; + e->age = e->age * 2; +} + +/* Another way to use foreach +static void print(size_t index, void *elem) { + my_elem_s *e = (my_elem_s *)elem; + printf("%s (%d)\n", e->name, e->age); +} +*/ + +/* Compare function used to sort */ +int my_cmp(const void *a, const void *b) { + /* Sort by age */ + my_elem_s *ma = (my_elem_s *)a; + my_elem_s *mb = (my_elem_s *)b; + + return ma->age - mb->age; +} + +void test_vec1() { + /* Allocate a new vector */ + size_t elem_size = sizeof(my_elem_s); + vec_s *v = vec_new(10, elem_size); + assert(vec_size(v) == 0); + assert(vec_cap(v) == 16); + + /* Push an element */ + my_elem_s e1 = { + .age = 21, + .name = "John", + }; + vec_push(v, &e1); + assert(vec_size(v) == 1); + + /* Retrieve an element (Remember to free) */ + my_elem_s *e1_v = (my_elem_s *)vec_get(v, 0); + free(e1_v); + + /* Pop last element (Remember to free) */ + my_elem_s *pop = (my_elem_s *)vec_pop(v); + free(pop); + + /* Insert an element */ + vec_push(v, &e1); + e1.age = 25; + vec_push(v, &e1); + e1.age = 19; + vec_insert(v, 2, &e1); + my_elem_s last = { + .age = 33, + .name = "Last", + }; + vec_push(v, &last); + my_elem_s *lastv = (my_elem_s *)vec_pop(v); + free(lastv); + + /* Iterate for each element */ + vec_foreach(v, multiply); + /* Print each element */ + // vec_foreach(v, print); + + /* Sort */ + vec_sort(v, my_cmp); + + /* Deallocate the vector */ + vec_free(v); +} diff --git a/vector/myvector.c b/vector/myvector.c index a666606..b9b6b48 100644 --- a/vector/myvector.c +++ b/vector/myvector.c @@ -90,11 +90,11 @@ void vec_free(vec_s *vec) { size_t vec_size(vec_s *vec) { if (vec == NULL) { - return -1; + return (size_t)-1; } if (mtx_lock(&vec->lock) != thrd_success) { - return -1; + return (size_t)-1; } size_t size = vec->size; @@ -106,11 +106,11 @@ size_t vec_size(vec_s *vec) { size_t vec_cap(vec_s *vec) { if (vec == NULL) { - return -1; + return (size_t)-1; } if (mtx_lock(&vec->lock) != thrd_success) { - return -1; + return (size_t)-1; } size_t cap = vec->capacity;