retab everything to use tabs
This commit is contained in:
@@ -18,17 +18,17 @@ typedef union any_align { char c; int i; long l; long long ll; float f; double d
|
||||
// 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);
|
||||
void *(*resize)(void *this, void *old_ptr, size_t bytes);
|
||||
void (*reset)(void *this);
|
||||
void *(*alloc)(void *this, size_t bytes);
|
||||
void *(*resize)(void *this, void *old_ptr, size_t bytes);
|
||||
void (*reset)(void *this);
|
||||
} allocator_vtbl_t;
|
||||
|
||||
// An instance of an allocator.
|
||||
typedef struct allocator {
|
||||
// pointer to the behind-the-scenes data that an allocator may store.
|
||||
void *this;
|
||||
// pointer to the method implementations of an allocator.
|
||||
const allocator_vtbl_t *vtbl;
|
||||
// pointer to the behind-the-scenes data that an allocator may store.
|
||||
void *this;
|
||||
// pointer to the method implementations of an allocator.
|
||||
const allocator_vtbl_t *vtbl;
|
||||
} allocator_t;
|
||||
|
||||
void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line);
|
||||
@@ -37,29 +37,31 @@ void allocator_reset(allocator_t this);
|
||||
#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__)
|
||||
|
||||
// std_allocator ///////////////////////////////////////////////////////////////
|
||||
// forever_allocator ///////////////////////////////////////////////////////////
|
||||
allocator_t forever_allocator();
|
||||
|
||||
// buffer_allocator ////////////////////////////////////////////////////////////
|
||||
typedef struct buffer_allocator {
|
||||
size_t size, capacity;
|
||||
uint8_t *data;
|
||||
size_t size, capacity;
|
||||
uint8_t *data;
|
||||
} buffer_allocator_t;
|
||||
|
||||
#define buffer_allocator_create(CAPACITY) \
|
||||
// TODO: name stack value or something to signal what is happening here!
|
||||
#define buffer_allocator_value(CAPACITY) \
|
||||
((buffer_allocator_t){ \
|
||||
.size = 0, .capacity = CAPACITY, .data = (uint8_t[CAPACITY]){0}})
|
||||
.size = 0, .capacity = CAPACITY, .data = (uint8_t[CAPACITY]){0}})
|
||||
|
||||
allocator_t buffer_allocator(buffer_allocator_t *this);
|
||||
allocator_t allocator_from_buffer(buffer_allocator_t *this);
|
||||
|
||||
// borrow_allocator ////////////////////////////////////////////////////////////
|
||||
typedef struct linked_allocation_node {
|
||||
struct linked_allocation_node *next;
|
||||
struct linked_allocation_node *prev;
|
||||
any_align_t data[];
|
||||
struct linked_allocation_node *next;
|
||||
struct linked_allocation_node *prev;
|
||||
any_align_t data[];
|
||||
} linked_allocation_node_t;
|
||||
|
||||
typedef struct borrow_allocator {
|
||||
linked_allocation_node_t *head;
|
||||
linked_allocation_node_t *head;
|
||||
} borrow_allocator_t;
|
||||
|
||||
#define borrow_allocator_value() ((borrow_allocator_t){.head=NULL})
|
||||
@@ -76,67 +78,94 @@ allocator_t allocator_from_borrow(borrow_allocator_t *this);
|
||||
// with_borrow(foos_allocator) {bar = foo(foos_allocator, my_allocator); } Using
|
||||
// the return a keyword in the statement following this macro will cause a
|
||||
// guaranteed memory leak.
|
||||
#define with_borrow(NAME) \
|
||||
for (allocator_t NAME = borrow_allocator_create(); NAME.this != NULL; \
|
||||
NAME.this = (allocator_reset(NAME), NULL)) \
|
||||
for (int UNIQUE = 0; UNIQUE < 1; UNIQUE++)
|
||||
#define with_borrow(NAME) \
|
||||
for (allocator_t NAME = borrow_allocator_create(); NAME.this != NULL; \
|
||||
NAME.this = (allocator_reset(NAME), NULL)) \
|
||||
for (int UNIQUE = 0; UNIQUE < 1; UNIQUE++)
|
||||
|
||||
// arena allocator /////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct arena_allocator {
|
||||
allocator_t allocator;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
// this may grow outside the allocated data. When data is not large enough,
|
||||
// the backing allocator will be used to allocate exactly what the user
|
||||
// asked for, and the total_allocated will grow for each such allocation.
|
||||
// On the next reset if total_allocated is larger than capacity, we know
|
||||
// that there are allocations outside the large buffer, so we reset the
|
||||
// allocator, and allocate a new buffer that is the size of
|
||||
// total_allocated, and set the new size of the capacity. Otherwise the
|
||||
// size is just reset to 0. plus something else I think I forgot.
|
||||
size_t total_allocated_bytes;
|
||||
uint8_t *data;
|
||||
} arena_allocator_t;
|
||||
|
||||
#define arena_allocator_value(INITIAL_CAPACITY) ((arena_allocator_t) { \
|
||||
.allocator=borrow_allocator_create(), \
|
||||
.size=0, \
|
||||
.capacity=INITIAL_CAPACITY, \
|
||||
.data=NULL \
|
||||
})
|
||||
|
||||
allocator_t allocator_from_arena(arena_allocator_t *this);
|
||||
|
||||
// dynamic arrays //////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct dyn_array_header {
|
||||
size_t size, capacity, itemsize;
|
||||
allocator_t allocator;
|
||||
uint8_t bytes[];
|
||||
size_t size, capacity, itemsize;
|
||||
allocator_t allocator;
|
||||
uint8_t bytes[];
|
||||
} dyn_array_header_t;
|
||||
|
||||
typedef struct dyn_array_create_func_args {
|
||||
allocator_t allocator;
|
||||
size_t itemsize;
|
||||
size_t initial_capacity;
|
||||
const char *file;
|
||||
int line;
|
||||
allocator_t allocator;
|
||||
size_t itemsize;
|
||||
size_t initial_capacity;
|
||||
const char *file;
|
||||
int line;
|
||||
} dyn_array_create_func_args_t;
|
||||
void *dyn_array_create_func(dyn_array_create_func_args_t args);
|
||||
#define dyn_array_create(ALLOCATOR, TYPE, ...) \
|
||||
((TYPE *)dyn_array_create_func( \
|
||||
(dyn_array_create_func_args_t){.allocator = ALLOCATOR, \
|
||||
.itemsize = sizeof(TYPE), \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
__VA_ARGS__}))
|
||||
#define dyn_array_create(ALLOCATOR, TYPE, ...) \
|
||||
((TYPE *)dyn_array_create_func( \
|
||||
(dyn_array_create_func_args_t){.allocator = ALLOCATOR, \
|
||||
.itemsize = sizeof(TYPE), \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
__VA_ARGS__}))
|
||||
// Always reassign the array. if multiple variables reference the same growing
|
||||
// array, then you should be using pointer pointers.
|
||||
void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int line);
|
||||
void dyn_array_shrink_func(void *this, size_t n_items_to_remove, const char *file, int line);
|
||||
|
||||
#define dyn_array_grow(THIS, N_NEW_ITEMS) \
|
||||
#define dyn_array_grow(THIS, N_NEW_ITEMS) \
|
||||
dyn_array_grow_func(THIS, N_NEW_ITEMS, __FILE__, __LINE__)
|
||||
|
||||
#define dyn_array_shrink(THIS, N_ITEMS_TO_REMOVE) \
|
||||
#define dyn_array_shrink(THIS, N_ITEMS_TO_REMOVE) \
|
||||
dyn_array_shrink_func(THIS, N_ITEMS_TO_REMOVE, __FILE__, __LINE__)
|
||||
|
||||
#define dyn_array_reset(THIS) \
|
||||
do { \
|
||||
dyn_array_shrink(THIS, dyn_array_length(THIS)); \
|
||||
#define dyn_array_reset(THIS) \
|
||||
do { \
|
||||
dyn_array_shrink(THIS, dyn_array_length(THIS)); \
|
||||
} while (0)
|
||||
|
||||
typedef struct dyn_array_create_non_crashing_func_args {
|
||||
allocator_t allocator;
|
||||
size_t itemsize;
|
||||
size_t initial_capacity;
|
||||
const char *file;
|
||||
size_t line;
|
||||
allocator_t allocator;
|
||||
size_t itemsize;
|
||||
size_t initial_capacity;
|
||||
const char *file;
|
||||
size_t line;
|
||||
} dyn_array_create_non_crashing_func_args_t;
|
||||
void *dyn_array_create_non_crashing_func(dyn_array_create_non_crashing_func_args_t args);
|
||||
// This version returns a NULL pointer instead of crashing if the allocator return NULL.
|
||||
// It is up to you to check that the pointer returned isn't NULL
|
||||
#define dyn_array_create_non_crashing(ALLOCATOR, TYPE, ...) \
|
||||
((TYPE *)dyn_array_create_non_crashing_func( \
|
||||
(dyn_array_create_non_crashing_func_args_t){.allocator = ALLOCATOR, \
|
||||
.itemsize = sizeof(TYPE), \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
__VA_ARGS__}))
|
||||
#define dyn_array_create_non_crashing(ALLOCATOR, TYPE, ...) \
|
||||
((TYPE *)dyn_array_create_non_crashing_func( \
|
||||
(dyn_array_create_non_crashing_func_args_t){.allocator = ALLOCATOR, \
|
||||
.itemsize = sizeof(TYPE), \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
__VA_ARGS__}))
|
||||
// TODO: remove the non-crashing versions. they crash...
|
||||
// This version returns a NULL pointer instead of crashing if the allocator return NULL.
|
||||
// It is up to you to check that the pointer returned isn't NULL
|
||||
@@ -149,8 +178,8 @@ size_t dyn_array_length(void *this);
|
||||
size_t dyn_array_capacity(void *this);
|
||||
|
||||
#define dyn_array_append(THIS, VAL) do { \
|
||||
THIS = dyn_array_grow(THIS, 1); \
|
||||
THIS[dyn_array_length(THIS)-1] = VAL; \
|
||||
THIS = dyn_array_grow(THIS, 1); \
|
||||
THIS[dyn_array_length(THIS)-1] = VAL; \
|
||||
} while(0)
|
||||
|
||||
#define dyn_array_pop(THIS) (dyn_array_shrink(THIS, 1), THIS[dyn_array_length(THIS)])
|
||||
@@ -158,28 +187,29 @@ size_t dyn_array_capacity(void *this);
|
||||
#ifdef CIG_IMPL
|
||||
|
||||
void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line) {
|
||||
void *ptr = this.vtbl->alloc(this.this, bytes);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "%s:%d: alloc returned NULL\n", file, line);
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
void *ptr = this.vtbl->alloc(this.this, bytes);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "%s:%d: alloc returned NULL\n", file, line);
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
void *allocator_resize_func(allocator_t this, void *old_ptr, size_t bytes, const char *file, int line) {
|
||||
void *ptr = this.vtbl->resize(this.this, old_ptr, bytes);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "%s:%d: alloc returned NULL\n", file, line);
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
void *ptr = this.vtbl->resize(this.this, old_ptr, bytes);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "%s:%d: alloc returned NULL\n", file, line);
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
void allocator_reset(allocator_t this) {
|
||||
this.vtbl->reset(this.this);
|
||||
this.vtbl->reset(this.this);
|
||||
}
|
||||
|
||||
#include "forever_allocator.c"
|
||||
#include "buffer_allocator.c"
|
||||
#include "borrow_allocator.c"
|
||||
#include "arena_allocator.c"
|
||||
#include "dyn_array.c"
|
||||
|
||||
#endif // CIG_IMPL
|
||||
|
||||
Reference in New Issue
Block a user