From 5203f76d46552cde34dc27b7b01818cdabbd68bb Mon Sep 17 00:00:00 2001 From: Francesco Date: Sun, 3 Aug 2025 19:57:31 +0200 Subject: [PATCH] add queue --- README.md | 1 + examples/hashmap/hm1.c | 7 ++++ examples/queue/q1.c | 53 +++++++++++++++++++++++++ examples/string/str1.c | 24 ++++++++++++ queue/myqueue.c | 89 ++++++++++++++++++++++++++++++++++++++++++ queue/myqueue.h | 68 ++++++++++++++++++++++++++++++++ string/mystring.c | 16 ++++---- 7 files changed, 250 insertions(+), 8 deletions(-) create mode 100644 examples/hashmap/hm1.c create mode 100644 examples/queue/q1.c create mode 100644 examples/string/str1.c create mode 100644 queue/myqueue.c create mode 100644 queue/myqueue.h diff --git a/README.md b/README.md index b11d2ca..7824074 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,4 @@ It is not production-ready. Use at your own risk. - Hashmaps - Thread-safe (MT Safe) - Dynamic strings - Not thread-safe (MT Unsafe) > Requires linking with the C math library (`-lm`) +- Circular Queue - Not thread-safe (MT Unsafe) diff --git a/examples/hashmap/hm1.c b/examples/hashmap/hm1.c new file mode 100644 index 0000000..b1e8e0d --- /dev/null +++ b/examples/hashmap/hm1.c @@ -0,0 +1,7 @@ +#include + +int main(void) { + puts("TODO: Hashmap"); + + return 0; +} diff --git a/examples/queue/q1.c b/examples/queue/q1.c new file mode 100644 index 0000000..6d231d0 --- /dev/null +++ b/examples/queue/q1.c @@ -0,0 +1,53 @@ +#include +#include + +#include "../../queue/myqueue.h" + +int main(void) { + mcl_queue *queue = mcl_queue_init(3, sizeof(int)); + assert(queue != NULL); + + int val, out; + + val = 1; + assert(mcl_queue_push(queue, &val) == 0); + + val = 2; + assert(mcl_queue_push(queue, &val) == 0); + + int front = *((int *)mcl_queue_get_front(queue)); + int rear = *((int *)mcl_queue_get_rear(queue)); + printf("Front: %d, Rear: %d\n", front, rear); + assert(front == 1); + assert(rear == 2); + + assert(mcl_queue_pop(queue, &out) == 0); + printf("Pop: %d\n", out); + assert(out == 1); + + front = *((int *)mcl_queue_get_front(queue)); + printf("Front after pop: %d\n", front); + assert(front == 2); + + val = 3; + assert(mcl_queue_push(queue, &val) == 0); + + rear = *((int *)mcl_queue_get_rear(queue)); + printf("Rear after push 3: %d\n", rear); + assert(rear == 3); + + val = 4; + int res = mcl_queue_push(queue, &val); + assert(res == 0); + + while (mcl_queue_pop(queue, &out) == 0) { + printf("Pop: %d\n", out); + } + printf("Queue is now empty\n"); + + assert(mcl_queue_pop(queue, &out) == -1); + + mcl_queue_free(queue); + printf("All tests passed successfully.\n"); + return 0; +} diff --git a/examples/string/str1.c b/examples/string/str1.c new file mode 100644 index 0000000..c2250e9 --- /dev/null +++ b/examples/string/str1.c @@ -0,0 +1,24 @@ +#include +#include + +#include "../../string/mystring.h" + +int main(void) { + mcl_string *str = mcl_string_new("Hello, world!", 512); + assert(str != NULL); + + printf("%s\nsize: %ld, cap: %ld\n", mcl_string_cstr(str), (long)mcl_string_length(str), (long)mcl_string_capacity(str)); + assert(mcl_string_length(str) == 13); + + int ret = mcl_string_append(str, " How are you?"); + assert(ret == 0); + + printf("After append:\n"); + printf("%s\nsize: %ld, cap: %ld\n", mcl_string_cstr(str), (long)mcl_string_length(str), (long)mcl_string_capacity(str)); + assert(mcl_string_length(str) == 26); + + mcl_string_free(str); + + printf("All tests passed successfully.\n"); + return 0; +} diff --git a/queue/myqueue.c b/queue/myqueue.c new file mode 100644 index 0000000..49fe73e --- /dev/null +++ b/queue/myqueue.c @@ -0,0 +1,89 @@ +#include "myqueue.h" + +#include +#include + +mcl_queue *mcl_queue_init(size_t queue_size, size_t elem_size) { + mcl_queue *queue = malloc(sizeof(mcl_queue)); + if (queue == NULL) { + return NULL; + } + + queue->buffer = malloc(queue_size * elem_size); + if (queue->buffer == NULL) { + free(queue); + + return NULL; + } + + queue->front = 0; + queue->rear = 0; + queue->size = 0; + queue->capacity = queue_size; + queue->elem_size = elem_size; + + return queue; +} + +int mcl_queue_push(mcl_queue *queue, const void *elem) { + if (queue->size == queue->capacity) { + /* Queue full */ + return -1; + } + + /* Copy the elem in the buffer */ + void *dest = (void *)queue->buffer + (queue->rear * queue->elem_size); + memcpy(dest, elem, queue->elem_size); + + queue->size++; + queue->rear = (queue->rear + 1) % queue->capacity; + + return 0; +} + +int mcl_queue_pop(mcl_queue *queue, void *out_elem) { + if (queue->size == 0) { + /* Queue empty */ + return -1; + } + + void *src = (void *)queue->buffer + (queue->front * queue->elem_size); + memcpy(out_elem, src, queue->elem_size); + + queue->front = (queue->front + 1) % queue->capacity; + queue->size--; + + return 0; +} + +void *mcl_queue_get_front(mcl_queue *queue) { + if (queue->size == 0) { + return NULL; + } + + return (void *)queue->buffer + (queue->front * queue->elem_size); +} + +void *mcl_queue_get_rear(mcl_queue *queue) { + if (queue->size == 0) { + return NULL; + } + + size_t rear_index; + if (queue->rear == 0) { + rear_index = queue->capacity - 1; + } else { + rear_index = queue->rear - 1; + } + + return (void *)queue->buffer + (rear_index * queue->elem_size); +} + +void mcl_queue_free(mcl_queue *queue) { + if (queue == NULL) { + return; + } + + free(queue->buffer); + free(queue); +} diff --git a/queue/myqueue.h b/queue/myqueue.h new file mode 100644 index 0000000..42d4bfd --- /dev/null +++ b/queue/myqueue.h @@ -0,0 +1,68 @@ +#ifndef MYCLIB_QUEUE_H +#define MYCLIB_QUEUE_H + +#include + +/** + * @brief A generic circular queue (ring buffer). + */ +typedef struct mcl_queue_t { + size_t front; /**< Index of the first element (read position). */ + size_t rear; /**< Index where the next element will be written (write position). */ + size_t size; /**< Current number of elements in the queue. */ + size_t capacity; /**< Maximum number of elements the queue can hold. */ + size_t elem_size; /**< Size in bytes of each element in the queue. */ + void *buffer; /**< Pointer to the memory buffer that stores the elements. */ +} mcl_queue; + +/** + * @brief Create and initialize a new queue. + * + * @param queue_size Number of elements the queue can hold. + * @param elem_size Size (in bytes) of each element in the queue. + * @return Pointer to the new queue, or NULL if allocation fails. + */ +mcl_queue *mcl_queue_init(size_t queue_size, size_t elem_size); + +/** + * @brief Add an element to the queue. + * + * @param queue Pointer to the queue. + * @param elem Pointer to the element to insert. + * @return 0 on success, -1 if the queue is full. + */ +int mcl_queue_push(mcl_queue *queue, const void *elem); + +/** + * @brief Remove an element from the queue. + * + * @param queue Pointer to the queue. + * @param out_elem Pointer where the removed element will be copied. + * @return 0 on success, -1 if the queue is empty. + */ +int mcl_queue_pop(mcl_queue *queue, void *out_elem); + +/** + * @brief Get a pointer to the front element of the queue (oldest one). + * + * @param queue Pointer to the queue. + * @return Pointer to the front element, or NULL if the queue is empty. + */ +void *mcl_queue_get_front(mcl_queue *queue); + +/** + * @brief Get a pointer to the rear element of the queue (most recently added). + * + * @param queue Pointer to the queue. + * @return Pointer to the rear element, or NULL if the queue is empty. + */ +void *mcl_queue_get_rear(mcl_queue *queue); + +/** + * @brief Free all memory used by the queue. + * + * @param queue Pointer to the queue to free. + */ +void mcl_queue_free(mcl_queue *queue); + +#endif diff --git a/string/mystring.c b/string/mystring.c index 2e979fc..1d95df7 100644 --- a/string/mystring.c +++ b/string/mystring.c @@ -5,13 +5,13 @@ #include mcl_string *mcl_string_new(const char *text, long initial_capacity) { - if (!text) { + if (text == NULL) { return NULL; } /* Allocate string struct */ mcl_string *str = malloc(sizeof(mcl_string)); - if (!str) { + if (str == NULL) { return NULL; } @@ -31,7 +31,7 @@ mcl_string *mcl_string_new(const char *text, long initial_capacity) { /* Allocate data buffer */ str->data = malloc(sizeof(char) * str->capacity); - if (!str->data) { + if (str->data == NULL) { free(str); return NULL; @@ -46,7 +46,7 @@ mcl_string *mcl_string_new(const char *text, long initial_capacity) { } int mcl_string_append(mcl_string *string, const char *text) { - if (!string || !text) { + if (string == NULL || text == NULL) { return -1; } @@ -83,7 +83,7 @@ int mcl_string_append(mcl_string *string, const char *text) { } void mcl_string_free(mcl_string *string) { - if (!string) { + if (string == NULL) { return; } @@ -95,7 +95,7 @@ void mcl_string_free(mcl_string *string) { } size_t mcl_string_length(const mcl_string *string) { - if (!string) { + if (string == NULL) { return 0; } @@ -103,7 +103,7 @@ size_t mcl_string_length(const mcl_string *string) { } size_t mcl_string_capacity(const mcl_string *string) { - if (!string) { + if (string == NULL) { return 0; } @@ -111,7 +111,7 @@ size_t mcl_string_capacity(const mcl_string *string) { } const char *mcl_string_cstr(const mcl_string *string) { - if (!string || !string->data) { + if (string == NULL || string->data == NULL) { return ""; }