diff options
Diffstat (limited to 'source/kit/allocator.c')
-rw-r--r-- | source/kit/allocator.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/source/kit/allocator.c b/source/kit/allocator.c new file mode 100644 index 0000000..e1446ac --- /dev/null +++ b/source/kit/allocator.c @@ -0,0 +1,201 @@ +#include "allocator.h" + +#include <assert.h> +#include <string.h> + +#ifndef KIT_DISABLE_SYSTEM_MALLOC +# include <stdlib.h> +#endif + +static void *kit_allocate_default_(i32 request, i64 size, + i64 previous_size, void *pointer) { +#ifndef KIT_DISABLE_SYSTEM_MALLOC + switch (request) { + case KIT_ALLOCATE: + case KIT_ALLOCATE_ZERO: { + assert(size >= 0); + assert(previous_size == 0); + assert(pointer == NULL); + + if (size <= 0) + return NULL; + + void *p = malloc(size); + + if (p != NULL && request == KIT_ALLOCATE_ZERO) + memset(p, 0, size); + + return p; + } + + case KIT_REALLOCATE: + case KIT_REALLOCATE_ZERO: { + assert(size >= 0); + assert(previous_size != 0 || pointer == NULL); + assert(previous_size == 0 || pointer != NULL); + + if (previous_size == 0 && pointer != NULL) + return NULL; + if (previous_size != 0 && pointer == NULL) + return NULL; + if (size == previous_size) + return pointer; + + u8 *p = NULL; + + if (size > 0) { + p = (u8 *) malloc(size); + + if (p != NULL) { + if (size > 0 && previous_size > 0) + memcpy(p, pointer, + size < previous_size ? size : previous_size); + if (request == KIT_REALLOCATE_ZERO && size > previous_size) + memset(p + previous_size, 0, size - previous_size); + } + } + + free(pointer); + + return p; + } + + case KIT_DEALLOCATE: + assert(size == 0); + assert(pointer != NULL); + if (pointer != NULL) + free(pointer); + return NULL; + + case KIT_DEALLOCATE_ALL: + // Do nothing. + // + return NULL; + + default:; + } +#endif + + assert(0); + return NULL; +} + +static void *kit_allocate_from_buffer_(kit_allocator_t *alloc, + i32 request, i64 size, + i64 previous_size, + void *pointer) { + assert(alloc != NULL); + assert(pointer == NULL || pointer < alloc->data); + + if (alloc == NULL) + return NULL; + + switch (request) { + case KIT_ALLOCATE: + case KIT_ALLOCATE_ZERO: { + assert(size >= 0); + assert(previous_size == 0); + assert(pointer == NULL); + + if (size <= 0) + return NULL; + + if (alloc->size < size) + return NULL; + + void *p = alloc->data; + alloc->bytes += size; + alloc->size -= size; + + if (request == KIT_ALLOCATE_ZERO) + memset(p, 0, size); + + return p; + } + + case KIT_REALLOCATE: + case KIT_REALLOCATE_ZERO: { + assert(size >= 0); + assert(previous_size != 0 || pointer == NULL); + assert(previous_size == 0 || pointer != NULL); + + if (size <= 0) + return NULL; + if (size <= previous_size) + return pointer; + if (previous_size == 0 && pointer != NULL) + return NULL; + if (previous_size != 0 && pointer == NULL) + return NULL; + + if ((u8 *) pointer + previous_size == alloc->data) { + if (alloc->size < size - previous_size) + return NULL; + alloc->bytes += size - previous_size; + alloc->size -= size - previous_size; + return pointer; + } + + if (alloc->size < size) + return NULL; + + u8 *p = alloc->bytes; + alloc->bytes += size; + alloc->size -= size; + + if (previous_size > 0) + memcpy(p, pointer, previous_size); + if (request == KIT_REALLOCATE_ZERO) + memset(p + previous_size, 0, size - previous_size); + + return p; + } + + case KIT_DEALLOCATE: + case KIT_DEALLOCATE_ALL: return NULL; + + default:; + } + + assert(0); + return NULL; +} +#ifndef KIT_ENABLE_CUSTOM_ALLOC_DISPATCH +void *kit_alloc_dispatch(kit_allocator_t *alloc, i32 request, + i64 size, i64 previous_size, void *pointer) { + if (alloc == NULL) + return kit_allocate_default_(request, size, previous_size, + pointer); + + switch (alloc->type) { + case KIT_ALLOC_TYPE_DEFAULT: + return kit_allocate_default_(request, size, previous_size, + pointer); + + case KIT_ALLOC_TYPE_BUFFER: + return kit_allocate_from_buffer_(alloc, request, + // alignment + ((size + 7) / 8) * 8, + previous_size, pointer); + + default:; + } + + return NULL; +} +#endif + +kit_allocator_t kit_alloc_default(void) { + kit_allocator_t alloc = { .type = KIT_ALLOC_TYPE_DEFAULT, + .size = 0, + .data = NULL }; + return alloc; +} + +kit_allocator_t kit_alloc_buffer(i64 size, void *buffer) { + kit_allocator_t alloc = { .type = KIT_ALLOC_TYPE_BUFFER, + .size = size, + .data = buffer }; + + return alloc; +} |