Mercurial > molko
changeset 545:27303e9402de
core: introduce mlk_alloc_expand
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 05 Mar 2023 22:14:02 +0100 |
parents | 0ff9f4a5c364 |
children | b7da58230a66 |
files | libmlk-core/mlk/core/alloc.c libmlk-core/mlk/core/alloc.h tests/test-alloc.c |
diffstat | 3 files changed, 134 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/libmlk-core/mlk/core/alloc.c Sun Mar 05 21:56:51 2023 +0100 +++ b/libmlk-core/mlk/core/alloc.c Sun Mar 05 22:14:02 2023 +0100 @@ -105,9 +105,9 @@ } static inline struct block * -blockat(void *ptr) +blockat(const void *ptr) { - unsigned char *addr = (unsigned char *)ptr; + const unsigned char *addr = (const unsigned char *)ptr; return (struct block *)&addr[-BLKSIZE]; } @@ -145,6 +145,7 @@ #endif b = funcs->realloc(b, BLKSIZE + nsize); + b->n = n; if (zero && nsize > osize) memset(b->data + osize, 0, nsize - osize); @@ -152,6 +153,17 @@ return b->data; } +static inline void * +expand(void *ptr, size_t n, int zero) +{ + struct block *b = blockat(ptr); + + if (n <= b->n) + return ptr; + + return reallocate(ptr, b->n + n, zero); +} + void * mlk_alloc_new(size_t n, size_t w) { @@ -183,6 +195,18 @@ } void * +mlk_alloc_expand(void *ptr, size_t n) +{ + return reallocate(ptr, n, 0); +} + +void * +mlk_alloc_expand0(void *ptr, size_t n) +{ + return expand(ptr, n, 1); +} + +void * mlk_alloc_dup(const void *ptr, size_t n, size_t w) { assert(ptr); @@ -224,6 +248,22 @@ return str; } +size_t +mlk_alloc_getn(const void *ptr) +{ + assert(ptr); + + return blockat(ptr)->n; +} + +size_t +mlk_alloc_getw(const void *ptr) +{ + assert(ptr); + + return blockat(ptr)->w; +} + void mlk_alloc_free(void *ptr) {
--- a/libmlk-core/mlk/core/alloc.h Sun Mar 05 21:56:51 2023 +0100 +++ b/libmlk-core/mlk/core/alloc.h Sun Mar 05 22:14:02 2023 +0100 @@ -76,7 +76,7 @@ * \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 + * If you use ::mlk_alloc_resize, the storage will be expanded/shrinked * automatically without the need to pass the actual size of the array. * * ```c @@ -218,15 +218,38 @@ mlk_alloc_resize(void *ptr, size_t n); /** - * \copydoc mlk_alloc_renew + * \copydoc mlk_alloc_resize * - * Similar to ::mlk_alloc_new but also ensure expanded data is zero + * Similar to ::mlk_alloc_resize but also ensure expanded data is zero * initialized. */ void * mlk_alloc_resize0(void *ptr, size_t n); /** + * Similar to ::mlk_alloc_resize but expands the storage by n. + * + * Example, if the current pointer holds 10 `int`, passing 90 as n argument + * will expand the memory to a total of 100 `int`. + * + * \pre ptr != NULL + * \param ptr the pointer to expand + * \param n the number of items to append + * \return whatever the allocator returned to rearrange the pointer memory + */ +void * +mlk_alloc_expand(void *ptr, size_t n); + +/** + * \copydoc mlk_alloc_expand + * + * Similar to ::mlk_alloc_expand but also ensure expanded data is zero + * initialized. + */ +void * +mlk_alloc_expand0(void *ptr, size_t n); + +/** * Duplicate a memory block. * * \pre ptr != NULL @@ -259,6 +282,26 @@ mlk_alloc_sdupf(const char *fmt, ...); /** + * Get the number of items in ptr. + * + * \pre ptr != NULL + * \param ptr the pointer block + * \return how many number of elements ptr holds + */ +size_t +mlk_alloc_getn(const void *ptr); + +/** + * Get the element width in ptr. + * + * \pre ptr != NULL + * \param ptr the pointer block + * \return size of individual elements ptr holds + */ +size_t +mlk_alloc_getw(const void *ptr); + +/** * Free resources specified by pointer. * * If pointer is null, function is no-op.
--- a/tests/test-alloc.c Sun Mar 05 21:56:51 2023 +0100 +++ b/tests/test-alloc.c Sun Mar 05 22:14:02 2023 +0100 @@ -63,11 +63,13 @@ }; static void -test_basics_array0(void) +test_basics_resize0(void) { struct point *points; points = mlk_alloc_new0(2, sizeof (*points)); + DT_EQ_SIZE(mlk_alloc_getn(points), 2); + DT_EQ_SIZE(mlk_alloc_getw(points), sizeof (*points)); DT_EQ_INT(points[0].x, 0); DT_EQ_INT(points[0].y, 0); DT_EQ_INT(points[1].x, 0); @@ -79,6 +81,8 @@ points[1].y = 40; points = mlk_alloc_resize0(points, 4); + DT_EQ_SIZE(mlk_alloc_getn(points), 4); + DT_EQ_SIZE(mlk_alloc_getw(points), sizeof (*points)); /* Make sure previous are still correct. */ DT_EQ_INT(points[0].x, 10); @@ -94,6 +98,45 @@ } static void +test_basics_expand0(void) +{ + struct point *points; + + points = mlk_alloc_new0(2, sizeof (*points)); + DT_EQ_SIZE(mlk_alloc_getn(points), 2); + DT_EQ_SIZE(mlk_alloc_getw(points), sizeof (*points)); + DT_EQ_INT(points[0].x, 0); + DT_EQ_INT(points[0].y, 0); + DT_EQ_INT(points[1].x, 0); + DT_EQ_INT(points[1].y, 0); + + points[0].x = 10; + points[0].y = 20; + points[1].x = 30; + points[1].y = 40; + + points = mlk_alloc_expand0(points, 4); + DT_EQ_SIZE(mlk_alloc_getn(points), 6); + DT_EQ_SIZE(mlk_alloc_getw(points), sizeof (*points)); + + /* Make sure previous are still correct. */ + DT_EQ_INT(points[0].x, 10); + DT_EQ_INT(points[0].y, 20); + DT_EQ_INT(points[1].x, 30); + DT_EQ_INT(points[1].y, 40); + + /* Now the new items must be zero'ed. */ + DT_EQ_INT(points[2].x, 0); + DT_EQ_INT(points[2].y, 0); + DT_EQ_INT(points[3].x, 0); + DT_EQ_INT(points[3].y, 0); + DT_EQ_INT(points[4].x, 0); + DT_EQ_INT(points[4].y, 0); + DT_EQ_INT(points[5].x, 0); + DT_EQ_INT(points[5].y, 0); +} + +static void test_basics_pool_simple(void) { struct mlk_alloc_pool pool; @@ -170,7 +213,8 @@ int main(void) { - DT_RUN(test_basics_array0); + DT_RUN(test_basics_resize0); + DT_RUN(test_basics_expand0); DT_RUN(test_basics_pool_simple); DT_RUN(test_basics_sdupf); DT_RUN(test_custom_count);