changeset 442:9c3b3935f0aa

core: rework allocations
author David Demelier <markand@malikania.fr>
date Thu, 03 Nov 2022 21:09:25 +0100
parents 31c1bbc33813
children dfc65293d984
files GNUmakefile libmlk-core/mlk/core/action-stack.c libmlk-core/mlk/core/action-stack.h libmlk-core/mlk/core/alloc.c libmlk-core/mlk/core/alloc.h libmlk-core/mlk/core/buf.c libmlk-core/mlk/core/buf.h libmlk-core/mlk/core/sys.c libmlk-rpg/mlk/rpg/battle-bar-default.c libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c libmlk-rpg/mlk/rpg/battle-entity-state-moving.c libmlk-rpg/mlk/rpg/battle-state-ai.c libmlk-rpg/mlk/rpg/battle-state-attacking.c libmlk-rpg/mlk/rpg/battle-state-check.c libmlk-rpg/mlk/rpg/battle-state-closing.c libmlk-rpg/mlk/rpg/battle-state-item.c libmlk-rpg/mlk/rpg/battle-state-lost.c libmlk-rpg/mlk/rpg/battle-state-menu.c libmlk-rpg/mlk/rpg/battle-state-opening.c libmlk-rpg/mlk/rpg/battle-state-rendering.c libmlk-rpg/mlk/rpg/battle-state-selection.c libmlk-rpg/mlk/rpg/battle-state-victory.c libmlk-rpg/mlk/rpg/battle.c libmlk-rpg/mlk/rpg/battle.h libmlk-rpg/mlk/rpg/map-file.c libmlk-rpg/mlk/rpg/map.c libmlk-rpg/mlk/rpg/map.h libmlk-rpg/mlk/rpg/tileset-file.c man/mlk-alloc.3 man/mlk_alloc_array.3 man/mlk_alloc_new.3 man/mlk_alloc_set.3 tests/test-action.c tests/test-alloc.c
diffstat 35 files changed, 389 insertions(+), 707 deletions(-) [+]
line wrap: on
line diff
--- a/GNUmakefile	Mon Oct 24 21:29:39 2022 +0200
+++ b/GNUmakefile	Thu Nov 03 21:09:25 2022 +0100
@@ -184,7 +184,6 @@
                         libmlk-core/mlk/core/action.c \
                         libmlk-core/mlk/core/alloc.c \
                         libmlk-core/mlk/core/animation.c \
-                        libmlk-core/mlk/core/buf.c \
                         libmlk-core/mlk/core/clock.c \
                         libmlk-core/mlk/core/core.c \
                         libmlk-core/mlk/core/drawable-stack.c \
@@ -413,20 +412,6 @@
 
 # }}}
 
-# {{{ manual pages
-
-MAN3 :=         man/mlk-action.3 \
-                man/mlk-alloc.3 \
-                man/mlk-err.3 \
-                man/mlk_err_string.3
-                man/mlk_action_draw.3 \
-                man/mlk_action_end.3 \
-                man/mlk_action_finish.3 \
-                man/mlk_action_handle.3 \
-                man/mlk_action_update.3
-
-# }}}
-
 doc:
 	cd doc && mkdocs build
 
@@ -443,7 +428,7 @@
 	cp -R libmlk-ui/mlk/ui/*.h $(DESTDIR)$(INCDIR)/mlk/ui
 	cp -R libmlk-rpg/mlk/rpg/*.h $(DESTDIR)$(INCDIR)/mlk/rpg
 	mkdir -p $(DESTDIR)$(MANDIR)/man3
-	cp $(MAN3) $(DESTDIR)$(MANDIR)/man3
+	cp man/*.3 $(DESTDIR)$(MANDIR)/man3
 
 clean:
 	rm -f $(MLK_BCC) $(MLK_MAP) $(MLK_TILESET)
--- a/libmlk-core/mlk/core/action-stack.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-core/mlk/core/action-stack.c	Thu Nov 03 21:09:25 2022 +0100
@@ -23,11 +23,11 @@
 #include "action.h"
 #include "err.h"
 
-#define ACTION_FOREACH(st, iter) \
+#define FOREACH(st, iter) \
 	for (size_t i = 0; i < (st)->actionsz && ((iter) = (st)->actions[i], 1); ++i)
 
 void
-action_stack_init(struct action_stack *st, struct mlk_action **actions, size_t actionsz)
+mlk_action_stack_init(struct mlk_action_stack *st, struct mlk_action **actions, size_t actionsz)
 {
 	assert(st);
 
@@ -39,7 +39,7 @@
 }
 
 int
-action_stack_add(struct action_stack *st, struct mlk_action *act)
+mlk_action_stack_add(struct mlk_action_stack *st, struct mlk_action *act)
 {
 	assert(st);
 	assert(act);
@@ -55,20 +55,20 @@
 }
 
 void
-action_stack_handle(struct action_stack *st, const union event *ev)
+mlk_action_stack_handle(struct mlk_action_stack *st, const union event *ev)
 {
 	assert(st);
 	assert(ev);
 
 	struct mlk_action *act;
 
-	ACTION_FOREACH(st, act)
+	FOREACH(st, act)
 		if (act)
 			mlk_action_handle(act, ev);
 }
 
 int
-action_stack_update(struct action_stack *st, unsigned int ticks)
+mlk_action_stack_update(struct mlk_action_stack *st, unsigned int ticks)
 {
 	assert(st);
 
@@ -88,29 +88,29 @@
 	 * We process all actions again in case the user modified the stack
 	 * within their update function.
 	 */
-	return action_stack_completed(st);
+	return mlk_action_stack_completed(st);
 }
 
 void
-action_stack_draw(const struct action_stack *st)
+mlk_action_stack_draw(const struct mlk_action_stack *st)
 {
 	assert(st);
 
 	struct mlk_action *act;
 
-	ACTION_FOREACH(st, act)
+	FOREACH(st, act)
 		if (act)
 			mlk_action_draw(act);
 }
 
 int
-action_stack_completed(const struct action_stack *st)
+mlk_action_stack_completed(const struct mlk_action_stack *st)
 {
 	assert(st);
 
 	struct mlk_action *act;
 
-	ACTION_FOREACH(st, act)
+	FOREACH(st, act)
 		if (act)
 			return 0;
 
@@ -118,13 +118,13 @@
 }
 
 void
-action_stack_finish(struct action_stack *st)
+mlk_action_stack_finish(struct mlk_action_stack *st)
 {
 	assert(st);
 
 	struct mlk_action *act;
 
-	ACTION_FOREACH(st, act) {
+	FOREACH(st, act) {
 		if (act) {
 			mlk_action_end(act);
 			mlk_action_finish(act);
--- a/libmlk-core/mlk/core/action-stack.h	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-core/mlk/core/action-stack.h	Thu Nov 03 21:09:25 2022 +0100
@@ -27,7 +27,7 @@
 
 union event;
 
-struct action_stack {
+struct mlk_action_stack {
 	struct mlk_action **actions;
 	size_t actionsz;
 };
@@ -35,25 +35,25 @@
 CORE_BEGIN_DECLS
 
 void
-action_stack_init(struct action_stack *, struct mlk_action **, size_t);
+mlk_action_stack_init(struct mlk_action_stack *, struct mlk_action **, size_t);
 
 int
-action_stack_add(struct action_stack *, struct mlk_action *);
+mlk_action_stack_add(struct mlk_action_stack *, struct mlk_action *);
 
 void
-action_stack_handle(struct action_stack *, const union event *);
+mlk_action_stack_handle(struct mlk_action_stack *, const union event *);
 
 int
-action_stack_update(struct action_stack *, unsigned int);
+mlk_action_stack_update(struct mlk_action_stack *, unsigned int);
 
 void
-action_stack_draw(const struct action_stack *);
+mlk_action_stack_draw(const struct mlk_action_stack *);
 
 int
-action_stack_completed(const struct action_stack *);
+mlk_action_stack_completed(const struct mlk_action_stack *);
 
 void
-action_stack_finish(struct action_stack *);
+mlk_action_stack_finish(struct mlk_action_stack *);
 
 CORE_END_DECLS
 
--- a/libmlk-core/mlk/core/alloc.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-core/mlk/core/alloc.c	Thu Nov 03 21:09:25 2022 +0100
@@ -24,11 +24,17 @@
 #include <SDL.h>
 
 #include "alloc.h"
-#include "buf.h"
 #include "error.h"
 #include "panic.h"
 
 #define OOM_MSG "out of memory"
+#define BLKSIZE (offsetof (struct block, data))
+
+struct block {
+	size_t n;
+	size_t w;
+	unsigned char data[];
+};
 
 static void *
 panic_alloc(size_t size)
@@ -58,6 +64,32 @@
 	.free = free
 };
 
+static void *
+wrap_sdl_malloc(size_t s)
+{
+	return funcs->alloc(s);
+}
+
+static void *
+wrap_sdl_calloc(size_t n, size_t w)
+{
+	const size_t s = n * w;
+
+	return memset(funcs->alloc(s), 0, s);
+}
+
+static void *
+wrap_sdl_realloc(void *mem, size_t s)
+{
+	return funcs->realloc(mem, s);
+}
+
+static void
+wrap_sdl_free(void *mem)
+{
+	funcs->free(mem);
+}
+
 void
 mlk_alloc_set(const struct mlk_alloc_funcs *newfuncs)
 {
@@ -69,75 +101,93 @@
 	funcs = newfuncs;
 
 	/* Change SDL allocators as well. */
-	SDL_SetMemoryFunctions(mlk_alloc_new, mlk_alloc_array0, mlk_alloc_renew, free);
+	SDL_SetMemoryFunctions(wrap_sdl_malloc, wrap_sdl_calloc,
+	    wrap_sdl_realloc, wrap_sdl_free);
 }
 
-void *
-mlk_alloc_new(size_t size)
+static inline struct block *
+blockat(void *ptr)
 {
-	assert(size != 0);
-
-	return funcs->alloc(size);
+	return ptr - BLKSIZE;
 }
 
-void *
-mlk_alloc_new0(size_t size)
+static inline void *
+allocate(size_t n, size_t w, int zero)
 {
-	assert(size != 0);
+	struct block *b;
+	size_t s = n * w;
+
+	// TODO: overflow check.
 
-	return memset(funcs->alloc(size), 0, size);
+	b = funcs->alloc(BLKSIZE + s);
+	b->n = n;
+	b->w = w;
+
+	if (zero)
+		memset(b->data, 0, s);
+
+	return b->data;
 }
 
-void *
-mlk_alloc_array(size_t len, size_t elemsize)
+static inline void *
+reallocate(void *ptr, size_t n, int zero)
 {
-	assert(len != 0);
-	assert(elemsize != 0);
+	assert(ptr);
+
+	struct block *b = blockat(ptr);
+	size_t osize = b->n * b->w;
+	size_t nsize = (b->n + n) * b->w;
 
-	return funcs->alloc(len * elemsize);
+#if !defined(NDEBUG)
+	assert(SIZE_MAX - osize >= nsize);
+#endif
+
+	b = funcs->realloc(b, BLKSIZE + nsize);
+
+	if (zero && nsize > osize)
+		memset(b->data + osize, 0, nsize - osize);
+
+	return b->data;
 }
 
 void *
-mlk_alloc_array0(size_t len, size_t elemsize)
+mlk_alloc_new(size_t n, size_t w)
 {
-	assert(len != 0);
-	assert(elemsize != 0);
+	assert(n);
+	assert(w);
 
-	return mlk_alloc_new0(len * elemsize);
+	return allocate(n, w, 0);
 }
 
 void *
-mlk_alloc_renew(void *ptr, size_t size)
+mlk_alloc_new0(size_t n, size_t w)
 {
-	return funcs->realloc(ptr, size);
+	assert(n);
+	assert(w);
+
+	return allocate(n, w, 1);
 }
 
 void *
-mlk_alloc_rearray(void *ptr, size_t len, size_t elemsize)
+mlk_alloc_renew(void *ptr, size_t n)
 {
-	assert(elemsize != 0);
-
-	return funcs->realloc(ptr, len * elemsize);
+	return reallocate(ptr, n, 0);
 }
 
 void *
-mlk_alloc_rearray0(void *ptr, size_t oldlen, size_t newlen, size_t elemsize)
+mlk_alloc_renew0(void *ptr, size_t n)
 {
-	ptr = funcs->realloc(ptr, newlen * elemsize);
-
-	if (newlen > oldlen)
-		memset((unsigned char *)ptr + (oldlen * elemsize), 0, (newlen - oldlen) * elemsize);
-
-	return ptr;
+	return reallocate(ptr, n, 1);
 }
 
 void *
-mlk_alloc_dup(const void *ptr, size_t size)
+mlk_alloc_dup(const void *ptr, size_t n, size_t w)
 {
 	assert(ptr);
-	assert(size != 0);
+	assert(n);
+	assert(w);
 
-	return memcpy(funcs->alloc(size), ptr, size);
+	return memcpy(mlk_alloc_new(n, w), ptr, n * w);
 }
 
 char *
@@ -147,38 +197,52 @@
 
 	size_t len = strlen(src) + 1;
 
-	return memcpy(funcs->alloc(len), src, len);
+	return memcpy(mlk_alloc_new(len, 1), src, len);
 }
 
 char *
 mlk_alloc_sdupf(const char *fmt, ...)
 {
-	struct buf buf = {0};
 	va_list ap;
+	char *str;
+	int size;
 
 	va_start(ap, fmt);
-	buf_vprintf(&buf, fmt, ap);
+	size = vsnprintf(NULL, 0, fmt, ap);
 	va_end(ap);
 
-	return buf.data;
+	if (size <= 0)
+		return NULL;
+
+	str = mlk_alloc_new(size + 1, 1);
+	va_start(ap, fmt);
+	vsnprintf(str, size + 1, fmt, ap);
+	va_end(ap);
+
+	return str;
 }
 
 void
 mlk_alloc_free(void *ptr)
 {
-	funcs->free(ptr);
+	if (ptr)
+		funcs->free(blockat(ptr));
 }
 
 void
-mlk_alloc_pool_init(struct mlk_alloc_pool *pool, size_t elemsize, void (*finalizer)(void *))
+mlk_alloc_pool_init(struct mlk_alloc_pool *pool,
+                    size_t poolsize,
+                    size_t elemsize,
+                    void (*finalizer)(void *))
 {
 	assert(pool);
+	assert(poolsize > 0 && (poolsize & (poolsize - 1)) == 0);
 	assert(elemsize != 0);
 
-	pool->data = mlk_alloc_array(MLK_ALLOC_POOL_INIT_DEFAULT, elemsize);
+	pool->data = mlk_alloc_new(poolsize, elemsize);
 	pool->elemsize = elemsize;
 	pool->size = 0;
-	pool->capacity = MLK_ALLOC_POOL_INIT_DEFAULT;
+	pool->capacity = poolsize;
 	pool->finalizer = finalizer;
 }
 
@@ -189,7 +253,7 @@
 
 	if (pool->size >= pool->capacity) {
 		pool->capacity *= 2;
-		pool->data = mlk_alloc_rearray(pool->data, pool->capacity, pool->elemsize);
+		pool->data = mlk_alloc_renew(pool->data, pool->capacity);
 	}
 
 	return ((unsigned char *)pool->data) + pool->size++ * pool->elemsize;
@@ -211,7 +275,7 @@
 
 	void *ptr;
 
-	ptr = mlk_alloc_rearray(pool->data, pool->size, pool->elemsize);
+	ptr = mlk_alloc_renew(pool->data, pool->size);
 	memset(pool, 0, sizeof (*pool));
 
 	return ptr;
@@ -232,6 +296,6 @@
 			pool->finalizer(tab + i * pool->elemsize);
 	}
 
-	free(pool->data);
+	mlk_alloc_free(pool->data);
 	memset(pool, 0, sizeof (*pool));
 }
--- a/libmlk-core/mlk/core/alloc.h	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-core/mlk/core/alloc.h	Thu Nov 03 21:09:25 2022 +0100
@@ -23,9 +23,6 @@
 
 #include "core.h"
 
-/* Must be power of 2. */
-#define MLK_ALLOC_POOL_INIT_DEFAULT (32)
-
 /* Custom allocator. */
 struct mlk_alloc_funcs {
 	void *(*alloc)(size_t);
@@ -49,28 +46,19 @@
 mlk_alloc_set(const struct mlk_alloc_funcs *);
 
 void *
-mlk_alloc_new(size_t);
+mlk_alloc_new(size_t, size_t);
 
 void *
-mlk_alloc_new0(size_t);
-
-void *
-mlk_alloc_array(size_t, size_t);
-
-void *
-mlk_alloc_array0(size_t, size_t);
+mlk_alloc_new0(size_t, size_t);
 
 void *
 mlk_alloc_renew(void *, size_t);
 
 void *
-mlk_alloc_rearray(void *, size_t, size_t);
+mlk_alloc_renew0(void *, size_t);
 
 void *
-mlk_alloc_rearray0(void *, size_t, size_t, size_t);
-
-void *
-mlk_alloc_dup(const void *, size_t);
+mlk_alloc_dup(const void *, size_t, size_t);
 
 char *
 mlk_alloc_sdup(const char *);
@@ -83,7 +71,7 @@
 
 /* alloc_pool functions. */
 void
-mlk_alloc_pool_init(struct mlk_alloc_pool *, size_t , void (*)(void *));
+mlk_alloc_pool_init(struct mlk_alloc_pool *, size_t, size_t , void (*)(void *));
 
 void *
 mlk_alloc_pool_new(struct mlk_alloc_pool *);
--- a/libmlk-core/mlk/core/buf.c	Mon Oct 24 21:29:39 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-/*
- * buf.c -- simple string buffer for C
- *
- * Copyright (c) 2019-2022 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "buf.h"
-
-/*
- * Try to increase the buffer length by a power of two until we have enough
- * space to fit `desired'.
- *
- * Detects overflow and return -1 if happened or reallocation could not
- * occur.
- */
-static int
-growdbl(struct buf *b, size_t desired)
-{
-	size_t newcap = b->capacity;
-	void *newptr;
-
-	while (desired > newcap - b->length) {
-		const size_t r = newcap * 2;
-
-		/* Overflow occured. */
-		if (r / newcap != 2) {
-#if defined(ENOMEM)
-			errno = ENOMEM;
-#endif
-			return -1;
-		}
-
-		newcap = r;
-	}
-
-	/* At this step we must have enough room. */
-	assert(newcap - b->length >= desired);
-
-	/* Pretty much impossible to reach but always assume it's possible. */
-	if (newcap == SIZE_MAX) {
-#if defined(ENOMEM)
-		errno = ENOMEM;
-#endif
-		return -1;
-	}
-
-	if (!(newptr = BUF_REALLOC(b->data, newcap + 1)))
-		return -1;
-
-	b->data = newptr;
-	b->capacity = newcap;
-
-	return 0;
-}
-
-/*
- * Try to allocate just enough space for the `desired' amount of space. This is
- * only used when the buffer is already too large but hasn't reached SIZE_MAX
- * yet.
- *
- * Returns -1 if allocation failed.
- */
-static int
-growmin(struct buf *b, size_t desired)
-{
-	size_t newcap;
-	void *newptr;
-
-	if (desired >= SIZE_MAX - b->length) {
-#if defined(ENOMEM)
-		errno = ENOMEM;
-#endif
-		return -1;
-	}
-
-	/* Don't forget to keep what's remaining between capacity and length. */
-	newcap = b->capacity + (desired - (b->capacity - b->length));
-
-	/* Try to reallocate. */
-	if (!(newptr = BUF_REALLOC(b->data, newcap + 1)))
-		return -1;
-
-	b->data = newptr;
-	b->capacity = newcap;
-
-	return 0;
-}
-
-/*
- * Entry point for reallocating data. Will try to allocate twice until we have
- * enough room and then only the minimal amount.
- */
-static int
-grow(struct buf *b, size_t desired)
-{
-	const size_t avail = b->capacity - b->length;
-
-	if (avail >= desired)
-		return 0;
-
-	if (!b->capacity) {
-		if (!(b->data = BUF_MALLOC(desired + 1)))
-			return -1;
-
-		b->capacity = desired;
-	} else if (growdbl(b, desired) < 0 && growmin(b, desired) < 0)
-		return -1;
-
-	return 0;
-}
-
-void
-buf_init(struct buf *b)
-{
-	assert(b);
-
-	memset(b, 0, sizeof (*b));
-}
-
-int
-buf_reserve(struct buf *b, size_t amount)
-{
-	assert(b);
-
-	if (grow(b, amount) < 0)
-		return -1;
-
-	return 0;
-}
-
-int
-buf_resize(struct buf *b, size_t size, char ch)
-{
-	assert(b);
-
-	/* New size is smaller than curren't length, just update it. */
-	if (size < b->length) {
-		b->data[b->length = size] = 0;
-		return 0;
-	}
-
-	/* New size is bigger, data may be reallocated. */
-	if (grow(b, size - b->length) < 0)
-		return -1;
-
-	memset(&b->data[b->length], ch, size - b->length);
-	b->length = size;
-	b->data[b->length] = 0;
-
-	return 0;
-}
-
-int
-buf_shrink(struct buf *b)
-{
-	assert(b);
-
-	void *newptr;
-
-	if (b->length == 0) {
-		free(b->data);
-		b->data = NULL;
-		b->length = b->capacity = 0;
-		return 0;
-	}
-
-	if (!(newptr = BUF_REALLOC(b->data, b->length + 1)))
-		return -1;
-
-	b->data = newptr;
-	b->capacity = b->length;
-
-	return 0;
-}
-
-void
-buf_erase(struct buf *b, size_t pos, size_t count)
-{
-	assert(b);
-	assert(pos <= b->length);
-
-	if (count > b->length - pos) {
-		/* Optimize whole erase at pos. */
-		b->data[pos] = 0;
-		b->length = pos;
-	} else {
-		memmove(&b->data[pos], &b->data[pos + count], b->length - count);
-		b->length -= count;
-	}
-}
-
-int
-buf_putc(struct buf *b, char c)
-{
-	assert(b);
-
-	if (grow(b, 1) < 0)
-		return -1;
-
-	b->data[b->length++] = c;
-	b->data[b->length] = 0;
-
-	return 0;
-}
-
-int
-buf_puts(struct buf *b, const char *s)
-{
-	assert(b);
-	assert(s);
-
-	const size_t len = strlen(s);
-
-	if (grow(b, len) < 0)
-		return -1;
-
-	memcpy(&b->data[b->length], s, len + 1);
-	b->length += len;
-
-	return 0;
-}
-
-int
-buf_printf(struct buf *b, const char *fmt, ...)
-{
-	assert(b);
-	assert(fmt);
-
-	va_list ap;
-	int ret;
-
-	va_start(ap, fmt);
-	ret = buf_vprintf(b, fmt, ap);
-	va_end(ap);
-
-	return ret;
-}
-
-int
-buf_vprintf(struct buf *b, const char *fmt, va_list args)
-{
-	assert(b);
-	assert(fmt);
-
-	va_list ap;
-	int amount;
-
-	/* Determine length. */
-	va_copy(ap, args);
-	amount = vsnprintf(NULL, 0, fmt, ap);
-	va_end(ap);
-
-	if (amount < 0)
-		return -1;
-
-	/* Do actual copy. */
-	if (grow(b, amount) < 0)
-		return -1;
-
-	va_copy(ap, args);
-	amount = vsprintf(&b->data[b->length], fmt, ap);
-	va_end(ap);
-
-	if (amount < 0)
-		return -1;
-
-	b->length += amount;
-
-	return 0;
-}
-
-int
-buf_sub(struct buf *b, const struct buf *src, size_t pos, size_t count)
-{
-	assert(b);
-	assert(src);
-	assert(pos <= src->length);
-
-	if (count >= src->length)
-		count = src->length - pos;
-	if (!(b->data = BUF_MALLOC(count + 1)))
-		return -1;
-
-	strncpy(b->data, &src->data[pos], count);
-	b->length = count;
-	b->capacity = count;
-	b->data[b->length] = 0;
-
-	return 0;
-}
-
-int
-buf_dup(struct buf *b, const struct buf *src)
-{
-	assert(b);
-	assert(src);
-
-	if (!src->data)
-		return 0;
-	if (!(b->data = BUF_MALLOC(src->length + 1)))
-		return -1;
-
-	memcpy(b->data, src->data, src->length + 1);
-	b->capacity = src->length;
-	b->length = src->length;
-
-	return 0;
-}
-
-void
-buf_clear(struct buf *b)
-{
-	assert(b);
-
-	if (b->data)
-		b->data[b->length = 0] = 0;
-}
-
-void
-buf_finish(struct buf *b)
-{
-	assert(b);
-
-	BUF_FREE(b->data);
-	b->data = NULL;
-	b->capacity = b->length = 0;
-}
--- a/libmlk-core/mlk/core/buf.h	Mon Oct 24 21:29:39 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * buf.h -- simple string buffer for C
- *
- * Copyright (c) 2019-2022 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef BUF_H
-#define BUF_H
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "alloc.h"
-
-#if !defined(BUF_MALLOC)
-#	define BUF_MALLOC mlk_alloc_new
-#endif
-
-#if !defined(BUF_REALLOC)
-#	define BUF_REALLOC mlk_alloc_renew
-#endif
-
-#if !defined(BUF_FREE)
-#	define BUF_FREE mlk_alloc_free
-#endif
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-struct buf {
-	char *data;
-	size_t length;
-	size_t capacity;
-};
-
-void
-buf_init(struct buf *);
-
-int
-buf_reserve(struct buf *, size_t);
-
-int
-buf_resize(struct buf *, size_t, char);
-
-int
-buf_shrink(struct buf *);
-
-void
-buf_erase(struct buf *, size_t, size_t);
-
-int
-buf_putc(struct buf *, char);
-
-int
-buf_puts(struct buf *, const char *);
-
-int
-buf_printf(struct buf *, const char *, ...);
-
-int
-buf_vprintf(struct buf *, const char *, va_list);
-
-int
-buf_sub(struct buf *, const struct buf *, size_t, size_t);
-
-int
-buf_dup(struct buf *, const struct buf *);
-
-void
-buf_clear(struct buf *);
-
-void
-buf_finish(struct buf *);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif /* !BUF_H */
--- a/libmlk-core/mlk/core/sys.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-core/mlk/core/sys.c	Thu Nov 03 21:09:25 2022 +0100
@@ -272,10 +272,10 @@
 	struct audiostream *stream;
 	int ret = 0;
 
-	stream = mlk_alloc_new(sizeof (*stream));
+	stream = mlk_alloc_new(1, sizeof (*stream));
 	stream->samplerate = info->samplerate;
 	stream->samplesz = info->frames * info->channels;
-	stream->samples = mlk_alloc_array(stream->samplesz, sizeof (*stream->samples));
+	stream->samples = mlk_alloc_new(stream->samplesz, sizeof (*stream->samples));
 	stream->format = info->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
 
 	sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
--- a/libmlk-rpg/mlk/rpg/battle-bar-default.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-bar-default.c	Thu Nov 03 21:09:25 2022 +0100
@@ -556,8 +556,7 @@
 
 	(void)bt;
 
-	bar->items = mlk_alloc_rearray0(bar->items, bar->itemsz,
-	    CHARACTER_SPELL_MAX, sizeof (*bar->items));
+	bar->items = mlk_alloc_renew0(bar->items, CHARACTER_SPELL_MAX);
 	bar->itemsz = CHARACTER_SPELL_MAX;
 	bar->state = BATTLE_BAR_DEFAULT_STATE_GRID;
 
--- a/libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-entity-state-attacking.c	Thu Nov 03 21:09:25 2022 +0100
@@ -90,7 +90,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-entity-state-blinking.c	Thu Nov 03 21:09:25 2022 +0100
@@ -87,7 +87,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.finish = finish;
--- a/libmlk-rpg/mlk/rpg/battle-entity-state-moving.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-entity-state-moving.c	Thu Nov 03 21:09:25 2022 +0100
@@ -118,7 +118,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-ai.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-ai.c	Thu Nov 03 21:09:25 2022 +0100
@@ -82,7 +82,7 @@
 
 	struct battle_state *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->data = bt;
 	self->update = update;
 	self->draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-attacking.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-attacking.c	Thu Nov 03 21:09:25 2022 +0100
@@ -165,7 +165,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-check.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-check.c	Thu Nov 03 21:09:25 2022 +0100
@@ -88,7 +88,7 @@
 		return;
 	}
 
-	fade = mlk_alloc_new0(sizeof (*fade));
+	fade = mlk_alloc_new0(1, sizeof (*fade));
 	fade->ch = et->ch;
 	fade->x = et->x;
 	fade->y = et->y;
@@ -197,7 +197,7 @@
 
 	struct battle_state *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->data = bt;
 	self->update = update;
 	self->draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-closing.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-closing.c	Thu Nov 03 21:09:25 2022 +0100
@@ -129,7 +129,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-item.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-item.c	Thu Nov 03 21:09:25 2022 +0100
@@ -136,7 +136,7 @@
 
 	struct self *self;
 
-	self = mlk_alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-lost.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-lost.c	Thu Nov 03 21:09:25 2022 +0100
@@ -123,7 +123,7 @@
 
 	struct self *self;
 
-	self = alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.handle = handle;
 	self->state.update = update;
--- a/libmlk-rpg/mlk/rpg/battle-state-menu.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-menu.c	Thu Nov 03 21:09:25 2022 +0100
@@ -92,7 +92,7 @@
 
 	struct battle_state *state;
 
-	state = alloc_new0(sizeof (*state));
+	state = mlk_alloc_new0(1, sizeof (*state));
 	state->data = bt;
 	state->handle = handle;
 	state->update = update;
--- a/libmlk-rpg/mlk/rpg/battle-state-opening.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-opening.c	Thu Nov 03 21:09:25 2022 +0100
@@ -101,7 +101,7 @@
 
 	struct self *self;
 
-	self = alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-rendering.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-rendering.c	Thu Nov 03 21:09:25 2022 +0100
@@ -103,7 +103,7 @@
 
 	struct self *self;
 
-	self = alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.update = update;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-selection.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-selection.c	Thu Nov 03 21:09:25 2022 +0100
@@ -220,7 +220,7 @@
 
 	struct self *self;
 
-	self = alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.handle = handle;
 	self->state.draw = draw;
--- a/libmlk-rpg/mlk/rpg/battle-state-victory.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle-state-victory.c	Thu Nov 03 21:09:25 2022 +0100
@@ -125,7 +125,7 @@
 	struct self *self;
 
 	/* TODO: compute money, xp and drop. */
-	self = alloc_new0(sizeof (*self));
+	self = mlk_alloc_new0(1, sizeof (*self));
 	self->state.data = self;
 	self->state.handle = handle;
 	self->state.update = update;
--- a/libmlk-rpg/mlk/rpg/battle.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle.c	Thu Nov 03 21:09:25 2022 +0100
@@ -267,8 +267,7 @@
 	struct battle_entity **porder;
 
 	/* Create a pointer list to every entity. */
-	bt->order = alloc_rearray0(bt->order, bt->ordersz,
-	    bt->teamsz + bt->enemiesz, sizeof (*bt->order));
+	bt->order = mlk_alloc_renew0(bt->order, bt->teamsz + bt->enemiesz);
 	bt->ordersz = bt->teamsz + bt->enemiesz;
 	bt->ordercur = porder = bt->order;
 
@@ -395,7 +394,7 @@
 		return;
 	}
 
-	id = alloc_new0(sizeof (*id));
+	id = mlk_alloc_new0(1, sizeof (*id));
 	id->bti.color = BATTLE_INDICATOR_HP_COLOR;
 	id->bti.amount = labs(amount);
 
@@ -422,7 +421,7 @@
 	if (comp & BATTLE_COMPONENT_BAR)
 		battle_bar_handle(bt->bar, bt, ev);
 	if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions)
-		action_stack_handle(bt->actions, ev);
+		mlk_action_stack_handle(bt->actions, ev);
 }
 
 void
@@ -446,7 +445,7 @@
 	if (comp & BATTLE_COMPONENT_BAR)
 		battle_bar_update(bt->bar, bt, ticks);
 	if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions)
-		action_stack_update(bt->actions, ticks);
+		mlk_action_stack_update(bt->actions, ticks);
 	if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects)
 		drawable_stack_update(bt->effects, ticks);
 }
@@ -476,7 +475,7 @@
 	if (comp & BATTLE_COMPONENT_BAR)
 		battle_bar_draw(bt->bar, bt);
 	if ((comp & BATTLE_COMPONENT_ACTIONS) && bt->actions)
-		action_stack_draw(bt->actions);
+		mlk_action_stack_draw(bt->actions);
 	if ((comp & BATTLE_COMPONENT_DRAWABLES) && bt->effects)
 		drawable_stack_draw(bt->effects);
 }
--- a/libmlk-rpg/mlk/rpg/battle.h	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/battle.h	Thu Nov 03 21:09:25 2022 +0100
@@ -81,7 +81,7 @@
 	struct music *music[3];
 	struct theme *theme;
 	struct drawable_stack *effects;
-	struct action_stack *actions;
+	struct mlk_action_stack *actions;
 	struct inventory *inventory;
 	struct battle_bar *bar;
 };
--- a/libmlk-rpg/mlk/rpg/map-file.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/map-file.c	Thu Nov 03 21:09:25 2022 +0100
@@ -66,7 +66,7 @@
 	 * The next line after a layer declaration is a list of plain integer
 	 * that fill the layer tiles.
 	 */
-	if (!(ctx->mf->layers[layer_type].tiles = mlk_alloc_array0(amount, sizeof (unsigned short))))
+	if (!(ctx->mf->layers[layer_type].tiles = mlk_alloc_new0(amount, sizeof (unsigned short))))
 		return -1;
 
 	for (int tile; fscanf(ctx->fp, "%d\n", &tile) && current < amount; ++current)
@@ -275,7 +275,7 @@
 	int ret = 0;
 
 	memset(map, 0, sizeof (*map));
-	mlk_alloc_pool_init(&file->blocks, sizeof (*map->blocks), NULL);
+	mlk_alloc_pool_init(&file->blocks, 16, sizeof (*map->blocks), NULL);
 
 	if (!(ctx.fp = fopen(path, "r")))
 		goto fail;
@@ -301,9 +301,9 @@
 {
 	assert(file);
 
-	free(file->layers[0].tiles);
-	free(file->layers[1].tiles);
-	free(file->layers[2].tiles);
+	mlk_alloc_free(file->layers[0].tiles);
+	mlk_alloc_free(file->layers[1].tiles);
+	mlk_alloc_free(file->layers[2].tiles);
 
 	tileset_file_finish(&file->tileset_file);
 	mlk_alloc_pool_finish(&file->blocks);
--- a/libmlk-rpg/mlk/rpg/map.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/map.c	Thu Nov 03 21:09:25 2022 +0100
@@ -619,8 +619,8 @@
 		break;
 	}
 
-	action_stack_handle(&map->astack_par, ev);
-	action_stack_handle(&map->astack_seq, ev);
+	mlk_action_stack_handle(&map->astack_par, ev);
+	mlk_action_stack_handle(&map->astack_seq, ev);
 }
 
 void
@@ -628,13 +628,13 @@
 {
 	assert(map);
 
-	action_stack_update(&map->astack_par, ticks);
-	action_stack_update(&map->astack_seq, ticks);
+	mlk_action_stack_update(&map->astack_par, ticks);
+	mlk_action_stack_update(&map->astack_seq, ticks);
 
 	tileset_update(map->tileset, ticks);
 
 	/* No movements if the sequential actions are running. */
-	if (action_stack_completed(&map->astack_seq))
+	if (mlk_action_stack_completed(&map->astack_seq))
 		move(map, ticks);
 }
 
@@ -656,8 +656,8 @@
 	draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]);
 	draw_collide(map);
 
-	action_stack_draw(&map->astack_par);
-	action_stack_draw(&map->astack_seq);
+	mlk_action_stack_draw(&map->astack_par);
+	mlk_action_stack_draw(&map->astack_seq);
 }
 
 void
@@ -665,8 +665,8 @@
 {
 	assert(map);
 
-	action_stack_finish(&map->astack_par);
-	action_stack_finish(&map->astack_seq);
+	mlk_action_stack_finish(&map->astack_par);
+	mlk_action_stack_finish(&map->astack_seq);
 
 	memset(map, 0, sizeof (*map));
 }
--- a/libmlk-rpg/mlk/rpg/map.h	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/map.h	Thu Nov 03 21:09:25 2022 +0100
@@ -71,8 +71,8 @@
 	size_t blocksz;                 /*!< (+) Number of collisions. */
 
 	/* List of actions. */
-	struct action_stack astack_par; /*!< (+) Parallel actions. */
-	struct action_stack astack_seq; /*!< (+) Blocking actions. */
+	struct mlk_action_stack astack_par; /*!< (+) Parallel actions. */
+	struct mlk_action_stack astack_seq; /*!< (+) Blocking actions. */
 
 	/* Player. */
 	struct sprite *player_sprite;   /*!< (+) The sprite to use */
--- a/libmlk-rpg/mlk/rpg/tileset-file.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/libmlk-rpg/mlk/rpg/tileset-file.c	Thu Nov 03 21:09:25 2022 +0100
@@ -152,7 +152,7 @@
 	unsigned short id, w, h;
 	struct tileset_tiledef *td;
 
-	mlk_alloc_pool_init(&ctx->tf->tiledefs, sizeof (*td), NULL);
+	mlk_alloc_pool_init(&ctx->tf->tiledefs, 16, sizeof (*td), NULL);
 
 	while (fscanf(ctx->fp, "%hu|%hd|%hd|%hu|%hu\n", &id, &x, &y, &w, &h) == 5) {
 		td = mlk_alloc_pool_new(&ctx->tf->tiledefs);
@@ -181,8 +181,10 @@
 	char filename[FILENAME_MAX + 1];
 	struct tileset_animation_block *anim;
 
-	mlk_alloc_pool_init(&ctx->tf->anims[0], sizeof (struct tileset_animation_block), tileset_animation_block_finish);
-	mlk_alloc_pool_init(&ctx->tf->anims[1], sizeof (struct tileset_animation), NULL);
+	mlk_alloc_pool_init(&ctx->tf->anims[0], 16,
+	    sizeof (struct tileset_animation_block), tileset_animation_block_finish);
+	mlk_alloc_pool_init(&ctx->tf->anims[1], 16,
+	    sizeof (struct tileset_animation), NULL);
 
 	/*
 	 * 1. Create the first array of animation, sprite and texture that are
--- a/man/mlk-alloc.3	Mon Oct 24 21:29:39 2022 +0200
+++ b/man/mlk-alloc.3	Thu Nov 03 21:09:25 2022 +0100
@@ -5,25 +5,9 @@
 .Nm mlk-alloc
 .Nd allocation routines
 .Sh LIBRARY
-.Lb libmlk-core
+libmlk-core (-lmlk-core)
 .Sh SYNOPSIS
 .In mlk/core/alloc.h
-.Ft void
-.Fn mlk_alloc_set "const struct mlk_alloc_funcs *funcs"
-.Ft void *
-.Fn mlk_alloc_new "size_t size"
-.Ft void *
-.Fn mlk_alloc_new0 "size_t size"
-.Ft void *
-.Fn mlk_alloc_array "size_t len" "size_t elemsize"
-.Ft void *
-.Fn mlk_alloc_array0 "size_t len" "size_t elemsize"
-.Ft void *
-.Fn mlk_alloc_renew "void *ptr" "size_t size"
-.Ft void *
-.Fn mlk_alloc_rearray "void *ptr" "size_t newlen" "size_t elemsize"
-.Ft void *
-.Fn mlk_alloc_rearray0 "void *ptr" "size_t oldlen" "size_t newlen" "size_t elemsize"
 .Ft void *
 .Fn mlk_alloc_dup "const void *ptr" "size_t size"
 .Ft char *
@@ -116,62 +100,6 @@
 .El
 .Pp
 The
-.Fn mlk_alloc_set
-function changes allocator functions to
-.Fa funcs
-allocator routines. It must be kept valid until the program is no longer used.
-.Pp
-The
-.Fn mlk_alloc_new
-and
-.Fn mlk_alloc_new0
-function allocates memory data of the given
-.Fa size .
-The
-.Fn mlk_alloc_new0
-variant ensure the data is being zero-initialized.
-.Pp
-The
-.Fn mlk_alloc_array
-and
-.Fn mlk_alloc_array0
-functions allocate an array of
-.Fa len
-elements of
-.Fa elemsize
-individually.
-The
-.Fn mlk_alloc_array0
-variant ensure the data is being zero-initialized.
-.Pp
-The
-.Fn mlk_alloc_renew
-function reallocates the pointer
-.Fa ptr
-(which may be NULL) to the new
-.Fa size
-which can be 0.
-.Pp
-The
-.Fn mlk_alloc_rearray
-function reallocates the pointer
-.Fa ptr
-(which may be NULL) as an array of
-.Fa newlen
-elements of
-.Fa elemsize
-individually.
-.Pp
-The
-.Fn mlk_alloc_rearray0
-function is similar to
-.Fn mlk_alloc_rearray
-but zero-initialize the memory. It needs the previous length given in
-.Fa oldlen
-argument because the function would not know which memory region to zero
-initialize when increasing the memory.
-.Pp
-The
 .Fn mlk_alloc_dup
 function duplicates the pointer
 .Fa ptr
@@ -309,7 +237,10 @@
 	point_draw(&points[i]);
 .Ed
 .Sh SEE ALSO
-.Xr mlk-panic 3
+.Xr mlk-panic 3 ,
+.Xr mlk_alloc_array.3 ,
+.Xr mlk_alloc_new.3 ,
+.Xr mlk_alloc_set.3
 .Sh AUTHORS
 The
 .Nm
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/man/mlk_alloc_array.3	Thu Nov 03 21:09:25 2022 +0100
@@ -0,0 +1,65 @@
+.Dd $Mdocdate$
+.Dt MLK_ALLOC_ARRAY 3
+.Os
+.Sh NAME
+.Nm mlk_alloc_array ,
+.Nm mlk_alloc_array0 ,
+.Nm mlk_alloc_rearray ,
+.Nm mlk_alloc_rearray0
+.Nd safe array allocation
+.Sh LIBRARY
+libmlk-core (-lmlk-core)
+.Sh SYNOPSIS
+.In mlk/core/alloc.h
+.Ft void *
+.Fn mlk_alloc_array "size_t len, size_t elemsize"
+.Ft void *
+.Fn mlk_alloc_array0 "size_t len, size_t elemsize"
+.Ft void *
+.Fn mlk_alloc_rearray "void *ptr, size_t newlen, size_t elemsize"
+.Ft void *
+.Fn mlk_alloc_rearray0 "void *ptr, size_t oldlen, size_t newlen, size_t elemsize"
+.Sh DESCRIPTION
+These functions are designed to safely allocate arrays. They take an amount of
+objects to allocate and their individual sizes, the function ensuress that the
+multiplication does not overflow.
+.Pp
+The
+.Fn mlk_alloc_array
+and
+.Fn mlk_alloc_array0
+functions allocate an array of
+.Fa len
+elements of
+.Fa elemsize
+individually.
+The
+.Fn mlk_alloc_array0
+variant ensure the data is being zero-initialized.
+.Pp
+The
+.Fn mlk_alloc_rearray
+function reallocates the pointer
+.Fa ptr
+(which may be NULL) as an array of
+.Fa newlen
+elements of
+.Fa elemsize
+individually.
+.Pp
+The
+.Fn mlk_alloc_rearray0
+function is similar to
+.Fn mlk_alloc_rearray
+but zero-initialize the memory. It needs the previous length given in
+.Fa oldlen
+argument because the function would not know which memory region to zero
+initialize when increasing the memory.
+.Sh RETURN VALUES
+All functions return a pointer to the memory according to the current
+allocation strategy.
+.Sh SEE ALSO
+.Xr mlk-alloc 3 ,
+.Xr mlk_alloc_set 3
+.Sh AUTHORS
+.An David Demelier Aq Mt markand@malikania.fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/man/mlk_alloc_new.3	Thu Nov 03 21:09:25 2022 +0100
@@ -0,0 +1,56 @@
+.Dd $Mdocdate$
+.Dt MLK_ALLOC_NEW 3
+.Os
+.Sh NAME
+.Nm mlk_alloc_new ,
+.Nm mlk_alloc_new0 ,
+.Nm mlk_alloc_renew ,
+.Nm mlk_alloc_renew0
+.Nd allocate memory
+.Sh LIBRARY
+libmlk-core (-lmlk-core)
+.Sh SYNOPSIS
+.In mlk/core/alloc.h
+.Ft void *
+.Fn mlk_alloc_new "size_t size"
+.Ft void *
+.Fn mlk_alloc_new0 "size_t size"
+.Ft void *
+.Fn mlk_alloc_renew "void *ptr, size_t size"
+.Ft void *
+.Fn mlk_alloc_renew0 "void *ptr, size_t oldsize, size_t newsize"
+.Sh DESCRIPTION
+.Pp
+The
+.Fn mlk_alloc_new
+and
+.Fn mlk_alloc_new0
+functions allocate memory data of the given
+.Fa size .
+The
+.Fn mlk_alloc_new0
+variant ensure the data is being zero-initialized.
+.Pp
+The
+.Fn mlk_alloc_renew
+function reallocates the pointer
+.Fa ptr
+according to its
+.Fa size .
+.Pp
+The
+.Fn mlk_alloc_renew0
+function is similar to
+.Fn mlk_alloc_renew
+but zero-initialize the memory. It needs the previous size given in
+.Fa oldsize
+argument because the function would not know which memory region to zero
+initialize when increasing the memory.
+.Sh RETURN VALUES
+All functions return a pointer to the memory according to the current
+allocation strategy.
+.Sh SEE ALSO
+.Xr mlk-alloc 3 ,
+.Xr mlk_alloc_set 3
+.Sh AUTHORS
+.An David Demelier Aq Mt markand@malikania.fr .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/man/mlk_alloc_set.3	Thu Nov 03 21:09:25 2022 +0100
@@ -0,0 +1,30 @@
+.Dd $Mdocdate$
+.Dt MLK_ALLOC_SET 3
+.Os
+.Sh NAME
+.Nm mlk_alloc_set
+.Nd allocation routines
+.Sh LIBRARY
+libmlk-core (-lmlk-core)
+.Sh SYNOPSIS
+.In mlk/core/alloc.h
+.Ft void
+.Fn mlk_alloc_set "const struct mlk_alloc_funcs *funcs"
+.Sh DESCRIPTION
+Change allocation routines for the entire framework and its underlying
+libraries.
+.Pp
+The
+.Fn mlk_alloc_set
+function changes allocator functions to
+.Fa funcs
+allocator routines. It must be kept valid until the program is no longer used.
+See the
+.Xr mlk-alloc 3
+manual page for the
+.Vt mlk_alloc_funcs
+type definition.
+.Sh SEE ALSO
+.Xr mlk-alloc 3
+.Sh AUTHORS
+.An David Demelier Aq Mt markand@malikania.fr .
--- a/tests/test-action.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/tests/test-action.c	Thu Nov 03 21:09:25 2022 +0100
@@ -180,19 +180,19 @@
 test_stack_add(void)
 {
 	struct mlk_action *actions[10];
-	struct action_stack st = {0};
+	struct mlk_action_stack st = {0};
 	struct mlk_action act = {0};
 
-	action_stack_init(&st, actions, 10);
+	mlk_action_stack_init(&st, actions, 10);
 
-	DT_EQ_INT(action_stack_add(&st, &act), 0);
+	DT_EQ_INT(mlk_action_stack_add(&st, &act), 0);
 
 	/* Now fill up. */
 	for (int i = 0; i < 9; ++i)
-		DT_EQ_INT(action_stack_add(&st, &act), 0);
+		DT_EQ_INT(mlk_action_stack_add(&st, &act), 0);
 
 	/* This one should not fit in. */
-	DT_EQ_INT(action_stack_add(&st, &act), MLK_ERR_NO_MEM);
+	DT_EQ_INT(mlk_action_stack_add(&st, &act), MLK_ERR_NO_MEM);
 }
 
 static void
@@ -208,13 +208,13 @@
 	};
 
 	struct mlk_action *actions[10];
-	struct action_stack st = {0};
+	struct mlk_action_stack st = {0};
 
-	action_stack_init(&st, actions, 10);
-	action_stack_add(&st, &table[0].act);
-	action_stack_add(&st, &table[1].act);
-	action_stack_add(&st, &table[2].act);
-	action_stack_handle(&st, &dummy);
+	mlk_action_stack_init(&st, actions, 10);
+	mlk_action_stack_add(&st, &table[0].act);
+	mlk_action_stack_add(&st, &table[1].act);
+	mlk_action_stack_add(&st, &table[2].act);
+	mlk_action_stack_handle(&st, &dummy);
 
 	DT_ASSERT(table[0].called);
 	DT_ASSERT(table[1].called);
@@ -238,18 +238,18 @@
 	};
 
 	struct mlk_action *actions[10];
-	struct action_stack st = {0};
+	struct mlk_action_stack st = {0};
 
-	action_stack_init(&st, actions, 10);
-	action_stack_add(&st, &table[0].act);
-	action_stack_add(&st, &table[1].act);
-	action_stack_add(&st, &table[2].act);
-	action_stack_add(&st, &table[3].act);
-	action_stack_add(&st, &table[4].act);
-	action_stack_add(&st, &table[5].act);
-	action_stack_add(&st, &table[6].act);
+	mlk_action_stack_init(&st, actions, 10);
+	mlk_action_stack_add(&st, &table[0].act);
+	mlk_action_stack_add(&st, &table[1].act);
+	mlk_action_stack_add(&st, &table[2].act);
+	mlk_action_stack_add(&st, &table[3].act);
+	mlk_action_stack_add(&st, &table[4].act);
+	mlk_action_stack_add(&st, &table[5].act);
+	mlk_action_stack_add(&st, &table[6].act);
 
-	DT_ASSERT(!action_stack_update(&st, 0));
+	DT_ASSERT(!mlk_action_stack_update(&st, 0));
 
 	DT_ASSERT(!table[0].inv.handle);
 	DT_ASSERT(!table[1].inv.handle);
@@ -310,7 +310,7 @@
 	    table[3].act.update =
 	    table[6].act.update = my_update_true;
 
-	DT_ASSERT(action_stack_update(&st, 0));
+	DT_ASSERT(mlk_action_stack_update(&st, 0));
 	DT_EQ_PTR(st.actions[0], NULL);
 	DT_EQ_PTR(st.actions[1], NULL);
 	DT_EQ_PTR(st.actions[2], NULL);
@@ -337,17 +337,17 @@
 	};
 
 	struct mlk_action *actions[10];
-	struct action_stack st = {0};
+	struct mlk_action_stack st = {0};
 
-	action_stack_init(&st, actions, 10);
-	action_stack_add(&st, &table[0].act);
-	action_stack_add(&st, &table[1].act);
-	action_stack_add(&st, &table[2].act);
-	action_stack_add(&st, &table[3].act);
-	action_stack_add(&st, &table[4].act);
-	action_stack_add(&st, &table[5].act);
-	action_stack_add(&st, &table[6].act);
-	action_stack_draw(&st);
+	mlk_action_stack_init(&st, actions, 10);
+	mlk_action_stack_add(&st, &table[0].act);
+	mlk_action_stack_add(&st, &table[1].act);
+	mlk_action_stack_add(&st, &table[2].act);
+	mlk_action_stack_add(&st, &table[3].act);
+	mlk_action_stack_add(&st, &table[4].act);
+	mlk_action_stack_add(&st, &table[5].act);
+	mlk_action_stack_add(&st, &table[6].act);
+	mlk_action_stack_draw(&st);
 
 	DT_ASSERT(!table[0].inv.handle);
 	DT_ASSERT(!table[1].inv.handle);
@@ -402,12 +402,12 @@
 	};
 
 	struct mlk_action *actions[10];
-	struct action_stack st = {0};
+	struct mlk_action_stack st = {0};
 
-	action_stack_init(&st, actions, 10);
-	action_stack_add(&st, &table[0].act);
-	action_stack_add(&st, &table[1].act);
-	action_stack_finish(&st);
+	mlk_action_stack_init(&st, actions, 10);
+	mlk_action_stack_add(&st, &table[0].act);
+	mlk_action_stack_add(&st, &table[1].act);
+	mlk_action_stack_finish(&st);
 
 	DT_ASSERT(!table[0].inv.handle);
 	DT_ASSERT(!table[0].inv.update);
--- a/tests/test-alloc.c	Mon Oct 24 21:29:39 2022 +0200
+++ b/tests/test-alloc.c	Thu Nov 03 21:09:25 2022 +0100
@@ -28,7 +28,6 @@
 };
 
 static struct {
-	size_t total;
 	size_t alloc_count;
 	size_t free_count;
 } my_stats;
@@ -37,7 +36,6 @@
 my_alloc(size_t n)
 {
 	my_stats.alloc_count += 1;
-	my_stats.total += n;
 
 	return malloc(n);
 }
@@ -65,11 +63,11 @@
 };
 
 static void
-test_basics_array_simple(void)
+test_basics_array0(void)
 {
 	struct point *points;
 
-	DT_ASSERT((points = mlk_alloc_array0(2, sizeof (*points))));
+	points = mlk_alloc_new0(2, sizeof (*points));
 	DT_EQ_INT(points[0].x, 0);
 	DT_EQ_INT(points[0].y, 0);
 	DT_EQ_INT(points[1].x, 0);
@@ -80,11 +78,15 @@
 	points[1].x = 30;
 	points[1].y = 40;
 
-	DT_ASSERT((points = mlk_alloc_rearray0(points, 2, 4, sizeof (*points))));
+	points = mlk_alloc_renew0(points, 4);
+
+	/* 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);
@@ -98,11 +100,11 @@
 	struct point *p, *data;
 	size_t total = 0;
 
-	mlk_alloc_pool_init(&pool, sizeof (*p), NULL);
+	mlk_alloc_pool_init(&pool, 16, sizeof (*p), NULL);
 
 	DT_EQ_UINT(pool.elemsize, sizeof (*p));
 	DT_EQ_UINT(pool.size, 0);
-	DT_EQ_UINT(pool.capacity, MLK_ALLOC_POOL_INIT_DEFAULT);
+	DT_EQ_UINT(pool.capacity, 16);
 
 	/* Create until we reach the capacity. */
 	for (size_t i = 0; i < pool.capacity; ++i) {
@@ -150,18 +152,17 @@
 	char *str = mlk_alloc_sdupf("Hello %s", "David");
 
 	DT_EQ_STR(str, "Hello David");
-	free(str);
+	mlk_alloc_free(str);
 }
 
 static void
 test_custom_count(void)
 {
 	mlk_alloc_set(&my_funcs);
-	mlk_alloc_free(mlk_alloc_new(10));
-	mlk_alloc_free(mlk_alloc_new0(20));
+	mlk_alloc_free(mlk_alloc_new(10, 1));
+	mlk_alloc_free(mlk_alloc_new0(20, 1));
 	mlk_alloc_free(mlk_alloc_sdup("malikania"));
 
-	DT_EQ_UINT(my_stats.total, 40U);
 	DT_EQ_UINT(my_stats.alloc_count, 3U);
 	DT_EQ_UINT(my_stats.free_count, 3U);
 }
@@ -169,7 +170,7 @@
 int
 main(void)
 {
-	DT_RUN(test_basics_array_simple);
+	DT_RUN(test_basics_array0);
 	DT_RUN(test_basics_pool_simple);
 	DT_RUN(test_basics_sdupf);
 	DT_RUN(test_custom_count);