107 lines
4.7 KiB
C
107 lines
4.7 KiB
C
#ifndef ALLOCATOR_H
|
|
#define ALLOCATOR_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef union any_align { char c; int i; long l; long long ll; float f; double d; void *p; } any_align_t;
|
|
#define MAX_ALIGN (sizeof(any_align_t))
|
|
#define KB (1024)
|
|
#define MB (KB * KB)
|
|
#define GB (KB * KB * KB)
|
|
#define OFFSET(STRUCT, FIELD) ((size_t) (&((STRUCT*) NULL)->FIELD))
|
|
#define PTR_FROM_FIELD_PTR(STRUCT, FIELD, PTR) ((STRUCT *) (((char *) PTR) - OFFSET(STRUCT, FIELD)))
|
|
|
|
|
|
// Contains all operations an allocator can do. Similar interface to sdtlibs
|
|
// malloc, realloc and free.
|
|
typedef struct allocator_vtbl {
|
|
void *(*alloc)(void *this, size_t bytes, const char *file, int line);
|
|
void *(*resize)(void *this, void *old_ptr, size_t bytes, const char *file, int line);
|
|
void (*free)(void *this, void *ptr, const char *file, int line);
|
|
} allocator_vtbl_t;
|
|
|
|
// An instance of an allocator.
|
|
typedef struct allocator {
|
|
// pointer to the behind-the-scenes data that an allocator may store.
|
|
void *const this;
|
|
// pointer to the method implementations of an allocator.
|
|
const allocator_vtbl_t *const vtbl;
|
|
} allocator_t;
|
|
|
|
void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line);
|
|
void *allocator_resize_func(allocator_t this, void *old_ptr, size_t bytes, const char *file, int line);
|
|
void allocator_free_func(allocator_t this, void *ptr, const char *file, int line);
|
|
#define allocator_alloc(this, bytes) allocator_alloc_func(this, bytes, __FILE__, __LINE__)
|
|
#define allocator_resize(this, old_ptr, bytes) allocator_resize_func(this, old_ptr, bytes, __FILE__, __LINE__)
|
|
#define allocator_free(this, ptr) allocator_free_func(this, ptr, __FILE__, __LINE__)
|
|
|
|
// std_allocator ///////////////////////////////////////////////////////////////
|
|
extern const allocator_t allocator_stdlib;
|
|
// buffer_allocator ////////////////////////////////////////////////////////////
|
|
typedef struct buffer_allocator {
|
|
size_t size, capacity;
|
|
uint8_t *data;
|
|
} buffer_allocator_t;
|
|
|
|
#define buffer_allocator_create(CAPACITY) \
|
|
((buffer_allocator_t){ \
|
|
.size = 0, .capacity = CAPACITY, .data = (uint8_t[CAPACITY]){}})
|
|
|
|
allocator_t buffer_allocator_interface(buffer_allocator_t *this);
|
|
void *buffer_allocator_alloc(buffer_allocator_t *this, size_t bytes);
|
|
// Very simple resize. Does not free any memory, nor does it keep track of the
|
|
// previously allocated size of the old_pointer, just copies over as few bytes
|
|
// as it can with the information it has to a new allocation.
|
|
void *buffer_allocator_resize(buffer_allocator_t *this, void *old_ptr, size_t bytes);
|
|
void buffer_allocator_reset(buffer_allocator_t *this);
|
|
|
|
// borrow_allocator ////////////////////////////////////////////////////////////
|
|
typedef struct linked_allocation_node {
|
|
struct linked_allocation_node *next;
|
|
struct linked_allocation_node *prev;
|
|
const char *file;
|
|
int line;
|
|
any_align_t data[];
|
|
} linked_allocation_node_t;
|
|
|
|
typedef struct borrow_allocator {
|
|
linked_allocation_node_t *head;
|
|
} borrow_allocator_t;
|
|
|
|
#define borrow_allocator_create() ((borrow_allocator_t){.head=NULL})
|
|
|
|
void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes, const char *file, int line);
|
|
#define borrow_allocator_alloc(this, bytes) borrow_allocator_alloc_func(this, bytes, __FILE__, __LINE__)
|
|
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
|
|
|
|
void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line) {
|
|
return this.vtbl->alloc(this.this, bytes, file, line);
|
|
}
|
|
void *allocator_resize_func(allocator_t this, void *old_ptr, size_t bytes, const char *file, int line) {
|
|
return this.vtbl->resize(this.this, old_ptr, bytes, file, line);
|
|
}
|
|
void allocator_free_func(allocator_t this, void *ptr, const char *file, int line) {
|
|
this.vtbl->free(this.this, ptr, file, line);
|
|
}
|
|
|
|
#include "std_allocator.c"
|
|
#include "buffer_allocator.c"
|
|
#include "borrow_allocator.c"
|
|
|
|
#endif // ALLOCATOR_IMPLEMENTATION
|
|
#endif // ALLOCATOR_H
|