diff --git a/src/util/gen/dynarr.h b/src/util/gen/dynarr.h index de7e076..dcd568e 100644 --- a/src/util/gen/dynarr.h +++ b/src/util/gen/dynarr.h @@ -2,11 +2,15 @@ #define DYNARR_H #include #include + #define DYNARR_COMB2(a, b) a##b #define DYNARR_COMB1(a, b) DYNARR_COMB2(a, b) #endif // DYNARR_H +#define DYNARR_TYPE float + #ifdef DYNARR_TYPE +#include #include // customising the linkage @@ -19,14 +23,9 @@ #define DYNARR_NAME DYNARR_COMB1(dynarr_, DYNARR_TYPE) #endif // DYNARR_NAME -#define DYNARR_init DYNARR_COMB1(DYNARR_NAME, _init) // name of the initialization funcition -#define DYNARR_add DYNARR_COMB1(DYNARR_NAME, _add) // name of the addition function -#define DYNARR_remove DYNARR_COMB1(DYNARR_NAME, _remove) // name of the removal function -#define DYNARR_free DYNARR_COMB1(DYNARR_NAME, _free) // name of the freeing function +#define DYNARR_FUNC(name) DYNARR_COMB1(DYNARR_NAME, _##name) // name of the initialization funcition // TODO: add shrink function (call when count < cap / 4) -// TODO: add resize function // TODO: add bulk addition function -// TODO: add bulk addition function (doesn't respec growth factor) // TODO: add bulk deletion function @@ -37,31 +36,50 @@ typedef struct { size_t cap; // contains the capacity of the dynamic array } DYNARR_NAME; -// initializes the dynamic array with a specific capacity (dat may be null if malloc fails) -DYNARR_LINKAGE DYNARR_NAME DYNARR_init(const size_t cap) { - return (DYNARR_NAME){ - malloc(cap * sizeof(DYNARR_TYPE)), - 0, - cap, - }; +// adds an exact number of items to the capacity, does not respect scaling +// returns 0 upon success, 1 upon failure +DYNARR_LINKAGE uint8_t DYNARR_FUNC(resize_exact)(DYNARR_NAME* arr, size_t ncap) { + if (ncap < arr->count) return 1; // the new capacity is smaller than the count, this is very likely unintentional + if (ncap == arr->cap) return 0; // the capacity is already the new capacity; no work needs to be done + + // (re)allocate the memory for the array + DYNARR_TYPE* nptr = (arr->dat == NULL) + ? malloc(ncap * sizeof(DYNARR_TYPE)) + : realloc(arr->dat, ncap * sizeof(DYNARR_TYPE)); + + // if memory (re)allocation failed; return + if (nptr == NULL) + return 1; + + arr->dat = nptr; + arr->cap = ncap; + return 0; +} + +// resizes the array by adding `nitems` to the count, respects capacity scaling +// returns 0 upon success, 1 upon failure +DYNARR_LINKAGE uint8_t DYNARR_FUNC(resize)(DYNARR_NAME* arr, size_t ncount) { + if (ncount < arr->count) return 1; // the new count is less than the current count, this is very likely unintentional + if (ncount == arr->cap) return 0; // the current capacity has already been set to this + + // calculates what the new size should be by adding the amount of items to the count + // assumes scaling factor is 2 + return DYNARR_FUNC(resize_exact)(arr, 1 << (size_t)ceil(log2(ncount))); } // adds an item to the dynamic array, doubles the capacity if the new count exceeds the maximum // returns 0 upon success, 1 upon failure -DYNARR_LINKAGE uint8_t DYNARR_add(DYNARR_NAME* arr, DYNARR_TYPE item) { +DYNARR_LINKAGE uint8_t DYNARR_FUNC(add)(DYNARR_NAME* arr, DYNARR_TYPE item) { size_t idx = arr->count; arr->count++; // resize the dynamic array if the new count has hit the max capacity if (arr->cap == arr->count) { - if (!arr->cap) arr->cap = 1; // set the capacity to 1 if it's 0 - else arr->cap *= 2; // otherwise, multiply the capacity by 2 - DYNARR_TYPE* nptr = realloc(arr->dat, arr->cap * sizeof(DYNARR_TYPE)); - - if (nptr == NULL) - return 1; - - arr->dat = nptr; + uint8_t const s = !arr->cap // if zero + ? DYNARR_FUNC(resize_exact)(arr, 1) // set the capacity to 1 if it's 0 + : DYNARR_FUNC(resize_exact)(arr, arr->cap * 2); // otherwise, multiply the capacity by 2 + // return 1 upon non-zero + if (s) return 1; } arr->dat[idx] = item; @@ -70,7 +88,7 @@ DYNARR_LINKAGE uint8_t DYNARR_add(DYNARR_NAME* arr, DYNARR_TYPE item) { // removes an item from the dynamic array from a certain index // returns 0 upon success, 1 upon failure -DYNARR_LINKAGE uint8_t DYNARR_remove(DYNARR_NAME* arr, size_t idx) { +DYNARR_LINKAGE uint8_t DYNARR_FUNC(remove)(DYNARR_NAME* arr, size_t idx) { if (arr->count == 0 || idx >= arr->count) return 1; // remove one from the count @@ -85,17 +103,21 @@ DYNARR_LINKAGE uint8_t DYNARR_remove(DYNARR_NAME* arr, size_t idx) { return 0; } +// trims the parts of the dynamic array that isn't in use +DYNARR_LINKAGE uint8_t DYNARR_FUNC(trim)(DYNARR_NAME* arr) { + if (arr->cap == arr->count) return 0; // return success if no work needs to be done + return DYNARR_FUNC(resize_exact)(arr, arr->count); +} + // cleans up the resources associated with the array, do not use after this step. This is undefined behaviour -DYNARR_LINKAGE void DYNARR_free(DYNARR_NAME* arr) { +DYNARR_LINKAGE void DYNARR_FUNC(free)(DYNARR_NAME* arr) { + if (arr->dat == NULL) return; free(arr->dat); - arr->dat = NULL; + *arr = (DYNARR_NAME){0}; // zero out all fields to re-initialize } // clean up all defined definitions so they can be used again later -#undef DYNARR_init -#undef DYNARR_add -#undef DYNARR_remove -#undef DYNARR_free +#undef DYNARR_FUNC #undef DYNARR_NAME #undef DYNARR_LINKAGE #undef DYNARR_TYPE