borrow allocator implementation
This commit is contained in:
+15
-3
@@ -61,6 +61,8 @@ void buffer_allocator_reset(buffer_allocator_t *this);
|
|||||||
typedef struct linked_allocation_node {
|
typedef struct linked_allocation_node {
|
||||||
struct linked_allocation_node *next;
|
struct linked_allocation_node *next;
|
||||||
struct linked_allocation_node *prev;
|
struct linked_allocation_node *prev;
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
any_align_t data[];
|
any_align_t data[];
|
||||||
} linked_allocation_node_t;
|
} linked_allocation_node_t;
|
||||||
|
|
||||||
@@ -70,9 +72,19 @@ typedef struct borrow_allocator {
|
|||||||
|
|
||||||
#define borrow_allocator_create() ((borrow_allocator_t){.head=NULL})
|
#define borrow_allocator_create() ((borrow_allocator_t){.head=NULL})
|
||||||
|
|
||||||
void *borrow_allcoator_alloc(borrow_allocator_t *this, size_t bytes);
|
void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes, const char *file, int line);
|
||||||
void *borrow_allcoator_resize(borrow_allocator_t *this, void *old_ptr, size_t bytes);
|
#define borrow_allocator_alloc(this, bytes) borrow_allocator_alloc_func(this, bytes, __FILE__, __LINE__)
|
||||||
void borrow_allcoator_free(borrow_allocator_t *this, void *old_ptr);
|
void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size_t bytes, const char *file, int line);
|
||||||
|
#define borrow_allocator_resize(this, old_ptr, bytes) borrow_allocator_resize_func(this, old_ptr, bytes, __FILE__, __LINE__)
|
||||||
|
void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr);
|
||||||
|
// Free all allocations done by this allocator.
|
||||||
|
void borrow_allocator_reset(borrow_allocator_t *this);
|
||||||
|
size_t borrow_allocator_count_allocations(borrow_allocator_t *this);
|
||||||
|
// Check that all allocations have been freed, or print a list of files and
|
||||||
|
// lines where made that haven't been freed to stderr and then exit the program
|
||||||
|
// with 1 as the return value.
|
||||||
|
void borrow_allocator_assert_all_freed(borrow_allocator_t *this);
|
||||||
|
allocator_t borrow_allocator_interface(borrow_allocator_t *this);
|
||||||
|
|
||||||
#ifdef ALLOCATOR_IMPLEMENTATION
|
#ifdef ALLOCATOR_IMPLEMENTATION
|
||||||
|
|
||||||
|
|||||||
+91
-10
@@ -1,25 +1,106 @@
|
|||||||
#include "allocator.h"
|
#include "allocator.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
void *borrow_allcoator_alloc(borrow_allocator_t *this, size_t bytes) {
|
void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes, const char *file, int line) {
|
||||||
linked_allocation_node_t *node = malloc(sizeof(*this->head) + bytes);
|
linked_allocation_node_t *node = malloc(sizeof(*this->head) + bytes);
|
||||||
if (node == NULL) { return NULL; }
|
if (node == NULL) { return NULL; }
|
||||||
|
node->file = file;
|
||||||
|
node->line = line;
|
||||||
node->prev = NULL;
|
node->prev = NULL;
|
||||||
node->next = this->head;
|
node->next = this->head;
|
||||||
if (this->head != NULL) {
|
if (this->head != NULL) {
|
||||||
|
assert(this->head->prev == NULL);
|
||||||
this->head->prev = node;
|
this->head->prev = node;
|
||||||
}
|
}
|
||||||
this->head = node;
|
this->head = node;
|
||||||
|
return &node->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: it is important to consider the case where the old_node is the head
|
void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size_t bytes, const char *file, int line) {
|
||||||
// node.
|
linked_allocation_node_t *old_node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr);
|
||||||
|
linked_allocation_node_t *new_node = realloc(old_node, sizeof(*old_node) + bytes);
|
||||||
|
if (new_node == NULL) { return NULL; }
|
||||||
|
new_node->file = file;
|
||||||
|
new_node->line = line;
|
||||||
|
if (this->head == old_node) {
|
||||||
|
assert(new_node->prev == NULL);
|
||||||
|
this->head = new_node;
|
||||||
|
}
|
||||||
|
if (new_node->prev != NULL) { new_node->prev->next = new_node; }
|
||||||
|
if (new_node->next != NULL) { new_node->next->prev = new_node; }
|
||||||
|
return &new_node->data;
|
||||||
|
}
|
||||||
|
|
||||||
void *borrow_allcoator_resize(borrow_allocator_t *this, void *old_ptr, size_t bytes) {
|
void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr) {
|
||||||
linked_allocation_node_t *old_node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr);
|
linked_allocation_node_t *node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr);
|
||||||
// TODO: update the links
|
if (node->prev != NULL) { node->prev->next = node->next; }
|
||||||
|
if (node->next != NULL) { node->next->prev = node->prev; }
|
||||||
|
if (this->head == node) {
|
||||||
|
assert(node->prev == NULL);
|
||||||
|
if (node->next != NULL) { assert(node->next->prev == NULL); }
|
||||||
|
this->head = node->next;
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void borrow_allocator_reset(borrow_allocator_t *this) {
|
||||||
|
if (this->head == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(this->head->prev == NULL);
|
||||||
|
void *prev = NULL;
|
||||||
|
for (linked_allocation_node_t *node = this->head; node != NULL; node = node->next) {
|
||||||
|
free(prev);
|
||||||
|
prev = node;
|
||||||
|
}
|
||||||
|
free(prev);
|
||||||
|
this->head = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t borrow_allocator_count_allocations(borrow_allocator_t *this) {
|
||||||
|
size_t output = 0;
|
||||||
|
for (linked_allocation_node_t *node = this->head; node != NULL; node = node->next) {
|
||||||
|
output++;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *borrow_alloc(void *this, size_t bytes, const char *file, int line) {
|
||||||
|
return borrow_allocator_alloc_func(this, bytes, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *borrow_resize(void *this, void *old_ptr, size_t bytes, const char *file, int line) {
|
||||||
|
return borrow_allocator_resize_func(this, old_ptr, bytes, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void borrow_free(void *this, void *ptr, const char *file, int line) {
|
||||||
|
(void)file;
|
||||||
|
(void)line;
|
||||||
|
borrow_allocator_free(this, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const allocator_vtbl_t borrow_vtbl = {
|
||||||
|
.alloc = borrow_alloc,
|
||||||
|
.resize = borrow_resize,
|
||||||
|
.free = borrow_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
allocator_t borrow_allocator_interface(borrow_allocator_t *this) {
|
||||||
|
return (allocator_t) {
|
||||||
|
.this=this,
|
||||||
|
.vtbl=&borrow_vtbl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void borrow_allocator_assert_all_freed(borrow_allocator_t *this) {
|
||||||
|
bool should_crash = false;
|
||||||
|
for (linked_allocation_node_t *curr = this->head; curr != NULL; curr = curr->next) {
|
||||||
|
fprintf(stderr, "%s:%d: allocation not freed\n", curr->file, curr->line);
|
||||||
|
}
|
||||||
|
if (should_crash) {
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
void borrow_allcoator_free(borrow_allocator_t *this, void *old_ptr) {
|
|
||||||
linked_allocation_node_t *old_node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr);
|
|
||||||
// TODO: update the links
|
|
||||||
free(old_node);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <criterion/criterion.h>
|
||||||
|
#include "allocator.h"
|
||||||
|
|
||||||
|
#define EXPECT 5
|
||||||
|
Test(borrow_allocator, test) {
|
||||||
|
borrow_allocator_t balloc = borrow_allocator_create();
|
||||||
|
int *ptr = borrow_allocator_alloc(&balloc, sizeof(int));
|
||||||
|
*ptr = EXPECT;
|
||||||
|
cr_assert_eq(*ptr, EXPECT);
|
||||||
|
cr_assert_eq(1, borrow_allocator_count_allocations(&balloc));
|
||||||
|
borrow_allocator_reset(&balloc);
|
||||||
|
cr_assert_eq(0, borrow_allocator_count_allocations(&balloc));
|
||||||
|
borrow_allocator_assert_all_freed(&balloc);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user