Last active
January 15, 2023 12:37
-
-
Save matheusmv/270d5ebfaa2ae63d769a04911ab68a4d to your computer and use it in GitHub Desktop.
queue with dynamic array in c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "queue.h" | |
#include <assert.h> | |
static Queue* queue_malloc(size_t capacity, object_copy copy_func, object_free free_func) { | |
Queue* queue = NULL; | |
Vector* array = NULL; | |
queue = calloc(1, sizeof(Queue)); | |
if (queue == NULL) | |
goto error; | |
if (vector_init_with_capacity(&array, capacity, copy_func, free_func) < 0) | |
goto error; | |
*queue = (Queue) { | |
.array = array, | |
}; | |
return queue; | |
error: | |
if (queue != NULL) free(queue); | |
if (array != NULL) vector_free(&array); | |
return NULL; | |
} | |
int queue_init(Queue** queue, object_copy copy_func, object_free free_func) { | |
assert(queue != NULL); | |
Queue* new_queue = NULL; | |
new_queue = queue_malloc(DEFAULT_CAPACITY, copy_func, free_func); | |
if (new_queue == NULL) | |
exit(EXIT_FAILURE); | |
*queue = new_queue; | |
return 0; | |
} | |
int queue_init_with_capacity(Queue** queue, size_t capacity, object_copy copy_func, object_free free_func) { | |
assert(queue != NULL && capacity > 0); | |
Queue* new_queue = NULL; | |
new_queue = queue_malloc(capacity, copy_func, free_func); | |
if (new_queue == NULL) | |
exit(EXIT_FAILURE); | |
*queue = new_queue; | |
return 0; | |
} | |
void queue_free(Queue** queue) { | |
if (queue == NULL || *queue == NULL) | |
return; | |
if ((*queue)->array != NULL) | |
vector_free(&(*queue)->array); | |
free(*queue); | |
*queue = NULL; | |
} | |
size_t queue_length(Queue** queue) { | |
assert(queue != NULL && *queue != NULL); | |
return vector_length(&(*queue)->array); | |
} | |
int queue_enqueue(Queue** queue, const void* object) { | |
assert(queue != NULL && *queue != NULL); | |
return vector_push_back(&(*queue)->array, object); | |
} | |
int queue_dequeue(Queue** queue, void** ret_buffer) { | |
assert(queue != NULL && *queue != NULL); | |
return vector_remove_at_index(&(*queue)->array, 0, ret_buffer); | |
} | |
void queue_for_each(Queue** queue, void (* consumer_func)(const void*)) { | |
assert(queue != NULL && *queue != NULL); | |
vector_for_each(&(*queue)->array, consumer_func); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef QUEUE_H_ | |
#define QUEUE_H_ | |
#include "vector.h" | |
typedef struct Queue Queue; | |
struct Queue { | |
Vector* array; | |
}; | |
int queue_init(Queue** queue, object_copy copy_func, object_free free_func); | |
int queue_init_with_capacity(Queue** queue, size_t capacity, object_copy copy_func, object_free free_func); | |
void queue_free(Queue** queue); | |
size_t queue_length(Queue** queue); | |
int queue_enqueue(Queue** queue, const void* object); | |
int queue_dequeue(Queue** queue, void** ret_buffer); | |
void queue_for_each(Queue** queue, void (* consumer_func)(const void*)); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "queue.h" | |
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
typedef struct User User; | |
struct User { | |
int id; | |
char* username; | |
char* password; | |
char* email; | |
}; | |
User user_create(int id, char* username, char* password, char* email); | |
User* user_new(int id, const char* username, const char* password, const char* email); | |
User* user_copy(const User* other); | |
void user_free(User** user); | |
void show_user(const User* user); | |
int main(void) { | |
Queue* users = NULL; | |
object_copy copy_func = (object_copy) user_copy; | |
object_free free_func = (object_free) user_free; | |
queue_init(&users, copy_func, free_func); | |
User john = user_create(1, "john", "12345", "john@email.com"); | |
User carl = user_create(2, "carl", "12345", "carl@email.com"); | |
User alex = user_create(3, "alex", "12345", "alex@email.com"); | |
queue_enqueue(&users, &john); | |
queue_enqueue(&users, &carl); | |
queue_enqueue(&users, &alex); | |
void (* log)(const void*) = (void (*)(const void*)) show_user; | |
queue_for_each(&users, log); | |
User* user = NULL; | |
queue_dequeue(&users, (void**) &user); | |
show_user(user); | |
user_free(&user); | |
queue_free(&users); | |
return EXIT_SUCCESS; | |
} | |
User user_create(int id, char* username, char* password, char* email) { | |
return (User) { | |
.id = id, | |
.username = username, | |
.password = password, | |
.email = email, | |
}; | |
} | |
static char* str_dup(const char* other) { | |
char* copy = NULL; | |
size_t len = strlen(other); | |
copy = malloc(len + 1); | |
memcpy(copy, other, len); | |
copy[len] = '\0'; | |
return copy; | |
} | |
User* user_new(int id, const char* username, const char* password, const char* email) { | |
User* user = NULL; | |
user = malloc(sizeof(User)); | |
user->id = id; | |
#if defined(_GNU_SORCE) | |
user->username = strdup(username); | |
user->password = strdup(password); | |
user->email = strdup(email); | |
#else | |
user->username = str_dup(username); | |
user->password = str_dup(password); | |
user->email = str_dup(email); | |
#endif | |
return user; | |
} | |
User* user_copy(const User* other) { | |
assert(other != NULL); | |
return user_new(other->id, other->username, other->password, other->email); | |
} | |
void user_free(User** user) { | |
if (user == NULL || *user == NULL) | |
return; | |
free((*user)->username); | |
free((*user)->password); | |
free((*user)->email); | |
free((*user)); | |
*user = NULL; | |
} | |
void show_user(const User* user) { | |
if (user == NULL) | |
return; | |
printf("id: %d, username: %s, password: %s, email: %s\n", | |
user->id, user->username, user->password, user->email); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "vector.h" | |
#include <assert.h> | |
#include <errno.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <string.h> | |
static Vector* vector_malloc(size_t capacity) { | |
Vector* vector = NULL; | |
Buffer* buffer = NULL; | |
vector = calloc(1, sizeof(Vector)); | |
if (vector == NULL) | |
goto error; | |
buffer = calloc(capacity, sizeof(Buffer)); | |
if (buffer == NULL) | |
goto error; | |
*vector = (Vector) { | |
.buffer = buffer, | |
.length = 0, | |
.capacity = capacity, | |
.copy = NULL, | |
.free = NULL, | |
}; | |
return vector; | |
error: | |
fprintf(stderr, "[ERROR] -- [%s]: %s\n", __func__, strerror(errno)); | |
if (vector != NULL) free(vector); | |
if (buffer != NULL) free(buffer); | |
return NULL; | |
} | |
static int vector_buffer_resize(Vector** vector) { | |
assert(vector != NULL && *vector != NULL && (*vector)->capacity > 0); | |
const size_t new_capacity = (*vector)->capacity * 2; | |
Buffer* new_buffer = NULL; | |
new_buffer = realloc((*vector)->buffer, new_capacity * sizeof(Buffer)); | |
if (new_buffer == NULL) { | |
fprintf(stderr, "[ERROR] -- [%s]: %s\n", __func__, strerror(errno)); | |
return -1; | |
} | |
*(*vector) = (Vector) { | |
.buffer = new_buffer, | |
.length = (*vector)->length, | |
.capacity = new_capacity, | |
.copy = (*vector)->copy, | |
.free = (*vector)->free, | |
}; | |
return 0; | |
} | |
static bool vector_has_storage_available(Vector** vector, size_t required_storage) { | |
assert(vector != NULL && *vector != NULL); | |
const size_t available_storage = (*vector)->capacity - (*vector)->length; | |
return required_storage <= available_storage; | |
} | |
static Buffer* vector_get_buffer_at_index(Vector** vector, size_t index) { | |
assert(vector != NULL && *vector != NULL); | |
return &(*vector)->buffer[index]; | |
} | |
static void vector_increase_length(Vector** vector) { | |
(*vector)->length += 1; | |
} | |
static void vector_decrease_length(Vector** vector) { | |
if ((*vector)->length > 0) | |
(*vector)->length -= 1; | |
} | |
int vector_init(Vector** vector, object_copy copy_func, object_free free_func) { | |
assert(vector != NULL); | |
Vector* new_vector = NULL; | |
new_vector = vector_malloc(DEFAULT_CAPACITY); | |
if (new_vector == NULL) | |
exit(EXIT_FAILURE); | |
if (copy_func != NULL) | |
new_vector->copy = copy_func; | |
if (free_func != NULL) | |
new_vector->free = free_func; | |
*vector = new_vector; | |
return 0; | |
} | |
int vector_init_with_capacity(Vector** vector, size_t capacity, object_copy copy_func, object_free free_func) { | |
assert(vector != NULL && capacity > 0); | |
Vector* new_vector = NULL; | |
new_vector = vector_malloc(capacity); | |
if (new_vector == NULL) | |
exit(EXIT_FAILURE); | |
if (copy_func != NULL) | |
new_vector->copy = copy_func; | |
if (free_func != NULL) | |
new_vector->free = free_func; | |
*vector = new_vector; | |
return 0; | |
} | |
void vector_free(Vector** vector) { | |
if (vector == NULL || *vector == NULL) | |
return; | |
object_free free_func = (*vector)->free; | |
Buffer* buffer = (*vector)->buffer; | |
if (free_func != NULL && buffer != NULL) { | |
for (size_t i = 0; i < (*vector)->length; ++i) { | |
free_func(&buffer[i].object); | |
} | |
} | |
free((*vector)->buffer); | |
free(*vector); | |
*vector = NULL; | |
} | |
void vector_for_each(Vector** vector, void (* consumer_func)(const void*)) { | |
assert(vector != NULL && *vector != NULL && consumer_func != NULL); | |
for (size_t i = 0; i < (*vector)->length; ++i) | |
consumer_func((*vector)->buffer[i].object); | |
} | |
size_t vector_capacity(Vector** vector) { | |
return (*vector)->capacity; | |
} | |
size_t vector_length(Vector** vector) { | |
return (*vector)->length; | |
} | |
void* vector_get_at_index(Vector** vector, size_t index) { | |
assert(vector != NULL && *vector != NULL); | |
if (index > (*vector)->length) { | |
fprintf(stderr, "[ERROR] -- [%s]: index (%ld) out of bounds\n", __func__, index); | |
vector_free(vector); | |
exit(EXIT_FAILURE); | |
} | |
return vector_get_buffer_at_index(vector, index)->object; | |
} | |
int vector_push_back(Vector** vector, const void* object) { | |
assert(vector != NULL && *vector != NULL && object != NULL); | |
if (!vector_has_storage_available(vector, 1)) { | |
vector_buffer_resize(vector); | |
} | |
object_copy copy_func = (*vector)->copy; | |
if (copy_func == NULL) | |
return -1; | |
size_t end = (*vector)->length; | |
Buffer* buffer = vector_get_buffer_at_index(vector, end); | |
buffer->object = copy_func(object); | |
vector_increase_length(vector); | |
return 0; | |
} | |
int vector_push_at_index(Vector** vector, const void* object, size_t index) { | |
assert(vector != NULL && *vector != NULL && object != NULL); | |
if (index > (*vector)->length) { | |
fprintf(stderr, "[ERROR] -- [%s]: index (%ld) out of bounds\n", __func__, index); | |
vector_free(vector); | |
exit(EXIT_FAILURE); | |
} | |
if (vector_length(vector) == 0 && index == 0) | |
return vector_push_back(vector, object); | |
if (!vector_has_storage_available(vector, 1)) { | |
vector_buffer_resize(vector); | |
} | |
object_copy copy_func = (*vector)->copy; | |
if (copy_func == NULL) | |
return -1; | |
size_t end = (*vector)->length; | |
for (size_t i = end; i > index; --i) { | |
Buffer* next = vector_get_buffer_at_index(vector, i); | |
Buffer* prev = vector_get_buffer_at_index(vector, i - 1); | |
next->object = prev->object; | |
} | |
Buffer* buffer = vector_get_buffer_at_index(vector, index); | |
buffer->object = copy_func(object); | |
vector_increase_length(vector); | |
return 0; | |
} | |
int vector_emplace_back(Vector** vector, void* object) { | |
assert(vector != NULL && *vector != NULL && object != NULL); | |
if (!vector_has_storage_available(vector, 1)) { | |
vector_buffer_resize(vector); | |
} | |
size_t end = (*vector)->length; | |
Buffer* buffer = vector_get_buffer_at_index(vector, end); | |
buffer->object = object; | |
vector_increase_length(vector); | |
return 0; | |
} | |
int vector_emplace_at_index(Vector** vector, void* object, size_t index) { | |
assert(vector != NULL && *vector != NULL && object != NULL); | |
if (index > (*vector)->length) { | |
fprintf(stderr, "[ERROR] -- [%s]: index (%ld) out of bounds\n", __func__, index); | |
vector_free(vector); | |
exit(EXIT_FAILURE); | |
} | |
if (vector_length(vector) == 0 && index == 0) | |
return vector_emplace_back(vector, object); | |
if (!vector_has_storage_available(vector, 1)) { | |
vector_buffer_resize(vector); | |
} | |
size_t end = (*vector)->length; | |
for (size_t i = end; i > index; --i) { | |
Buffer* next = vector_get_buffer_at_index(vector, i); | |
Buffer* prev = vector_get_buffer_at_index(vector, i - 1); | |
next->object = prev->object; | |
} | |
Buffer* buffer = vector_get_buffer_at_index(vector, index); | |
buffer->object = object; | |
vector_increase_length(vector); | |
return 0; | |
} | |
int vector_remove_back(Vector** vector, void** ret_buffer) { | |
assert(vector != NULL && *vector != NULL); | |
Buffer* end = vector_get_buffer_at_index(vector, (*vector)->length - 1); | |
if (ret_buffer != NULL) { | |
*ret_buffer = end->object; | |
end->object = NULL; | |
} else if ((*vector)->free != NULL) { | |
(*vector)->free(&end->object); | |
} | |
vector_decrease_length(vector); | |
return 0; | |
} | |
int vector_remove_at_index(Vector** vector, size_t index, void** ret_buffer) { | |
assert(vector != NULL && *vector != NULL); | |
if (index > (*vector)->length) { | |
fprintf(stderr, "[ERROR] -- [%s]: index (%ld) out of bounds\n", __func__, index); | |
vector_free(vector); | |
exit(EXIT_FAILURE); | |
} | |
if (vector_length(vector) == 0) | |
return -1; | |
if (index == (*vector)->length - 1) | |
return vector_remove_back(vector, ret_buffer); | |
Buffer* buff = vector_get_buffer_at_index(vector, index); | |
if (ret_buffer != NULL) { | |
*ret_buffer = buff->object; | |
buff->object = NULL; | |
} else if ((*vector)->free != NULL) { | |
(*vector)->free(&buff->object); | |
} | |
for (size_t i = index; i < (*vector)->length; ++i) { | |
Buffer* prev = vector_get_buffer_at_index(vector, i); | |
Buffer* next = vector_get_buffer_at_index(vector, i + 1); | |
prev->object = next->object; | |
} | |
Buffer* end = vector_get_buffer_at_index(vector, (*vector)->length - 1); | |
end->object = NULL; | |
vector_decrease_length(vector); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef VECTOR_H_ | |
#define VECTOR_H_ | |
#include <stdlib.h> | |
#define DEFAULT_CAPACITY 8 | |
typedef struct Buffer Buffer; | |
struct Buffer { | |
void* object; | |
}; | |
typedef void* (* object_copy)(const void*); | |
typedef void (* object_free)(void**); | |
typedef struct Vector Vector; | |
struct Vector { | |
Buffer* buffer; | |
size_t length; | |
size_t capacity; | |
object_copy copy; | |
object_free free; | |
}; | |
int vector_init(Vector** vector, object_copy copy_func, object_free free_func); | |
int vector_init_with_capacity(Vector** vector, size_t capacity, object_copy copy_func, object_free free_func); | |
void vector_free(Vector** vector); | |
void vector_for_each(Vector** vector, void (* consumer_func)(const void*)); | |
size_t vector_capacity(Vector** vector); | |
size_t vector_length(Vector** vector); | |
void* vector_get_at_index(Vector** vector, size_t index); | |
int vector_push_back(Vector** vector, const void* object); | |
int vector_push_at_index(Vector** vector, const void* object, size_t index); | |
int vector_emplace_back(Vector** vector, void* object); | |
int vector_emplace_at_index(Vector** vector, void* object, size_t index); | |
int vector_remove_back(Vector** vector, void** ret_buffer); | |
int vector_remove_at_index(Vector** vector, size_t index, void** ret_buffer); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "vector.h" | |
#include <assert.h> | |
#include <stdio.h> | |
#include <string.h> | |
typedef struct User User; | |
struct User { | |
int id; | |
char* username; | |
char* password; | |
char* email; | |
}; | |
User user_create(int id, char* username, char* password, char* email); | |
User* user_new(int id, const char* username, const char* password, const char* email); | |
User* user_copy(const User* other); | |
void user_free(User** user); | |
void show_user(const User* user); | |
int main(void) { | |
Vector* users = NULL; | |
object_copy copy_func = (object_copy) user_copy; | |
object_free free_func = (object_free) user_free; | |
vector_init_with_capacity(&users, 2, copy_func, free_func); | |
assert(users != NULL); | |
assert(users->capacity != DEFAULT_CAPACITY); | |
assert(users->capacity == 2); | |
assert(users->length == 0); | |
assert(users->copy != NULL); | |
assert(users->free != NULL); | |
User john = user_create(1, "john", "12345", "john@email.com"); | |
User carl = user_create(2, "carl", "12345", "carl@email.com"); | |
User alex = user_create(3, "alex", "12345", "alex@email.com"); | |
vector_push_back(&users, &john); | |
vector_push_back(&users, &carl); | |
vector_push_at_index(&users, &alex, 1); | |
vector_emplace_back(&users, user_new(4, "anne", "12345", "anne@email.com")); | |
vector_emplace_at_index(&users, user_new(5, "mary", "12345", "mary@email.com"), 2); | |
assert(vector_length(&users) == 5); | |
void (* log)(const void*) = (void (*)(const void*)) show_user; | |
vector_for_each(&users, log); | |
User* mary = NULL; | |
vector_remove_at_index(&users, 2, (void**) &mary); | |
assert(vector_length(&users) == 4); | |
show_user(mary); | |
user_free(&mary); | |
vector_free(&users); | |
assert(users == NULL); | |
return 0; | |
} | |
User user_create(int id, char* username, char* password, char* email) { | |
return (User) { | |
.id = id, | |
.username = username, | |
.password = password, | |
.email = email, | |
}; | |
} | |
static char* str_dup(const char* other) { | |
char* copy = NULL; | |
size_t len = strlen(other); | |
copy = malloc(len + 1); | |
memcpy(copy, other, len); | |
copy[len] = '\0'; | |
return copy; | |
} | |
User* user_new(int id, const char* username, const char* password, const char* email) { | |
User* user = NULL; | |
user = malloc(sizeof(User)); | |
user->id = id; | |
#if defined(_GNU_SORCE) | |
user->username = strdup(username); | |
user->password = strdup(password); | |
user->email = strdup(email); | |
#else | |
user->username = str_dup(username); | |
user->password = str_dup(password); | |
user->email = str_dup(email); | |
#endif | |
return user; | |
} | |
User* user_copy(const User* other) { | |
assert(other != NULL); | |
return user_new(other->id, other->username, other->password, other->email); | |
} | |
void user_free(User** user) { | |
if (user == NULL || *user == NULL) | |
return; | |
free((*user)->username); | |
free((*user)->password); | |
free((*user)->email); | |
free((*user)); | |
*user = NULL; | |
} | |
void show_user(const User* user) { | |
if (user == NULL) | |
return; | |
printf("id: %d, username: %s, password: %s, email: %s\n", | |
user->id, user->username, user->password, user->email); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment