Skip to content

Instantly share code, notes, and snippets.

@matheusmv
Last active January 15, 2023 12:37
Show Gist options
  • Save matheusmv/270d5ebfaa2ae63d769a04911ab68a4d to your computer and use it in GitHub Desktop.
Save matheusmv/270d5ebfaa2ae63d769a04911ab68a4d to your computer and use it in GitHub Desktop.
queue with dynamic array in c
#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);
}
#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
#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);
}
#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;
}
#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
#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