diff --git a/borrow_allocator.c b/borrow_allocator.c index ad0c923..0697b59 100644 --- a/borrow_allocator.c +++ b/borrow_allocator.c @@ -5,87 +5,87 @@ #include void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes) { - linked_allocation_node_t *node = malloc(sizeof(*this->head) + bytes); - if (node == NULL) { return NULL; } - node->prev = NULL; - node->next = this->head; - if (this->head != NULL) { - assert(this->head->prev == NULL); - this->head->prev = node; - } - this->head = node; - return &node->data; + linked_allocation_node_t *node = malloc(sizeof(*this->head) + bytes); + if (node == NULL) { return NULL; } + node->prev = NULL; + node->next = this->head; + if (this->head != NULL) { + assert(this->head->prev == NULL); + this->head->prev = node; + } + this->head = node; + return &node->data; } void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size_t bytes) { - 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; } - 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; + 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; } + 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; } // TODO: remove void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr) { - linked_allocation_node_t *node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr); - 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); + linked_allocation_node_t *node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr); + 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_free_all(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; + 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; + size_t output = 0; + for (linked_allocation_node_t *node = this->head; node != NULL; node = node->next) { + output++; + } + return output; } static void *borrow_alloc_impl(void *this, size_t bytes) { - return borrow_allocator_alloc_func(this, bytes); + return borrow_allocator_alloc_func(this, bytes); } static void *borrow_resize_impl(void *this, void *old_ptr, size_t bytes) { - return borrow_allocator_resize_func(this, old_ptr, bytes); + return borrow_allocator_resize_func(this, old_ptr, bytes); } static void borrow_reset(void *this) { - borrow_allocator_free_all(this); + borrow_allocator_free_all(this); } static const allocator_vtbl_t borrow_vtbl = { - .alloc = borrow_alloc_impl, - .resize = borrow_resize_impl, - .reset = borrow_reset, + .alloc = borrow_alloc_impl, + .resize = borrow_resize_impl, + .reset = borrow_reset, }; allocator_t allocator_from_borrow(borrow_allocator_t *this) { - return (allocator_t) { - .this=this, - .vtbl=&borrow_vtbl, - }; + return (allocator_t) { + .this=this, + .vtbl=&borrow_vtbl, + }; } diff --git a/buffer_allocator.c b/buffer_allocator.c index 9b48cea..6a72541 100644 --- a/buffer_allocator.c +++ b/buffer_allocator.c @@ -1,56 +1,56 @@ #include "cig.h" void *buffer_allocator_alloc(buffer_allocator_t *this, size_t bytes) { - size_t address_of_new_data = (size_t) &this->data[this->size]; - size_t offset = address_of_new_data % MAX_ALIGN; - size_t new_size = this->size + offset + bytes; - if (new_size > this->capacity) { - return NULL; - } - this->size += offset; - void *ptr = &this->data[this->size]; - this->size = new_size; - return ptr; + size_t address_of_new_data = (size_t) &this->data[this->size]; + size_t offset = address_of_new_data % MAX_ALIGN; + size_t new_size = this->size + offset + bytes; + if (new_size > this->capacity) { + return NULL; + } + this->size += offset; + void *ptr = &this->data[this->size]; + this->size = new_size; + return ptr; } void *buffer_allocator_resize(buffer_allocator_t *this, void *old_ptr, size_t bytes) { - void *new_ptr = buffer_allocator_alloc(this, bytes); - if (new_ptr == NULL) { - return NULL; - } - for (size_t i = 0; i < bytes; i++) { - unsigned char *new_ptr_b = (unsigned char *)new_ptr; - unsigned char *old_ptr_b = (unsigned char *)old_ptr; - new_ptr_b[i] = old_ptr_b[i]; - } - return new_ptr; + void *new_ptr = buffer_allocator_alloc(this, bytes); + if (new_ptr == NULL) { + return NULL; + } + for (size_t i = 0; i < bytes; i++) { + unsigned char *new_ptr_b = (unsigned char *)new_ptr; + unsigned char *old_ptr_b = (unsigned char *)old_ptr; + new_ptr_b[i] = old_ptr_b[i]; + } + return new_ptr; } void buffer_allocator_reset(buffer_allocator_t *this) { - this->size = 0; + this->size = 0; } static void *buffer_alloc_impl(void *this, size_t bytes) { - return buffer_allocator_alloc((buffer_allocator_t *)this, bytes); + return buffer_allocator_alloc((buffer_allocator_t *)this, bytes); } static void *buffer_resize_impl(void *this, void *old_ptr, size_t bytes) { - return buffer_allocator_resize((buffer_allocator_t *)this, old_ptr, bytes); + return buffer_allocator_resize((buffer_allocator_t *)this, old_ptr, bytes); } static void buffer_reset_impl(void *this) { - buffer_allocator_reset((buffer_allocator_t *)this); + buffer_allocator_reset((buffer_allocator_t *)this); } static const allocator_vtbl_t buffer_vtbl = { - .alloc = buffer_alloc_impl, - .resize = buffer_resize_impl, - .reset = buffer_reset_impl, + .alloc = buffer_alloc_impl, + .resize = buffer_resize_impl, + .reset = buffer_reset_impl, }; -allocator_t buffer_allocator(buffer_allocator_t *this) { - return (allocator_t) { - .this=this, - .vtbl=&buffer_vtbl, - }; +allocator_t allocator_from_buffer(buffer_allocator_t *this) { + return (allocator_t) { + .this=this, + .vtbl=&buffer_vtbl, + }; } diff --git a/cig.h b/cig.h index 464618b..2864878 100644 --- a/cig.h +++ b/cig.h @@ -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 diff --git a/cli.h b/cli.h index b38ee99..c085e08 100644 --- a/cli.h +++ b/cli.h @@ -7,8 +7,8 @@ #define CLI_UNIQUE2 __macro_internal_34bba35b8b9b20a75f9881e3795630e25d36e620d9c9741e2e9141ba82ec6ef8__ typedef struct args { - int count; - const char **values; + int count; + const char **values; } args_t; args_t cli_make_args(int argc, const char **argv); // no crash @@ -25,24 +25,24 @@ int cli_req_int_func(args_t args, const char *flag_name, const char *file, int l #define cli_req_int(ARGS, FLAG_NAME) cli_req_int_func(ARGS, FLAG_NAME, __FILE__, __LINE__) #define with_opt_str(ARGS, FLAG_NAME, VAR) \ - for (const char *VAR = NULL; VAR == NULL;) \ - for (bool CLI_UNIQUE1 = true; CLI_UNIQUE1;) \ - for ( \ - bool CLI_UNIQUE2 = (CLI_UNIQUE1 = cli_opt_str(ARGS, FLAG_NAME, &VAR), true); \ - CLI_UNIQUE2; \ - CLI_UNIQUE2 = (VAR = ((const char *) 1), CLI_UNIQUE1 = false, false) \ - ) \ - if (CLI_UNIQUE1) + for (const char *VAR = NULL; VAR == NULL;) \ + for (bool CLI_UNIQUE1 = true; CLI_UNIQUE1;) \ + for ( \ + bool CLI_UNIQUE2 = (CLI_UNIQUE1 = cli_opt_str(ARGS, FLAG_NAME, &VAR), true); \ + CLI_UNIQUE2; \ + CLI_UNIQUE2 = (VAR = ((const char *) 1), CLI_UNIQUE1 = false, false) \ + ) \ + if (CLI_UNIQUE1) #define with_opt_int(ARGS, FLAG_NAME, VAR) \ - for (int VAR = 0; VAR == 0;) \ - for (bool CLI_UNIQUE1 = true; CLI_UNIQUE1;) \ - for ( \ - bool CLI_UNIQUE2 = (CLI_UNIQUE1 = cli_opt_int(ARGS, FLAG_NAME, &VAR), true); \ - CLI_UNIQUE2; \ - CLI_UNIQUE2 = (VAR = 1, CLI_UNIQUE1 = false, false) \ - ) \ - if (CLI_UNIQUE1) + for (int VAR = 0; VAR == 0;) \ + for (bool CLI_UNIQUE1 = true; CLI_UNIQUE1;) \ + for ( \ + bool CLI_UNIQUE2 = (CLI_UNIQUE1 = cli_opt_int(ARGS, FLAG_NAME, &VAR), true); \ + CLI_UNIQUE2; \ + CLI_UNIQUE2 = (VAR = 1, CLI_UNIQUE1 = false, false) \ + ) \ + if (CLI_UNIQUE1) #ifdef CLI_IMPL @@ -51,108 +51,108 @@ int cli_req_int_func(args_t args, const char *flag_name, const char *file, int l #include bool cli_command(args_t *args, const char *command_name) { - if (args->count == 0) { - return false; - } - if (strcmp(args->values[0], command_name) == 0) { - args->values++; - args->count--; - return true; - } - return false; + if (args->count == 0) { + return false; + } + if (strcmp(args->values[0], command_name) == 0) { + args->values++; + args->count--; + return true; + } + return false; } bool cli_bool(args_t args, const char *flag_name) { - for ( int i = 0; i < args.count; i++ ) { - if (strcmp(args.values[i], flag_name) == 0) { - return true; - } - } - return false; + for ( int i = 0; i < args.count; i++ ) { + if (strcmp(args.values[i], flag_name) == 0) { + return true; + } + } + return false; } bool cli_opt_str_func(args_t args, const char *flag_name, const char **output, const char *file, int line) { - bool is_flag_name_found = false; - int flag_name_index; - for ( int i = 0; i < args.count; i++ ) { - if (strcmp(args.values[i], flag_name) == 0) { - is_flag_name_found = true; - flag_name_index = i; - break; - } - } - static const char *dummy = ""; - if (!is_flag_name_found) { - *output = dummy; - return false; - } - int flag_value_index = flag_name_index + 1; - if (args.count <= flag_value_index) { - fprintf(stderr, "%s:%d: No value provided for %s!\n", file, line, flag_name); - exit(1); - } - *output = args.values[flag_value_index]; - return true; + bool is_flag_name_found = false; + int flag_name_index; + for ( int i = 0; i < args.count; i++ ) { + if (strcmp(args.values[i], flag_name) == 0) { + is_flag_name_found = true; + flag_name_index = i; + break; + } + } + static const char *dummy = ""; + if (!is_flag_name_found) { + *output = dummy; + return false; + } + int flag_value_index = flag_name_index + 1; + if (args.count <= flag_value_index) { + fprintf(stderr, "%s:%d: No value provided for %s!\n", file, line, flag_name); + exit(1); + } + *output = args.values[flag_value_index]; + return true; } const char *cli_req_str_func(args_t args, const char *flag_name, const char *file, int line) { - const char *value; - if (cli_opt_str_func(args, flag_name, &value, file, line)) { - return value; - } else { - fprintf(stderr, "%s:%d: Required string %s not provided!\n", file, line, flag_name); - exit(1); - } - return ""; + const char *value; + if (cli_opt_str_func(args, flag_name, &value, file, line)) { + return value; + } else { + fprintf(stderr, "%s:%d: Required string %s not provided!\n", file, line, flag_name); + exit(1); + } + return ""; } bool cli_opt_int_func(args_t args, const char *flag_name, int *output, const char *file, int line) { - const char *text = ""; - if (cli_opt_str_func(args, flag_name, &text, file, line)) { - if ( - text[0] != '-' && - text[0] < '0' && - '9' < text[0] - ) { - fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); - exit(1); - } - if ( - text[0] == '-' && - text[1] == '\0' - ) { - fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); - exit(1); - } - for ( const char *c = &text[1]; (*c) != '\0'; c++ ) { - if ((*c) < '0' || '9' < (*c)) { - fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); - exit(1); - } - } - *output = atoi(text); - return true; - } - *output = 0; - return false; + const char *text = ""; + if (cli_opt_str_func(args, flag_name, &text, file, line)) { + if ( + text[0] != '-' && + text[0] < '0' && + '9' < text[0] + ) { + fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); + exit(1); + } + if ( + text[0] == '-' && + text[1] == '\0' + ) { + fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); + exit(1); + } + for ( const char *c = &text[1]; (*c) != '\0'; c++ ) { + if ((*c) < '0' || '9' < (*c)) { + fprintf(stderr, "%s:%d: Invalid integer %s!\n", file, line, text); + exit(1); + } + } + *output = atoi(text); + return true; + } + *output = 0; + return false; } int cli_req_int_func(args_t args, const char *flag_name, const char *file, int line) { - int value; - if (cli_opt_int_func(args, flag_name, &value, file, line)) { - return value; - } else { - fprintf(stderr, "%s:%d: Required int %s not provided!\n", file, line, flag_name); - exit(1); - } - return 0; + int value; + if (cli_opt_int_func(args, flag_name, &value, file, line)) { + return value; + } else { + fprintf(stderr, "%s:%d: Required int %s not provided!\n", file, line, flag_name); + exit(1); + } + return 0; } args_t cli_make_args(int argc, const char **argv) { - return (args_t) { - .count = argc-1, - .values = argv+1, - }; + return (args_t) { + .count = argc-1, + .values = argv+1, + }; } #endif /* CLI_IMPL */ diff --git a/dyn_array.c b/dyn_array.c index 091b119..0f32e3a 100644 --- a/dyn_array.c +++ b/dyn_array.c @@ -2,83 +2,83 @@ #include void *dyn_array_create_func(dyn_array_create_func_args_t args) { - void *bytes = dyn_array_create_non_crashing_func( - (dyn_array_create_non_crashing_func_args_t) { - .allocator=args.allocator, - .itemsize=args.itemsize, - .initial_capacity=args.initial_capacity, - .file=args.file, - .line=args.line - } - ); - return bytes; + void *bytes = dyn_array_create_non_crashing_func( + (dyn_array_create_non_crashing_func_args_t) { + .allocator=args.allocator, + .itemsize=args.itemsize, + .initial_capacity=args.initial_capacity, + .file=args.file, + .line=args.line + } + ); + return bytes; } void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int line) { - void *bytes = dyn_array_grow_non_crashing_func(this, n_new_items, file, line); - return bytes; + void *bytes = dyn_array_grow_non_crashing_func(this, n_new_items, file, line); + return bytes; } void *dyn_array_create_non_crashing_func(dyn_array_create_non_crashing_func_args_t args) { - dyn_array_header_t *header = allocator_alloc_func( - args.allocator, - sizeof(dyn_array_header_t) + args.itemsize * args.initial_capacity, - args.file, - args.line - ); - header->size = 0; - header->capacity = args.initial_capacity; - header->itemsize = args.itemsize; - header->allocator = args.allocator; - return &header->bytes; + dyn_array_header_t *header = allocator_alloc_func( + args.allocator, + sizeof(dyn_array_header_t) + args.itemsize * args.initial_capacity, + args.file, + args.line + ); + header->size = 0; + header->capacity = args.initial_capacity; + header->itemsize = args.itemsize; + header->allocator = args.allocator; + return &header->bytes; } void *dyn_array_grow_non_crashing_func(void *this, size_t n_new_items, const char *file, int line) { - dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - size_t new_size = header->size + n_new_items; + dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); + size_t new_size = header->size + n_new_items; - if (header->capacity < new_size) { - size_t cap_times_2 = header->capacity * 2; - size_t new_capacity = - cap_times_2 < new_size - ? new_size - : cap_times_2; - header = allocator_resize_func( - header->allocator, - header, - sizeof(dyn_array_header_t) + header->itemsize * new_capacity, - file, - line - ); - header->capacity = new_capacity; - } - header->size = new_size; - return &header->bytes; + if (header->capacity < new_size) { + size_t cap_times_2 = header->capacity * 2; + size_t new_capacity = + cap_times_2 < new_size + ? new_size + : cap_times_2; + header = allocator_resize_func( + header->allocator, + header, + sizeof(dyn_array_header_t) + header->itemsize * new_capacity, + file, + line + ); + header->capacity = new_capacity; + } + header->size = new_size; + return &header->bytes; } void dyn_array_shrink_func(void *this, size_t n_items_to_remove, const char *file, int line) { - if (dyn_array_length(this) < n_items_to_remove) { - fprintf( - stderr, - "%s:%d: tried to remove more items than contained in dynamic array.\n", - file, - line - ); - exit(1); - } - dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - header->size -= n_items_to_remove; + if (dyn_array_length(this) < n_items_to_remove) { + fprintf( + stderr, + "%s:%d: tried to remove more items than contained in dynamic array.\n", + file, + line + ); + exit(1); + } + dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); + header->size -= n_items_to_remove; } size_t dyn_array_length(void *this) { - if (this == NULL) { return 0; } - dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - return header->size; + if (this == NULL) { return 0; } + dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); + return header->size; } size_t dyn_array_capacity(void *this) { - if (this == NULL) { return 0; } - dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); - return header->capacity; + if (this == NULL) { return 0; } + dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); + return header->capacity; } diff --git a/forever_allocator.c b/forever_allocator.c index bd138de..51043f9 100644 --- a/forever_allocator.c +++ b/forever_allocator.c @@ -1,27 +1,27 @@ #include "cig.h" static void *forever_alloc(void *this, size_t bytes) { - (void)this; - return malloc(bytes); + (void)this; + return malloc(bytes); } static void *forever_resize(void *this, void *old_ptr, size_t bytes) { - (void)this; - return realloc(old_ptr, bytes); + (void)this; + return realloc(old_ptr, bytes); } static void forever_no_op(void *this) { - (void)this; + (void)this; } static const allocator_vtbl_t forever_vtbl = { - .alloc = forever_alloc, - .resize = forever_resize, - .reset = forever_no_op, + .alloc = forever_alloc, + .resize = forever_resize, + .reset = forever_no_op, }; allocator_t forever_allocator() { - return (allocator_t) { - .this=NULL, - .vtbl=&forever_vtbl, - }; + return (allocator_t) { + .this=NULL, + .vtbl=&forever_vtbl, + }; } diff --git a/scratch.c b/scratch.c index c40d95e..0d69b34 100644 --- a/scratch.c +++ b/scratch.c @@ -5,26 +5,26 @@ int main() { // test 1/////////////////////////////////////////////////////////////////////// - arena_allocator_t aalloc = arena_allocator_create(); + arena_allocator_t aalloc = arena_allocator_create(); - for ( int i = 0; i < 10; i++ ) with_arena(&aalloc, allocator) { - allocator_alloc(allocator, 10); - } + for ( int i = 0; i < 10; i++ ) with_arena(&aalloc, allocator) { + allocator_alloc(allocator, 10); + } - assert(aalloc.to_allocate == 10); - assert(borrow_allocator_count_allocations(&aalloc.borrow_allocator) == 0); - assert(dyn_array_capacity(aalloc.bytes) == 10); + assert(aalloc.to_allocate == 10); + assert(borrow_allocator_count_allocations(&aalloc.borrow_allocator) == 0); + assert(dyn_array_capacity(aalloc.bytes) == 10); - arena_allocator_destroy(&aalloc); - assert(aalloc.to_allocate == 0); + arena_allocator_destroy(&aalloc); + assert(aalloc.to_allocate == 0); arena_allocator_destroy(&aalloc); // test 2 ////////////////////////////////////////////////////////////////////// - aalloc = arena_allocator_create(); + aalloc = arena_allocator_create(); - for ( int i = 0; i < 10; i++ ) with_arena(&aalloc, allocator) { - allocator_alloc(allocator, 1000); - } + for ( int i = 0; i < 10; i++ ) with_arena(&aalloc, allocator) { + allocator_alloc(allocator, 1000); + } with_arena(&aalloc, allocator) { size_t prev_addr = 0; @@ -37,7 +37,7 @@ int main() { } arena_allocator_reset(&aalloc); fprintf(stderr, "%zu\n", aalloc.to_allocate); - //assert(aalloc.to_allocate == MAX_ALIGN * 1000 + 1); + //assert(aalloc.to_allocate == MAX_ALIGN * 1000 + 1); // TODO: WHAT is happening here? arena_allocator_destroy(&aalloc); } diff --git a/test_borrow_allocator.c b/test_borrow_allocator.c index bb06d5a..5b5683b 100644 --- a/test_borrow_allocator.c +++ b/test_borrow_allocator.c @@ -3,24 +3,24 @@ #define EXPECT 5 Test(borrow_allocator, test) { - allocator_t balloc = allocator_from_borrow(&borrow_allocator_value()); - int *ptr = allocator_alloc(balloc, sizeof(int)); - *ptr = EXPECT; - cr_assert_eq(*ptr, EXPECT); - allocator_reset(balloc); + allocator_t balloc = allocator_from_borrow(&borrow_allocator_value()); + int *ptr = allocator_alloc(balloc, sizeof(int)); + *ptr = EXPECT; + cr_assert_eq(*ptr, EXPECT); + allocator_reset(balloc); } #define IS_SIZE 900 Test(borrow_allocator, with) { - with_borrow(foo) { - with_borrow(bar) { - } - int *is = allocator_alloc(foo, sizeof(int) * IS_SIZE); - for (int i = 0; i < IS_SIZE; i++) is[i] = i; - is = allocator_alloc(foo, sizeof(int) * IS_SIZE); - for (int i = 0; i < IS_SIZE; i++) is[i] = i; - is = allocator_alloc(foo, sizeof(int) * IS_SIZE); - for (int i = 0; i < IS_SIZE; i++) is[i] = i; - break; - } + with_borrow(foo) { + with_borrow(bar) { + } + int *is = allocator_alloc(foo, sizeof(int) * IS_SIZE); + for (int i = 0; i < IS_SIZE; i++) is[i] = i; + is = allocator_alloc(foo, sizeof(int) * IS_SIZE); + for (int i = 0; i < IS_SIZE; i++) is[i] = i; + is = allocator_alloc(foo, sizeof(int) * IS_SIZE); + for (int i = 0; i < IS_SIZE; i++) is[i] = i; + break; + } } diff --git a/test_buffer_allocator.c b/test_buffer_allocator.c index 9ce0740..cfbc6f1 100644 --- a/test_buffer_allocator.c +++ b/test_buffer_allocator.c @@ -2,33 +2,33 @@ #include "cig.h" static void test_buffer_alloc(buffer_allocator_t impl) { - allocator_t inter = buffer_allocator(&impl); - const int n_ints = 100; - int *ints = allocator_alloc(inter, sizeof(int) * n_ints); - for (int i = 0; i < n_ints; i++) { - ints[i] = i; - } - for (int i = 0; i < n_ints; i++) { - cr_assert_eq(ints[i], i); - } - cr_assert_eq(impl.size, sizeof(int)*n_ints); - ints = allocator_alloc(inter, sizeof(int) * n_ints); - for (int i = 0; i < n_ints; i++) { - ints[i] = i; - } - for (int i = 0; i < n_ints; i++) { - cr_assert_eq(ints[i], i); - } - cr_assert_eq(impl.size, sizeof(int)*2*n_ints); - size_t double_ints = ((size_t) n_ints) * 2; - void *should_be_addr = allocator_resize(inter, ints, double_ints); - cr_assert_neq(should_be_addr, NULL); - allocator_reset(inter); + allocator_t inter = allocator_from_buffer(&impl); + const int n_ints = 100; + int *ints = allocator_alloc(inter, sizeof(int) * n_ints); + for (int i = 0; i < n_ints; i++) { + ints[i] = i; + } + for (int i = 0; i < n_ints; i++) { + cr_assert_eq(ints[i], i); + } + cr_assert_eq(impl.size, sizeof(int)*n_ints); + ints = allocator_alloc(inter, sizeof(int) * n_ints); + for (int i = 0; i < n_ints; i++) { + ints[i] = i; + } + for (int i = 0; i < n_ints; i++) { + cr_assert_eq(ints[i], i); + } + cr_assert_eq(impl.size, sizeof(int)*2*n_ints); + size_t double_ints = ((size_t) n_ints) * 2; + void *should_be_addr = allocator_resize(inter, ints, double_ints); + cr_assert_neq(should_be_addr, NULL); + allocator_reset(inter); } Test(buffer_allocator, test) { - buffer_allocator_t impl = buffer_allocator_create(MB); - test_buffer_alloc(impl); - cr_assert_eq(impl.size, 0); - test_buffer_alloc(impl); + buffer_allocator_t impl = buffer_allocator_value(MB); + test_buffer_alloc(impl); + cr_assert_eq(impl.size, 0); + test_buffer_alloc(impl); } diff --git a/test_dynamic_array.c b/test_dynamic_array.c index 5c120a0..4171c66 100644 --- a/test_dynamic_array.c +++ b/test_dynamic_array.c @@ -5,48 +5,48 @@ #include "cig.h" Test(dynamic_arrays, append) { - with_borrow(alloc) { - int *numbers = dyn_array_create(alloc, int); - dyn_array_append(numbers, 40); - dyn_array_append(numbers, 41); - dyn_array_append(numbers, 42); - dyn_array_append(numbers, 43); - dyn_array_append(numbers, 44); - dyn_array_append(numbers, 45); - dyn_array_append(numbers, 46); - dyn_array_append(numbers, 47); - dyn_array_append(numbers, 48); - dyn_array_append(numbers, 49); - dyn_array_append(numbers, 50); - for (int i = 0; i < (int)dyn_array_length(numbers); i++) { - cr_assert_eq(numbers[i], i+40); - } - } + with_borrow(alloc) { + int *numbers = dyn_array_create(alloc, int); + dyn_array_append(numbers, 40); + dyn_array_append(numbers, 41); + dyn_array_append(numbers, 42); + dyn_array_append(numbers, 43); + dyn_array_append(numbers, 44); + dyn_array_append(numbers, 45); + dyn_array_append(numbers, 46); + dyn_array_append(numbers, 47); + dyn_array_append(numbers, 48); + dyn_array_append(numbers, 49); + dyn_array_append(numbers, 50); + for (int i = 0; i < (int)dyn_array_length(numbers); i++) { + cr_assert_eq(numbers[i], i+40); + } + } } Test(dynamic_arrays, pop) { - with_borrow(alloc) { - int *numbers = dyn_array_create(alloc, int); - dyn_array_append(numbers, 40); - dyn_array_append(numbers, 41); - dyn_array_append(numbers, 42); - dyn_array_append(numbers, 43); - dyn_array_append(numbers, 44); - dyn_array_append(numbers, 45); - dyn_array_append(numbers, 46); - dyn_array_append(numbers, 47); - dyn_array_append(numbers, 48); - dyn_array_append(numbers, 49); - dyn_array_append(numbers, 50); - cr_assert_eq(dyn_array_length(numbers), 11); - // NOTE: you can stack for loops to have scoped variables you can abuse - // in macros. e.g. - // for (TYPE UNIQUE = (int)dyn_array_length(numbers); UNIQUE != 0; UNIQUE = 0;) - // for (int i = 0, i < UNIQUE; i++) - int len = (int)dyn_array_length(numbers); - for (int i = 0; i < len; i++) { - int num = dyn_array_pop(numbers); - cr_assert_eq(num, 50-i); - } - } + with_borrow(alloc) { + int *numbers = dyn_array_create(alloc, int); + dyn_array_append(numbers, 40); + dyn_array_append(numbers, 41); + dyn_array_append(numbers, 42); + dyn_array_append(numbers, 43); + dyn_array_append(numbers, 44); + dyn_array_append(numbers, 45); + dyn_array_append(numbers, 46); + dyn_array_append(numbers, 47); + dyn_array_append(numbers, 48); + dyn_array_append(numbers, 49); + dyn_array_append(numbers, 50); + cr_assert_eq(dyn_array_length(numbers), 11); + // NOTE: you can stack for loops to have scoped variables you can abuse + // in macros. e.g. + // for (TYPE UNIQUE = (int)dyn_array_length(numbers); UNIQUE != 0; UNIQUE = 0;) + // for (int i = 0, i < UNIQUE; i++) + int len = (int)dyn_array_length(numbers); + for (int i = 0; i < len; i++) { + int num = dyn_array_pop(numbers); + cr_assert_eq(num, 50-i); + } + } } diff --git a/test_macro_magic.c b/test_macro_magic.c index 270acf5..0961f20 100644 --- a/test_macro_magic.c +++ b/test_macro_magic.c @@ -2,25 +2,25 @@ #include enum animal { - dog, - cat, + dog, + cat, }; typedef struct args { - enum animal animal; - bool is_true; + enum animal animal; + bool is_true; } args_t; #define ARGS_DEFAULT .animal=cat, .is_true=true #define ARGS(...) ((args_t){ ARGS_DEFAULT, __VA_ARGS__ }) Test(macro_magic, default_values) { - args_t a1 = ARGS(); - args_t a2 = ARGS(.animal=dog); - args_t a3 = ARGS(.animal=dog, .is_true=false); - cr_assert_eq(a1.animal, cat); - cr_assert_eq(a2.animal, dog); - cr_assert_eq(a1.is_true, true); - cr_assert_eq(a2.is_true, true); - cr_assert_eq(a3.is_true, false); + args_t a1 = ARGS(); + args_t a2 = ARGS(.animal=dog); + args_t a3 = ARGS(.animal=dog, .is_true=false); + cr_assert_eq(a1.animal, cat); + cr_assert_eq(a2.animal, dog); + cr_assert_eq(a1.is_true, true); + cr_assert_eq(a2.is_true, true); + cr_assert_eq(a3.is_true, false); } diff --git a/test_std_allocator.c b/test_std_allocator.c index 8dafcaa..aac07f3 100644 --- a/test_std_allocator.c +++ b/test_std_allocator.c @@ -3,10 +3,10 @@ // TODO rename std to forever allocator Test(std_allocator, test) { - allocator_t this = forever_allocator(); - void *ptr = allocator_alloc(this, 10); - cr_assert(ptr != ((void *)0), "non null from malloc"); - void *new_ptr = allocator_resize(this, ptr, 1024*1024*500); - cr_assert(new_ptr != ((void *)0), "non null from realloc"); - cr_assert(new_ptr != ptr, "realloc is not the same ptr as malloc"); + allocator_t this = forever_allocator(); + void *ptr = allocator_alloc(this, 10); + cr_assert(ptr != ((void *)0), "non null from malloc"); + void *new_ptr = allocator_resize(this, ptr, 1024*1024*500); + cr_assert(new_ptr != ((void *)0), "non null from realloc"); + cr_assert(new_ptr != ptr, "realloc is not the same ptr as malloc"); }