#include "arraylist.h" #include #include #include #include struct ArrayList{ uint8_t *buffer; 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) { return NULL; } if (elem_size == 0) { 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; } ArrayListErr arraylist_destroy(ArrayList *arr) { if (arr == NULL) { return ARRLIST_NULL_ARG; } arr->capacity = 0; arr->elem_size = 0; arr->len = 0; free(arr->buffer); arr->buffer = NULL; free(arr); return ARRLIST_OK; } ArrayListErr arraylist_clear(ArrayList *arr) { if (arr == NULL) { return ARRLIST_NULL_ARG; } memset(arr->buffer, 0, arr->capacity * arr->elem_size); arr->capacity = 0; arr->elem_size = 0; arr->len = 0; return ARRLIST_OK; } size_t arraylist_size(const ArrayList *arr) { if (arr == NULL) { return 0; } return arr->len; } size_t arraylist_capacity(const ArrayList *arr) { if (arr == NULL) { return 0; } return arr->capacity; } bool arraylist_is_empty(const ArrayList *arr) { if (arr == NULL) { return true; } 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->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; 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, 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 for (size_t i = arr->len - 1; i >= 0; i--) { memcpy( arr->buffer + ((i + 1) * arr->elem_size), arr->buffer + (i * arr->elem_size), 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; } } for (size_t i = arr->len - 1; i >= index; i--) { memcpy( arr->buffer + ((i + 1) * arr->elem_size), arr->buffer + (i * arr->elem_size), arr->elem_size); } memcpy(arr->buffer + (index * arr->elem_size), data, arr->elem_size); arr->len++; return ARRLIST_OK; }