Fixed memory leak in dynamic array.
This commit is contained in:
parent
9f50fdbe7f
commit
5379426ead
2 changed files with 30 additions and 35 deletions
|
|
@ -1,10 +1,12 @@
|
||||||
// Special thanks to https://bytesbeneath.com/p/dynamic-arrays-in-c
|
// Special thanks to https://bytesbeneath.com/p/dynamic-arrays-in-c
|
||||||
#include "dyn_arr.h"
|
#include "dyn_arr.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define ARRAY_GROWTH_MULTIPLIER 1.3
|
#define ARRAY_GROWTH_MULTIPLIER 1.3
|
||||||
|
#define ARRAY_SHRINK_TRIGGER 2
|
||||||
|
|
||||||
void *dyn_arr_init(size_t item_size, size_t capacity) {
|
void *dyn_arr_init(size_t item_size, size_t capacity) {
|
||||||
void *dyna_ptr = NULL;
|
void *dyna_ptr = NULL;
|
||||||
|
|
@ -12,6 +14,7 @@ void *dyn_arr_init(size_t item_size, size_t capacity) {
|
||||||
dyna_header *header = malloc(size);
|
dyna_header *header = malloc(size);
|
||||||
|
|
||||||
if (header) {
|
if (header) {
|
||||||
|
header->item_size = item_size;
|
||||||
header->capacity = capacity;
|
header->capacity = capacity;
|
||||||
header->length = 0;
|
header->length = 0;
|
||||||
dyna_ptr = header + 1;
|
dyna_ptr = header + 1;
|
||||||
|
|
@ -20,17 +23,29 @@ void *dyn_arr_init(size_t item_size, size_t capacity) {
|
||||||
return dyna_ptr;
|
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);
|
dyna_header *header = dyna_get_header(array);
|
||||||
size_t minimum_capacity = header->length + item_count;
|
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;
|
return header + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t new_capacity = header->capacity * ARRAY_GROWTH_MULTIPLIER;
|
size_t new_capacity = minimum_capacity * ARRAY_GROWTH_MULTIPLIER;
|
||||||
while (new_capacity < minimum_capacity) {
|
// Force minimum automatic reallocation
|
||||||
new_capacity *= ARRAY_GROWTH_MULTIPLIER;
|
if (new_capacity <= ARRAY_INITIAL_CAPACITY) {
|
||||||
|
new_capacity = ARRAY_INITIAL_CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're at minimum auto capacity and the capacity is fine don't realloc
|
||||||
|
if (new_capacity <= ARRAY_INITIAL_CAPACITY &&
|
||||||
|
header->capacity >= minimum_capacity) {
|
||||||
|
return header + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t new_size = sizeof(dyna_header) + new_capacity * item_size;
|
size_t new_size = sizeof(dyna_header) + new_capacity * item_size;
|
||||||
|
|
@ -39,31 +54,9 @@ void *dyna_ensure_capacity(void *array, size_t item_count, size_t item_size) {
|
||||||
return header + 1;
|
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) {
|
void dyna_deinit(void *array) {
|
||||||
dyna_header *header = dyna_get_header(array);
|
|
||||||
header = NULL;
|
|
||||||
free(dyna_get_header(array));
|
free(dyna_get_header(array));
|
||||||
|
array = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dyna_empty(void *array) {
|
bool dyna_empty(void *array) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define ARRAY_INITIAL_CAPACITY 4
|
#define ARRAY_INITIAL_CAPACITY 10
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* Functions to implement to match what I want:
|
* Functions to implement to match what I want:
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
* - clear aka erase
|
* - clear aka erase
|
||||||
* - insert
|
* - insert
|
||||||
* - (optional) insert range
|
* - (optional) insert range
|
||||||
* - pop
|
|
||||||
* - (optional) swap
|
* - (optional) swap
|
||||||
* - (optional) resize
|
* - (optional) resize
|
||||||
* - Sanity checks
|
* - Sanity checks
|
||||||
|
|
@ -22,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct dyna_header {
|
typedef struct dyna_header {
|
||||||
|
size_t item_size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
size_t length;
|
size_t length;
|
||||||
} dyna_header;
|
} dyna_header;
|
||||||
|
|
@ -32,19 +32,21 @@ void *dyn_arr_init(size_t item_size, size_t capacity);
|
||||||
|
|
||||||
// Modification
|
// Modification
|
||||||
#define dyna_append(array, value) \
|
#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] = (value), \
|
||||||
&(array)[dyna_get_header(array)->length++])
|
&(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)))
|
#define dyna_pop(array) \
|
||||||
void dyn_arr_pop(void *array, size_t item_size);
|
((array) = dyna_ensure_capacity(array, -1), \
|
||||||
|
&(array)[dyna_get_header(array)->length--])
|
||||||
|
|
||||||
void dyna_deinit(void *array);
|
void dyna_deinit(void *array);
|
||||||
|
|
||||||
// Get meta data
|
// 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_length(array) (dyna_get_header(array)->length)
|
||||||
#define dyna_capacity(array) (dyna_get_header(array)->capacity)
|
#define dyna_capacity(array) (dyna_get_header(array)->capacity)
|
||||||
bool dyna_empty(void *array);
|
bool dyna_empty(void *array);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue