From 0ae03260671d8ca89d3e99853ce848d57cd122d6 Mon Sep 17 00:00:00 2001 From: Warwick Date: Wed, 18 Dec 2024 15:04:26 +0000 Subject: [PATCH] Fixed memory leak in dynamic array. --- src/dyn_arr.c | 45 +++++++++++++++++---------------------------- src/dyn_arr.h | 16 +++++++++------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/dyn_arr.c b/src/dyn_arr.c index 53aa893..0dfbe82 100644 --- a/src/dyn_arr.c +++ b/src/dyn_arr.c @@ -1,10 +1,12 @@ // Special thanks to https://bytesbeneath.com/p/dynamic-arrays-in-c #include "dyn_arr.h" +#include #include #include #include #define ARRAY_GROWTH_MULTIPLIER 1.3 +#define ARRAY_SHRINK_TRIGGER 2 void *dyn_arr_init(size_t item_size, size_t capacity) { void *dyna_ptr = NULL; @@ -12,6 +14,7 @@ void *dyn_arr_init(size_t item_size, size_t capacity) { dyna_header *header = malloc(size); if (header) { + header->item_size = item_size; header->capacity = capacity; header->length = 0; dyna_ptr = header + 1; @@ -20,17 +23,25 @@ void *dyn_arr_init(size_t item_size, size_t capacity) { return dyna_ptr; } -void *dyna_ensure_capacity(void *array, size_t item_count, size_t item_size) { +void *dyna_ensure_capacity(void *array, int64_t item_count) { + size_t item_size = dyna_item_size(array); dyna_header *header = dyna_get_header(array); size_t minimum_capacity = header->length + item_count; + size_t maximum_capacity = + (header->length + item_count) * ARRAY_SHRINK_TRIGGER; - if (header->capacity > minimum_capacity) { + // Return if capacity is in acceptable range. + if (header->capacity > minimum_capacity && + header->capacity < maximum_capacity) { return header + 1; } - size_t new_capacity = header->capacity * ARRAY_GROWTH_MULTIPLIER; - while (new_capacity < minimum_capacity) { - new_capacity *= ARRAY_GROWTH_MULTIPLIER; + size_t new_capacity = minimum_capacity * ARRAY_GROWTH_MULTIPLIER; + + // Return if the array is valid and so small it's not worth reallocating + if (header->capacity > minimum_capacity && + new_capacity <= ARRAY_INITIAL_CAPACITY) { + return header + 1; } size_t new_size = sizeof(dyna_header) + new_capacity * item_size; @@ -39,31 +50,9 @@ void *dyna_ensure_capacity(void *array, size_t item_count, size_t item_size) { return header + 1; } -void dyn_arr_pop(void *array, size_t item_size) { - if (dyna_empty(array)) { - return; - } - - dyna_length(array)--; - - // Shrink if smaller than growth factor, may break if growth factor is > 2 - if (dyna_length(array) > - (2 - ARRAY_GROWTH_MULTIPLIER) * dyna_capacity(array)) { - return; - } - - size_t new_capacity = dyna_length(array) * ARRAY_GROWTH_MULTIPLIER; - dyna_capacity(array) = new_capacity; - - size_t new_size = sizeof(dyna_header) + new_capacity * item_size; - dyna_header *header = dyna_get_header(array); - header = realloc(dyna_get_header(array), new_size); -} - void dyna_deinit(void *array) { - dyna_header *header = dyna_get_header(array); - header = NULL; free(dyna_get_header(array)); + array = NULL; } bool dyna_empty(void *array) { diff --git a/src/dyn_arr.h b/src/dyn_arr.h index 2927251..414572b 100644 --- a/src/dyn_arr.h +++ b/src/dyn_arr.h @@ -3,7 +3,7 @@ #include #include -#define ARRAY_INITIAL_CAPACITY 4 +#define ARRAY_INITIAL_CAPACITY 10 /* TODO: * Functions to implement to match what I want: @@ -13,7 +13,6 @@ * - clear aka erase * - insert * - (optional) insert range - * - pop * - (optional) swap * - (optional) resize * - Sanity checks @@ -22,6 +21,7 @@ */ typedef struct dyna_header { + size_t item_size; size_t capacity; size_t length; } dyna_header; @@ -32,19 +32,21 @@ void *dyn_arr_init(size_t item_size, size_t capacity); // Modification #define dyna_append(array, value) \ - ((array) = dyna_ensure_capacity(array, 1, sizeof(value)), \ + ((array) = dyna_ensure_capacity(array, 1), \ (array)[dyna_get_header(array)->length] = (value), \ &(array)[dyna_get_header(array)->length++]) -void *dyna_ensure_capacity(void *array, size_t item_count, size_t item_size); +void *dyna_ensure_capacity(void *array, int64_t item_count); -#define dyna_pop(array) dyn_arr_pop(array, sizeof(typeof(*array))) -void dyn_arr_pop(void *array, size_t item_size); +#define dyna_pop(array) \ + ((array) = dyna_ensure_capacity(array, -1), \ + &(array)[dyna_get_header(array)->length--]) void dyna_deinit(void *array); // Get meta data -#define dyna_get_header(array) ((dyna_header *)(array)-1) +#define dyna_get_header(array) ((dyna_header *)(array) - 1) +#define dyna_item_size(array) (dyna_get_header(array)->item_size) #define dyna_length(array) (dyna_get_header(array)->length) #define dyna_capacity(array) (dyna_get_header(array)->capacity) bool dyna_empty(void *array);