add resizeing functions

This commit is contained in:
2025-02-14 16:54:17 +01:00
parent 3d36b26fd9
commit 49bc822597

View File

@@ -2,11 +2,15 @@
#define DYNARR_H #define DYNARR_H
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#define DYNARR_COMB2(a, b) a##b #define DYNARR_COMB2(a, b) a##b
#define DYNARR_COMB1(a, b) DYNARR_COMB2(a, b) #define DYNARR_COMB1(a, b) DYNARR_COMB2(a, b)
#endif // DYNARR_H #endif // DYNARR_H
#define DYNARR_TYPE float
#ifdef DYNARR_TYPE #ifdef DYNARR_TYPE
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
// customising the linkage // customising the linkage
@@ -19,14 +23,9 @@
#define DYNARR_NAME DYNARR_COMB1(dynarr_, DYNARR_TYPE) #define DYNARR_NAME DYNARR_COMB1(dynarr_, DYNARR_TYPE)
#endif // DYNARR_NAME #endif // DYNARR_NAME
#define DYNARR_init DYNARR_COMB1(DYNARR_NAME, _init) // name of the initialization funcition #define DYNARR_FUNC(name) DYNARR_COMB1(DYNARR_NAME, _##name) // 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
// TODO: add shrink function (call when count < cap / 4) // TODO: add shrink function (call when count < cap / 4)
// TODO: add resize function
// TODO: add bulk addition function // TODO: add bulk addition function
// TODO: add bulk addition function (doesn't respec growth factor)
// TODO: add bulk deletion function // TODO: add bulk deletion function
@@ -37,31 +36,50 @@ typedef struct {
size_t cap; // contains the capacity of the dynamic array size_t cap; // contains the capacity of the dynamic array
} DYNARR_NAME; } DYNARR_NAME;
// initializes the dynamic array with a specific capacity (dat may be null if malloc fails) // adds an exact number of items to the capacity, does not respect scaling
DYNARR_LINKAGE DYNARR_NAME DYNARR_init(const size_t cap) { // returns 0 upon success, 1 upon failure
return (DYNARR_NAME){ DYNARR_LINKAGE uint8_t DYNARR_FUNC(resize_exact)(DYNARR_NAME* arr, size_t ncap) {
malloc(cap * sizeof(DYNARR_TYPE)), if (ncap < arr->count) return 1; // the new capacity is smaller than the count, this is very likely unintentional
0, if (ncap == arr->cap) return 0; // the capacity is already the new capacity; no work needs to be done
cap,
}; // (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 // adds an item to the dynamic array, doubles the capacity if the new count exceeds the maximum
// returns 0 upon success, 1 upon failure // 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; size_t idx = arr->count;
arr->count++; arr->count++;
// resize the dynamic array if the new count has hit the max capacity // resize the dynamic array if the new count has hit the max capacity
if (arr->cap == arr->count) { if (arr->cap == arr->count) {
if (!arr->cap) arr->cap = 1; // set the capacity to 1 if it's 0 uint8_t const s = !arr->cap // if zero
else arr->cap *= 2; // otherwise, multiply the capacity by 2 ? DYNARR_FUNC(resize_exact)(arr, 1) // set the capacity to 1 if it's 0
DYNARR_TYPE* nptr = realloc(arr->dat, arr->cap * sizeof(DYNARR_TYPE)); : DYNARR_FUNC(resize_exact)(arr, arr->cap * 2); // otherwise, multiply the capacity by 2
// return 1 upon non-zero
if (nptr == NULL) if (s) return 1;
return 1;
arr->dat = nptr;
} }
arr->dat[idx] = item; 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 // removes an item from the dynamic array from a certain index
// returns 0 upon success, 1 upon failure // 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; if (arr->count == 0 || idx >= arr->count) return 1;
// remove one from the count // remove one from the count
@@ -85,17 +103,21 @@ DYNARR_LINKAGE uint8_t DYNARR_remove(DYNARR_NAME* arr, size_t idx) {
return 0; 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 // 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); 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 // clean up all defined definitions so they can be used again later
#undef DYNARR_init #undef DYNARR_FUNC
#undef DYNARR_add
#undef DYNARR_remove
#undef DYNARR_free
#undef DYNARR_NAME #undef DYNARR_NAME
#undef DYNARR_LINKAGE #undef DYNARR_LINKAGE
#undef DYNARR_TYPE #undef DYNARR_TYPE