addition/refactor: Made ADT design and added grow/shrink

So, added private functions made to grow and shrink the array in a
multiple of 2, 2 as a factro is fine, at least that is Rust does it that
way. Also changed the design to ADT, forgot i liked that, probably will
be changing that to apply also to my Arena implementation, i will see if
fits --probably--.
This commit is contained in:
2026-04-14 20:30:02 -06:00
parent cb78e9467b
commit 4ea062fd60
2 changed files with 65 additions and 44 deletions

View File

@@ -5,15 +5,10 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
typedef struct { typedef struct ArrayList ArrayList;
void *data;
size_t capacity;
size_t len;
size_t elem_size;
} ArrayList;
typedef struct { typedef struct {
ArrayList array; ArrayList *array;
size_t offset; size_t offset;
} ArrayListSlice; } ArrayListSlice;
@@ -27,21 +22,13 @@ typedef enum {
ARRLIST_INVALID_ELEM_SIZE, ARRLIST_INVALID_ELEM_SIZE,
} ArrayListErr; } ArrayListErr;
typedef struct { ArrayList *arraylist_init(size_t capacity, size_t elem_size);
bool is_valid;
union {
ArrayListErr err;
ArrayList array;
};
} ArrayListResult;
ArrayListResult arraylist_init(size_t capacity, size_t elem_size);
ArrayListErr arraylist_destroy(ArrayList *arr); ArrayListErr arraylist_destroy(ArrayList *arr);
ArrayListErr arraylist_clear(ArrayList *arr); ArrayListErr arraylist_clear(ArrayList *arr);
size_t arraylist_size(ArrayList *arr); size_t arraylist_size(const ArrayList *arr);
size_t arraylist_capacity(ArrayList *arr); size_t arraylist_capacity(const ArrayList *arr);
bool arraylist_is_empty(ArrayList *arr); bool arraylist_is_empty(const ArrayList *arr);
ArrayListErr arraylist_push_back(ArrayList *arr, void *data); ArrayListErr arraylist_push_back(ArrayList *arr, void *data);
ArrayListErr arraylist_insert(ArrayList*arr, size_t index, void *data); ArrayListErr arraylist_insert(ArrayList*arr, size_t index, void *data);
@@ -52,7 +39,7 @@ ArrayListErr arraylist_pop_back(ArrayList *arr, void *out);
ArrayListErr arraylist_remove_at(ArrayList *arr, size_t index, void *out); ArrayListErr arraylist_remove_at(ArrayList *arr, size_t index, void *out);
ArrayListErr arraylist_pop_front(ArrayList *arr, void *out); ArrayListErr arraylist_pop_front(ArrayList *arr, void *out);
ArrayListErr arraylist_get(ArrayList *arr, size_t index, void *out); ArrayListErr arraylist_get(const ArrayList *arr, size_t index, void *out);
ArrayListErr arraylist_set(ArrayList *arr, size_t index, void *data); ArrayListErr arraylist_set(ArrayList *arr, size_t index, void *data);
ArrayListErr arraylist_resize(ArrayList *arr, size_t new_capacity); ArrayListErr arraylist_resize(ArrayList *arr, size_t new_capacity);

View File

@@ -1,37 +1,45 @@
#include "arraylist.h" #include "arraylist.h"
#include <stdatomic.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ArrayListResult arraylist_init(size_t capacity, size_t elem_size) { struct ArrayList{
void *data;
size_t capacity;
size_t len;
size_t elem_size;
};
// Grow and shrink factor is 2, 1.5 might give different results i guess
// but i'm basing myself in that Rust implementation of array does use
// 2 as the factor so i guess is good :)
static ArrayListErr arraylist_grow(ArrayList *arr);
static ArrayListErr arraylist_shrink(ArrayList *arr);
ArrayList *arraylist_init(size_t capacity, size_t elem_size) {
if (capacity == 0) { if (capacity == 0) {
return (ArrayListResult) { return NULL;
.is_valid = false,
.err = ARRLIST_INVALID_CAPACITY};
} }
if (elem_size == 0) { if (elem_size == 0) {
return (ArrayListResult) { return NULL;
.is_valid = false,
.err = ARRLIST_INVALID_ELEM_SIZE,
};
} }
ArrayList arr = { ArrayList *arr = malloc(sizeof(ArrayList));
.data = malloc(capacity * elem_size), if (arr == NULL) {
.capacity = capacity, return NULL;
.elem_size = elem_size, }
.len = 0 arr->capacity = capacity;
}; arr->elem_size = elem_size;
arr->len = 0;
if (arr.data == NULL) { arr->data = malloc(capacity * elem_size);
return (ArrayListResult) { if (arr->data == NULL) {
.is_valid = false, free(arr);
.err = ARRLIST_BAD_ALLOC, return NULL;
};
} }
return (ArrayListResult) {.is_valid = true, .array = arr}; return arr;
} }
ArrayListErr arraylist_destroy(ArrayList *arr) { ArrayListErr arraylist_destroy(ArrayList *arr) {
@@ -44,6 +52,7 @@ ArrayListErr arraylist_destroy(ArrayList *arr) {
arr->len = 0; arr->len = 0;
free(arr->data); free(arr->data);
arr->data = NULL; arr->data = NULL;
free(arr);
return ARRLIST_OK; return ARRLIST_OK;
} }
@@ -59,23 +68,48 @@ ArrayListErr arraylist_clear(ArrayList *arr) {
return ARRLIST_OK; return ARRLIST_OK;
} }
size_t arraylist_size(ArrayList *arr) { size_t arraylist_size(const ArrayList *arr) {
if (arr == NULL) { if (arr == NULL) {
return 0; return 0;
} }
return arr->len; return arr->len;
} }
size_t arraylist_capacity(ArrayList *arr) { size_t arraylist_capacity(const ArrayList *arr) {
if (arr == NULL) { if (arr == NULL) {
return 0; return 0;
} }
return arr->capacity; return arr->capacity;
} }
bool arraylist_is_empty(ArrayList *arr) { bool arraylist_is_empty(const ArrayList *arr) {
if (arr == NULL) { if (arr == NULL) {
return true; return true;
} }
return arr->capacity == 0; return arr->capacity == 0;
} }
static ArrayListErr arraylist_grow(ArrayList *arr) {
// We can asume is not null because is internal
// and only used by funtions that already verified
// arr is not null, same with shrink.
size_t new_capacity = arr->capacity * 2;
void *tmp = realloc(arr->data, new_capacity * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->data = tmp;
return ARRLIST_OK;
}
static ArrayListErr arraylist_shrink(ArrayList *arr) {
size_t new_capacity = arr->capacity / 2;
void *tmp = realloc(arr->data, new_capacity *arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->data = tmp;
return ARRLIST_OK;
}