Files
ArrayList/src/arraylist.c

389 lines
8.1 KiB
C
Raw Normal View History

#include "arraylist.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
2026-04-14 19:33:15 -06:00
#include <string.h>
struct ArrayList{
uint8_t *buffer;
size_t capacity;
size_t len;
size_t elem_size;
2026-04-19 21:57:28 -06:00
size_t borrows;
};
2026-04-19 21:57:28 -06:00
struct ArraySlice {
ArrayList *arr;
size_t start;
size_t end;
size_t current;
bool is_safe;
};
// 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) {
return NULL;
}
if (elem_size == 0) {
return NULL;
}
if (capacity > SIZE_MAX / elem_size) {
return NULL;
}
ArrayList *arr = malloc(sizeof(ArrayList));
if (arr == NULL) {
return NULL;
}
arr->capacity = capacity;
arr->elem_size = elem_size;
arr->len = 0;
arr->buffer = malloc(capacity * elem_size);
if (arr->buffer == NULL) {
free(arr);
return NULL;
}
return arr;
}
2026-04-14 19:33:15 -06:00
ArrayListErr arraylist_destroy(ArrayList **arr) {
if (arr == NULL || *arr == NULL) {
2026-04-14 19:33:15 -06:00
return ARRLIST_NULL_ARG;
}
// No problem on using free on NULL :)
free((*arr)->buffer);
free(*arr);
*arr = NULL;
2026-04-14 19:33:15 -06:00
return ARRLIST_OK;
}
ArrayListErr arraylist_clear(ArrayList *arr) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
arr->len = 0;
return ARRLIST_OK;
}
2026-04-14 19:38:56 -06:00
size_t arraylist_size(const ArrayList *arr) {
2026-04-14 19:38:56 -06:00
if (arr == NULL) {
return 0;
}
return arr->len;
}
size_t arraylist_capacity(const ArrayList *arr) {
2026-04-14 19:38:56 -06:00
if (arr == NULL) {
return 0;
}
return arr->capacity;
}
bool arraylist_is_empty(const ArrayList *arr) {
2026-04-14 19:38:56 -06:00
if (arr == NULL) {
return true;
}
return arr->len == 0;
2026-04-14 19:38:56 -06:00
}
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;
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
void *tmp = realloc(arr->buffer, new_capacity * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->buffer = tmp;
return ARRLIST_OK;
}
static ArrayListErr arraylist_shrink(ArrayList *arr) {
size_t new_capacity = arr->capacity / 2;
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
void *tmp = realloc(arr->buffer, new_capacity *arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->capacity = new_capacity;
arr->buffer = tmp;
return ARRLIST_OK;
}
ArrayListErr arraylist_push_back(ArrayList *arr, void *data) {
if (arr == NULL || data == NULL) {
return ARRLIST_NULL_ARG;
}
if (arr->len >= arr->capacity) {
ArrayListErr err = arraylist_grow(arr);
if (err != ARRLIST_OK) {
return err;
}
}
memcpy(arr->buffer + (arr->len * arr->elem_size), data, arr->elem_size);
arr->len++;
return ARRLIST_OK;
}
ArrayListErr arraylist_push_front(ArrayList *arr, void *data) {
if (arr == NULL || data == NULL) {
return ARRLIST_NULL_ARG;
}
if (arr->len >= arr->capacity) {
ArrayListErr err = arraylist_grow(arr);
if (err != ARRLIST_OK) {
return err;
}
}
// No problem if array is full because it grows if it's full
memmove(
arr->buffer + arr->elem_size,
2026-04-16 20:56:48 -06:00
arr->buffer,
(arr->len) * arr->elem_size
);
memcpy(
arr->buffer,
data,
arr->elem_size);
arr->len++;
return ARRLIST_OK;
}
ArrayListErr arraylist_insert(ArrayList *arr, size_t index, void *data) {
if (arr == NULL || data == NULL) {
return ARRLIST_NULL_ARG;
}
if (index > arr->len) {
return ARRLIST_OUT_OF_BOUNDS;
}
if (arr->len >= arr->capacity) {
ArrayListErr err = arraylist_grow(arr);
if (err != ARRLIST_OK) {
return err;
}
}
memmove(
arr->buffer + ((index + 1) * arr->elem_size),
arr->buffer + (index * arr->elem_size),
(arr->len - index) * arr->elem_size);
memcpy(arr->buffer + (index * arr->elem_size),
data,
arr->elem_size);
arr->len++;
return ARRLIST_OK;
}
ArrayListErr arraylist_pop_back(ArrayList *arr, void *out) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (arr->len < 1) {
return ARRLIST_EMPTY;
}
if (arr->capacity / 4 > arr->len) {
ArrayListErr err = arraylist_shrink(arr);
if (err != ARRLIST_OK) {
return err;
}
}
if (out != NULL) {
memcpy(
out,
arr->buffer + (arr->len - 1) * arr->elem_size,
arr->elem_size);
}
arr->len--;
return ARRLIST_OK;
}
ArrayListErr arraylist_pop_front(ArrayList *arr, void *out) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (arr->len < 1) {
return ARRLIST_EMPTY;
}
if (arr->capacity / 4 > arr->len) {
ArrayListErr err = arraylist_shrink(arr);
if (err != ARRLIST_OK) {
return err;
}
}
if (out != NULL) {
memcpy(
out,
arr->buffer,
arr->elem_size
);
}
memmove(
arr->buffer,
2026-04-17 07:47:02 -06:00
arr->buffer + arr->elem_size,
2026-04-17 08:21:26 -06:00
(arr->len - 1) * arr->elem_size);
arr->len--;
return ARRLIST_OK;
}
ArrayListErr arraylist_remove_at(ArrayList *arr, size_t index, void *out) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (index >= arr->len) {
return ARRLIST_OUT_OF_BOUNDS;
}
if (arr->len < 1) {
2026-04-18 20:34:42 -06:00
return ARRLIST_EMPTY;
}
if (out != NULL) {
memcpy(
out,
arr->buffer + (index * arr->elem_size),
arr->elem_size
);
}
2026-04-17 08:21:26 -06:00
memmove(
arr->buffer + (index * arr->elem_size),
arr->buffer + ((index + 1) * arr->elem_size),
(arr->len - index) * arr->elem_size);
arr->len--;
return ARRLIST_OK;
}
2026-04-15 07:38:04 -06:00
ArrayListErr arraylist_get(const ArrayList *arr, size_t index, void *out) {
if (arr == NULL || out == NULL) {
return ARRLIST_NULL_ARG;
}
if (index >= arr->capacity) {
return ARRLIST_OUT_OF_BOUNDS;
}
2026-04-15 07:38:04 -06:00
memcpy(
out,
arr->buffer + (index * arr->elem_size),
arr->elem_size);
return ARRLIST_OK;
}
ArrayListErr arraylist_set(ArrayList *arr, size_t index, void *data) {
if (arr == NULL || data == NULL) {
return ARRLIST_NULL_ARG;
}
if (index >= arr->capacity) {
return ARRLIST_OUT_OF_BOUNDS;
}
memcpy(
arr->buffer + (index * arr->elem_size),
data,
arr->elem_size);
return ARRLIST_OK;
}
ArrayListErr arraylist_resize(ArrayList *arr, size_t new_capacity) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
if (new_capacity < 1) {
return ARRLIST_INVALID_CAPACITY;
}
if (new_capacity > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
uint8_t *tmp = realloc(arr->buffer, new_capacity * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->buffer = tmp;
arr->capacity = new_capacity;
return ARRLIST_OK;
}
ArrayListErr arraylist_reserve(ArrayList *arr, size_t size_to_reserve) {
if (arr == NULL) {
return ARRLIST_NULL_ARG;
}
2026-04-18 20:34:42 -06:00
if (arr->capacity + size_to_reserve > SIZE_MAX / arr->elem_size ||
size_to_reserve > SIZE_MAX / arr->elem_size) {
return ARRLIST_ALLOC_OVERFLOW;
}
uint8_t *tmp = realloc(
arr->buffer,
(arr->capacity + size_to_reserve) * arr->elem_size);
if (tmp == NULL) {
return ARRLIST_BAD_ALLOC;
}
arr->buffer = tmp;
arr->capacity += size_to_reserve;
return ARRLIST_OK;
}