Mercurial > molko
changeset 510:21d2c66f3521
core: doxygenize alloc
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 04 Mar 2023 10:06:07 +0100 |
parents | a11cd7ea3a37 |
children | a1b118127f47 |
files | libmlk-core/mlk/core/alloc.c libmlk-core/mlk/core/alloc.h |
diffstat | 2 files changed, 179 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/libmlk-core/mlk/core/alloc.c Sat Mar 04 08:52:57 2023 +0100 +++ b/libmlk-core/mlk/core/alloc.c Sat Mar 04 10:06:07 2023 +0100 @@ -134,6 +134,7 @@ reallocate(void *ptr, size_t n, int zero) { assert(ptr); + assert(n); struct block *b = blockat(ptr); size_t osize = b->n * b->w;
--- a/libmlk-core/mlk/core/alloc.h Sat Mar 04 08:52:57 2023 +0100 +++ b/libmlk-core/mlk/core/alloc.h Sat Mar 04 10:06:07 2023 +0100 @@ -48,19 +48,76 @@ * The structure is allocated using the [flexible array member][fam] to avoid * allocating data twice. * - * Example: + * ### Example: allocating three ints + * + * Use the ::mlk_alloc_new function to allocate three ints with uninitialized + * memory. + * + * ```c + * int *ptr = mlk_alloc_new(3, sizeof (int)); + * + * ptr[0] = 10; + * ptr[1] = 20; + * ptr[2] = 30; + * ``` + * + * This generates the following blocks in memory. * - * Allocating three ints with `int *ptr = mlk_alloc_new(3, sizeof (int))` will - * create a block as following: + * ``` + * +-----------------+----------------+------------------------+ + * | What | Value | Description | + * +-----------------+----------------+------------------------+ + * | size_t | 3 | Three `int` requested | + * | size_t | sizeof (int) | Size of one `int` | + * | unsigned char * | undefined | Content of user memory | + * +-----------------+----------------+------------------------+ + * ``` + * + * \warning The returned address is the `unsigned char *` so the user must + * never free this address directly. + * + * If you use ::mlk_alloc_renew, the storage will be expanded/shrinked + * automatically without the need to pass the actual size of the array. + * + * ```c + * ptr = mlk_alloc_renew(ptr, 6); * - * | Type | Description | - * |---------------------------|-----------------------------| - * | `size_t` = 3 | Number of items allocated | - * | `size_t` = `sizeof (int)` | Size of individual elements | - * | `unsigned char *` | `int[3]` | + * // Now ptr holds 6 ints. + * // + * // ptr[0], ptr[1], ptr[2] are kept unchanged. + * // ptr[3-5] are uninitialized. + * ``` + * + * The block now looks like this: + * + * ``` + * +-----------------+----------------+------------------------+ + * | What | Value | Description | + * +-----------------+----------------+------------------------+ + * | size_t | 6 | Six `int` requested | + * | size_t | sizeof (int) | Size of one `int` | + * | unsigned char * | undefined | Content of user memory | + * +-----------------+----------------+------------------------+ + * ``` * - * Finally, calling `mlk_alloc_renew(ptr, 6)` will extend the memory for three - * more ints. + * Finally, free the result using ::mlk_alloc_free, DON'T free the pointer + * directly. + * + * ```c + * mlk_alloc_free(ptr); + * ``` + * + * ## Custom allocators + * + * The whole library uses allocators defined in this module when it needs to + * allocate data. By default, C standard `malloc`, `realloc` and `free` are + * used but they call ::mlk_panic in case of memory exhaustion. + * + * Those functions can be overridden through the ::mlk_alloc_set function with a + * set of functions defined in the structure ::mlk_alloc_funcs. + * + * When using custom allocators, it is recommended to call ::mlk_alloc_set as + * early as possible because it will also set internal libraries to use those. * * [fam]: https://en.wikipedia.org/wiki/Flexible_array_member */ @@ -69,9 +126,39 @@ #include "core.h" +/** + * \struct mlk_alloc_funcs + * \brief Custom allocator + */ struct mlk_alloc_funcs { - void *(*alloc)(size_t); + /** + * (read-write) + * + * Allocate the number of bytes uninitialized. + * + * \param size the number of bytes to allocate (always > 0) + * \return a pointer to the allocated memory or NULL on error + */ + void *(*alloc)(size_t size); + + /** + * (read-write) + * + * Realloc the pointer with the new size. + * + * \param ptr the pointer to reallocate (never NULL) + * \param size the new size (always > 0) + * \return a pointer to the allocated memory or NULL on error + */ void *(*realloc)(void *, size_t); + + /** + * (read-write) + * + * Free the pointer memory. + * + * \param ptr the pointer to release + */ void (*free)(void *); }; @@ -85,32 +172,101 @@ MLK_CORE_BEGIN_DECLS +/** + * Replace the memory allocators. + * + * The parameter funcs must be kept alive until the program ends or it is + * replaced with a new value. + * + * \param funcs the new allocator or NULL to re-use the defaults + */ void -mlk_alloc_set(const struct mlk_alloc_funcs *); +mlk_alloc_set(const struct mlk_alloc_funcs *funcs); +/** + * Allocates a block memory. + * + * \param n the number of elements to allocate + * \param w the size of each individual element + * \return whatever the allocator returned + */ void * -mlk_alloc_new(size_t, size_t); +mlk_alloc_new(size_t n, size_t w); +/** + * \copydoc mlk_alloc_new + * + * Similar to ::mlk_alloc_new but also ensure the data is zero initialized. + */ void * -mlk_alloc_new0(size_t, size_t); +mlk_alloc_new0(size_t n, size_t w); -void * -mlk_alloc_renew(void *, size_t); - +/** + * Reallocate a block memory. + * + * \note In contrast to standard `realloc` function, it is NOT possible to pass + * a NULL pointer in this function because it needs to know the initial + * block memory size. + * + * \pre ptr != NULL + * \pre n > 0 + * \param ptr the pointer to reallocate + * \param n the new size + * \return whatever the allocator returned to rearrange the pointer memory + */ void * -mlk_alloc_renew0(void *, size_t); +mlk_alloc_renew(void *ptr, size_t n); +/** + * \copydoc mlk_alloc_renew + * + * Similar to ::mlk_alloc_new but also ensure expanded data is zero + * initialized. + */ void * -mlk_alloc_dup(const void *, size_t, size_t); +mlk_alloc_renew0(void *ptr, size_t n); +/** + * Duplicate a memory block. + * + * \pre ptr != NULL + * \param ptr the pointer to copy + * \param n the number of elements to allocate + * \param w the size of each individual element + * \return whatever the allocator returned + */ +void * +mlk_alloc_dup(const void *ptr, size_t n, size_t w); + +/** + * Duplicate a string. + * + * \pre src != NULL + * \param src the string to duplicate + * \return whatever the allocator returned + */ char * -mlk_alloc_sdup(const char *); +mlk_alloc_sdup(const char *src); +/** + * Duplicate a string using a printf(3) format. + * + * \pre fmt != NULL + * \param fmt the printf(3) format string + * \return whatever the allocator returned + */ char * -mlk_alloc_sdupf(const char *, ...); +mlk_alloc_sdupf(const char *fmt, ...); +/** + * Free resources specified by pointer. + * + * If pointer is null, function is no-op. + * + * \param ptr the memory to release (maybe NULL) + */ void -mlk_alloc_free(void *); +mlk_alloc_free(void *ptr); /* alloc_pool functions. */ void