~kdsch/c-modules

0fd00f9de6dfc70b95d5c6ef6124dc0bd87f5173 — Karl Schultheisz 5 months ago 05c4494
Add pool allocator
4 files changed, 109 insertions(+), 0 deletions(-)

M main.c
M meson.build
A pool-allocator.c
A pool-allocator.h
M main.c => main.c +23 -0
@@ 1,4 1,5 @@
#include "dynamic-array.c"
#include "pool-allocator.c"

static void
harness_array(void)


@@ 13,9 14,31 @@ harness_array(void)
	assert(a.length == 0);
}

static void
harness_pool_allocator(void)
{
	struct object_allocator allocator;
	object_allocator_init(&allocator);
	struct object *objects[32];

	for (uint8_t i = 0; i < 32; i++) {
		objects[i] = object_new(&allocator);
	}

	assert(object_new(&allocator) == NULL);
	assert(allocator.used == UINT32_MAX);

	for (uint8_t i = 0; i < 32; i++) {
		object_free(&allocator, objects[i]);
	}

	assert(allocator.used == 0);
}

int
main(void)
{
	harness_array();
	harness_pool_allocator();
	return 0;
}

M meson.build => meson.build +1 -0
@@ 35,6 35,7 @@ test(
		'--unsigned-overflow-check',
		files(
			'dynamic-array.c',
			'pool-allocator.c',
			'main.c',
		),
	],

A pool-allocator.c => pool-allocator.c +67 -0
@@ 0,0 1,67 @@
#include "pool-allocator.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>

void
object_allocator_init(struct object_allocator *allocator)
{
	assert(allocator);
	allocator->used = 0;
}

static uint8_t
count_trailing_zeroes(uint32_t x)
{
	if (!x) {
		return 32;
	}

	uint8_t n = 0;

	if ((x & 0x0000ffff) == 0) { n += 16; x >>= 16; }
	if ((x & 0x000000ff) == 0) { n +=  8; x >>=  8; }
	if ((x & 0x0000000f) == 0) { n +=  4; x >>=  4; }
	if ((x & 0x00000003) == 0) { n +=  2; x >>=  2; }
	if ((x & 0x00000001) == 0) { n +=  1; }

	return n;
}

struct object *
object_new(struct object_allocator *allocator)
{
	assert(allocator);

	const uint8_t position = count_trailing_zeroes(allocator->used);

	assert(position <= 32);

	if (position == 0) {
		return NULL;
	}

	const uint8_t index = position - 1;
	allocator->used |= 1u << index;
	return &allocator->objects[index];
}

void
object_free(struct object_allocator *allocator, struct object *object)
{
	assert(allocator);

	// Don't call me when nothing is allocated.
	assert(0 < allocator->used);

	for (uint8_t i = 0; i < 32; i++) {
		if (object == &allocator->objects[i]) {
			allocator->used &= ~(1u << i);
			memset(object, 0, sizeof(*object));
			return;
		}
	}

	// Don't call me with addresses that aren't mine.
	assert(0);
}

A pool-allocator.h => pool-allocator.h +18 -0
@@ 0,0 1,18 @@
#ifndef POOL_ALLOCATOR_H
#define POOL_ALLOCATOR_H
#include <stdint.h>
struct object {
	uint8_t private[sizeof(struct{
		uint32_t whatever;
	})];
};

struct object_allocator {
	struct object objects[32];
	uint32_t used; // bitset
};

void object_allocator_init(struct object_allocator *allocator);
struct object *object_new(struct object_allocator *allocator);
void object_free(struct object_allocator *allocator, struct object *object);
#endif