changeset 182:f6497ec74b49

core: add alloc module, closes #2512
author David Demelier <markand@malikania.fr>
date Tue, 27 Oct 2020 16:54:18 +0100
parents 867b60e6258a
children 604fad63bd9c
files examples/example-drawable.c libadventure/adventure/state/mainmenu.c libadventure/adventure/state/panic.c libadventure/adventure/state/splashscreen.c libcore/CMakeLists.txt libcore/core/alloc.c libcore/core/alloc.h libcore/core/inhibit.c libcore/core/inhibit.h libcore/core/util.c libcore/core/util.h
diffstat 11 files changed, 226 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-drawable.c	Tue Oct 27 16:18:21 2020 +0100
+++ b/examples/example-drawable.c	Tue Oct 27 16:54:18 2020 +0100
@@ -18,6 +18,7 @@
 
 #include <stdlib.h>
 
+#include <core/alloc.h>
 #include <core/animation.h>
 #include <core/clock.h>
 #include <core/core.h>
@@ -89,7 +90,7 @@
 static void
 spawn(int x, int y)
 {
-	struct explosion *expl = emalloc(sizeof (struct explosion));
+	struct explosion *expl = alloc(1, sizeof (struct explosion));
 
 	animation_init(&expl->anim, &explosion_sprite, 100);
 	animation_drawable(&expl->anim, &expl->dw, x, y);
--- a/libadventure/adventure/state/mainmenu.c	Tue Oct 27 16:18:21 2020 +0100
+++ b/libadventure/adventure/state/mainmenu.c	Tue Oct 27 16:54:18 2020 +0100
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <core/alloc.h>
 #include <core/event.h>
 #include <core/font.h>
 #include <core/game.h>
@@ -119,7 +120,7 @@
 	struct font fonts[2];
 
 	/* Allocate the main menu data. */
-	main = (state->data = ecalloc(1, sizeof (*main)));
+	main = (state->data = alloc_zero(1, sizeof (*main)));
 
 	if (!font_openmem(&fonts[0], fonts_teutonic, sizeof (fonts_teutonic), 130) ||
 	    !font_openmem(&fonts[1], fonts_pirata_one, sizeof (fonts_pirata_one), 30))
--- a/libadventure/adventure/state/panic.c	Tue Oct 27 16:18:21 2020 +0100
+++ b/libadventure/adventure/state/panic.c	Tue Oct 27 16:54:18 2020 +0100
@@ -22,6 +22,7 @@
 #include <stdnoreturn.h>
 #include <string.h>
 
+#include <core/alloc.h>
 #include <core/error.h>
 #include <core/event.h>
 #include <core/font.h>
@@ -31,7 +32,6 @@
 #include <core/state.h>
 #include <core/sys.h>
 #include <core/texture.h>
-#include <core/util.h>
 #include <core/window.h>
 
 #include <ui/align.h>
@@ -98,7 +98,7 @@
 
 	theme = theme_default();
 	font = theme->fonts[THEME_FONT_INTERFACE];
-	view = ecalloc(1, sizeof (*view));
+	view = alloc_zero(1, sizeof (*view));
 
 	if (!font_render(font, &view->texts[0].tex, "An unrecoverable error occured and the game cannot continue.", FOREGROUND) ||
 	    !font_render(font, &view->texts[1].tex, "Please report the detailed error as provided below.", FOREGROUND) ||
--- a/libadventure/adventure/state/splashscreen.c	Tue Oct 27 16:18:21 2020 +0100
+++ b/libadventure/adventure/state/splashscreen.c	Tue Oct 27 16:54:18 2020 +0100
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <core/alloc.h>
 #include <core/font.h>
 #include <core/game.h>
 #include <core/image.h>
@@ -28,7 +29,6 @@
 #include <core/state.h>
 #include <core/sys.h>
 #include <core/texture.h>
-#include <core/util.h>
 #include <core/window.h>
 
 #include <ui/align.h>
@@ -54,7 +54,7 @@
 	struct splashscreen *splash;
 	struct font font;
 
-	splash = ecalloc(1, sizeof (*splash));
+	splash = alloc_zero(1, sizeof (*splash));
 	splash->next = next;
 
 	if (!font_openmem(&font, fonts_cubic, sizeof (fonts_cubic), 80))
--- a/libcore/CMakeLists.txt	Tue Oct 27 16:18:21 2020 +0100
+++ b/libcore/CMakeLists.txt	Tue Oct 27 16:54:18 2020 +0100
@@ -30,6 +30,8 @@
 	SOURCES
 	${libcore_SOURCE_DIR}/core/action.c
 	${libcore_SOURCE_DIR}/core/action.h
+	${libcore_SOURCE_DIR}/core/alloc.c
+	${libcore_SOURCE_DIR}/core/alloc.h
 	${libcore_SOURCE_DIR}/core/animation.c
 	${libcore_SOURCE_DIR}/core/animation.h
 	${libcore_SOURCE_DIR}/core/clock.c
@@ -49,7 +51,6 @@
 	${libcore_SOURCE_DIR}/core/game.h
 	${libcore_SOURCE_DIR}/core/image.c
 	${libcore_SOURCE_DIR}/core/image.h
-	${libcore_SOURCE_DIR}/core/inhibit.c
 	${libcore_SOURCE_DIR}/core/inhibit.h
 	${libcore_SOURCE_DIR}/core/key.h
 	${libcore_SOURCE_DIR}/core/maths.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/alloc.c	Tue Oct 27 16:54:18 2020 +0100
@@ -0,0 +1,100 @@
+/*
+ * alloc.h -- custom allocators
+ *
+ * Copyright (c) 2020 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 <stdlib.h>
+#include <string.h>
+
+#include "alloc.h"
+#include "error.h"
+#include "panic.h"
+
+static void *
+panic_alloc(size_t size)
+{
+	void *mem;
+
+	if (!(mem = malloc(size)))
+		panicf("%s", strerror(errno));
+
+	return mem;
+}
+
+static void *
+panic_realloc(void *ptr, size_t size)
+{
+	void *mem;
+
+	if (!(mem = realloc(ptr, size)))
+		panicf("%s", strerror(errno));
+
+	return mem;
+}
+
+struct allocator allocator = {
+	.alloc = panic_alloc,
+	.realloc = panic_realloc,
+	.free = free
+};
+
+void *
+alloc(size_t n, size_t size)
+{
+	assert(n != 0);
+	assert(size != 0);
+
+	size_t total = n * size;
+
+	if (total / n != size)
+		return errorf("%s", strerror(ENOMEM)), NULL;
+
+	return allocator.alloc(total);
+}
+
+void *
+alloc_zero(size_t n, size_t size)
+{
+	assert(n != 0);
+	assert(size != 0);
+
+	void *mem;
+	size_t total = n * size;
+
+	if (total / n != size)
+		return errorf("%s", strerror(ENOMEM)), NULL;
+
+	if ((mem = allocator.alloc(total)))
+		memset(mem, 0, total);
+
+	return mem;
+}
+
+void *
+alloc_dup(const void *ptr, size_t size)
+{
+	assert(ptr);
+	assert(size != 0);
+
+	void *mem;
+
+	if ((mem = allocator.alloc(size)))
+		memcpy(mem, ptr, size);
+
+	return mem;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcore/core/alloc.h	Tue Oct 27 16:54:18 2020 +0100
@@ -0,0 +1,116 @@
+/*
+ * alloc.h -- custom allocators
+ *
+ * Copyright (c) 2020 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 MOLKO_ALLOC_H
+#define MOLKO_ALLOC_H
+
+/**
+ * \file alloc.h
+ * \brief Custom allocators.
+ *
+ * This module controls how the API should allocate memory. Although dynamic
+ * allocation isn't much used in the core API, it is used in few places where
+ * static arrays would not fit (e.g. loading maps).
+ *
+ * To change the allocator, simply modify the global allocator object.
+ */
+
+#include <stddef.h>
+
+#include "util.h"
+
+/**
+ * \brief Global allocator strategy.
+ */
+struct allocator {
+	/**
+	 * (+) Allocate some data.
+	 *
+	 * The default implementation uses malloc and calls \ref panic in case
+	 * of failure.
+	 *
+	 * \pre size != 0
+	 * \param size the size to alloc
+	 * \return A pointer to the allocated region (NULL is allowed).
+	 */
+	void *(*alloc)(size_t size);
+
+	/**
+	 * (+) Realloc a region.
+	 *
+	 * The default implementation uses malloc and calls \ref panic in case
+	 * of failure.
+	 *
+	 * \pre size != 0
+	 * \param ptr the old region
+	 * \param size the new size
+	 * \return A pointer to the allocated region (NULL is allowed).
+	 */
+	void *(*realloc)(void *ptr, size_t size);
+
+	/**
+	 * (+) Free resources.
+	 *
+	 * The default implementation calls standard C free function.
+	 *
+	 * \param ptr the region (may be NULL)
+	 */
+	void (*free)(void *ptr);
+};
+
+/**
+ * \brief Global allocator object.
+ */
+extern struct allocator allocator;
+
+/**
+ * Shortcut for allocator->alloc.
+ *
+ * \pre n != 0 && size != 0
+ * \param n the number of objects to allocate
+ * \param size the size of each object
+ * \return The result of allocator->alloc.
+ */
+void *
+alloc(size_t n, size_t size) PLAT_NODISCARD;
+
+/**
+ * Shortcut for allocator->alloc and then use memset to clear memory.
+ *
+ * \pre n != 0 && size != 0
+ * \param n the number of objects to allocate
+ * \param size the size of each object
+ * \return The result of allocator->alloc.
+ */
+void *
+alloc_zero(size_t n, size_t size) PLAT_NODISCARD;
+
+/**
+ * Duplicate region pointer by ptr.
+ *
+ * This function calls \ref alloc to allocate memory.
+ *
+ * \pre ptr != NULL
+ * \param ptr the pointer
+ * \param size the size of the memory to copy
+ * \return The result of allocator->alloc filled with a copy of ptr.
+ */
+void *
+alloc_dup(const void *ptr, size_t size) PLAT_NODISCARD;
+
+#endif /* !MOLKO_ALLOC_H */
--- a/libcore/core/inhibit.c	Tue Oct 27 16:18:21 2020 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * inhibit.c -- disable specific game behavior
- *
- * Copyright (c) 2020 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 <stdlib.h>
-#include <string.h>
-
-#include "action.h"
-#include "inhibit.h"
-#include "game.h"
-#include "util.h"
-
-static bool
-update(struct action *a, unsigned int ticks)
-{
-	(void)ticks;
-
-	game.inhibit = *((enum inhibit *)a->data);
-
-	return true;
-}
-
-static void
-finish(struct action *a)
-{
-	free(a->data);
-}
-
-void
-inhibit_action(enum inhibit mode, struct action *a)
-{
-	assert(a);
-
-	memset(a, 0, sizeof (struct action));
-	a->data = ememdup(&mode, sizeof (enum inhibit));
-	a->update = update;
-	a->finish = finish;
-}
--- a/libcore/core/inhibit.h	Tue Oct 27 16:18:21 2020 +0100
+++ b/libcore/core/inhibit.h	Tue Oct 27 16:54:18 2020 +0100
@@ -53,16 +53,4 @@
 	INHIBIT_STATE_DRAW         = (1 << 2)
 };
 
-/**
- * Create an action to inhibit the system.
- *
- * The mode will replace the actual inhibit modes rather than adding new flags.
- *
- * \pre a != NULL
- * \param mode the new mode
- * \param a the action to fill
- */
-void
-inhibit_action(enum inhibit mode, struct action *a);
-
 #endif /* !MOLKO_INHIBIT_H */
--- a/libcore/core/util.c	Tue Oct 27 16:18:21 2020 +0100
+++ b/libcore/core/util.c	Tue Oct 27 16:54:18 2020 +0100
@@ -16,49 +16,10 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include <SDL.h>
 
-#include "panic.h"
 #include "util.h"
 
-void *
-emalloc(size_t size)
-{
-	void *mem;
-
-	if (!(mem = malloc(size)))
-		panicf("%s", strerror(errno));
-
-	return mem;
-}
-
-void *
-ecalloc(size_t n, size_t size)
-{
-	void *mem;
-
-	if (!(mem = calloc(n, size)))
-		panicf("%s", strerror(errno));
-
-	return mem;
-}
-
-void *
-ememdup(const void *ptr, size_t size)
-{
-	void *mem;
-
-	if (!(mem = malloc(size)))
-		panicf("%s", strerror(errno));
-
-	return memcpy(mem, ptr, size);
-}
-
 void
 delay(unsigned int ms)
 {
--- a/libcore/core/util.h	Tue Oct 27 16:18:21 2020 +0100
+++ b/libcore/core/util.h	Tue Oct 27 16:54:18 2020 +0100
@@ -44,39 +44,6 @@
 #define NELEM(x) sizeof ((x)) / sizeof ((x)[0])
 
 /**
- * Wrapper around malloc(3) that exits on allocation failure.
- *
- * \param size the size
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-emalloc(size_t size) PLAT_NODISCARD;
-
-/**
- * Wrapper around calloc(3) that exits on allocation failure.
- *
- * \param n the number of objects to allocate
- * \param size the size per n
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-ecalloc(size_t n, size_t size) PLAT_NODISCARD;
-
-/**
- * Copy the region specified by ptr.
- *
- * \pre ptr != NULL
- * \param ptr the pointer
- * \param size the size of the memory to copy
- * \return a pointer
- * \post returned pointer will never be NULL
- */
-void *
-ememdup(const void *ptr, size_t size) PLAT_NODISCARD;
-
-/**
  * Put the thread to sleep for a given amount of milliseconds.
  *
  * \param ms the number of milliseconds to wait