#ifndef APFL_ALLOC_H #define APFL_ALLOC_H #ifdef __cplusplus extern "C" { #endif #include #define ALLOCATOR_CALL(a, oldptr, oldsize, newsize) \ ((a).alloc((a).opaque, (oldptr), (oldsize), (newsize))) #define ALLOC_BYTES(a, n) (((n) == 0) ? NULL : ALLOCATOR_CALL(a, NULL, 0, (n))) #define REALLOC_BYTES(a, ptr, old, new) ALLOCATOR_CALL(a, ptr, old, new) #define FREE_BYTES(a, ptr, n) ALLOCATOR_CALL(a, ptr, n, 0) #define REALLOC_LIST(a, ptr, old, new) REALLOC_BYTES(a, ptr, sizeof(*ptr) * (old), sizeof(*ptr) * (new)) #define ALLOC_LIST(a, T, len) (T *)ALLOC_BYTES(a, sizeof(T) * (len)) #define FREE_LIST(a, ptr, len) FREE_BYTES(a, ptr, sizeof(*ptr) * (len)) #define ALLOC_OBJ(a, T) ALLOC_LIST(a, T, 1) #define FREE_OBJ(a, ptr) FREE_LIST(a, ptr, 1) #define DEINIT_CAP_LIST(allocator, items, len, cap, item_deinit) \ do { \ if ((items) == NULL) { \ break; \ } \ for (size_t i = 0; i < (len); i++) { \ item_deinit(allocator, &((items)[i])); \ } \ FREE_LIST(allocator, items, cap); \ len = 0; \ cap = 0; \ (items) = NULL; \ } while(0) #define DEINIT_LIST(allocator, items, len, item_deinit) \ do { \ if ((items) == NULL) { \ break; \ } \ for (size_t i = 0; i < (len); i++) { \ item_deinit(allocator, &((items)[i])); \ } \ FREE_LIST(allocator, items, len); \ len = 0; \ (items) = NULL; \ } while(0) #define DEINIT_LIST_WITH_ARGS(allocator, items, len, item_deinit, ...) \ do { \ if ((items) == NULL) { \ break; \ } \ for (size_t i = 0; i < (len); i++) { \ item_deinit(__VA_ARGS__, &((items)[i])); \ } \ FREE_LIST(allocator, items, len); \ len = 0; \ (items) = NULL; \ } while(0) #define DEINIT_CAP_LIST_WITH_ARGS(allocator, items, len, cap, item_deinit, ...) \ do { \ if ((items) == NULL) { \ break; \ } \ for (size_t i = 0; i < (len); i++) { \ item_deinit(__VA_ARGS__, &((items)[i])); \ } \ FREE_LIST(allocator, items, cap); \ len = 0; \ cap = 0; \ (items) = NULL; \ } while(0) #define MOVEPTR(out, in) \ do { \ out = in; \ in = NULL; \ } while(0) // DESTROY destroys a dynamically allocated value. // It will first deinit the value using deiniter, // free the memory and then set the variable to NULL. // It is always allowed to destroy an already destroyed // or deinited value. #define DESTROY(allocator, var, deiniter) \ do { \ if ((var) == NULL) { \ break; \ } \ deiniter(allocator, var); \ FREE_OBJ(allocator, var); \ (var) = NULL; \ } while(0) #ifdef __cplusplus } #endif #endif