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);