apfl/src/internal.h
Laria Carolin Chabowski ebf3fc89ff Introduce allocator abstraction
We now no longer call malloc/free/... directly, but use an allocator object
that is passed around.

This was mainly done as a preparation for a garbage collector: The
collector will need to know, how much memory we're using, introducing the
collector abstraction will allow the GC to hook into the memory allocation
and observe the memory usage.

This has other potential applications:

- We could now be embedded into applications that can't use the libc
  allocator.
- There could be an allocator that limits the total amount of used memory,
  e.g. for sandboxing purposes.
- In our tests we could use this to simulate out of memory conditions
  (implement an allocator that fails at the n-th allocation, increase n by
  one and restart the test until there are no more faked OOM conditions).

The function signature of the allocator is basically exactly the same as
the one Lua uses.
2022-02-08 22:53:13 +01:00

98 lines
4.3 KiB
C

#ifndef APFL_INTERNAL_H
#define APFL_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#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)
// Internal use only functions
void apfl_print_indented(unsigned indent, FILE *, const char* fmt, ...);
/* Decrease a refererence count. Returns true, if the object should be freed.
*/
bool apfl_refcount_dec(unsigned *);
#ifdef __cplusplus
}
#endif
#endif