Mirai's Miscellaneous Misadventures

M40 / core / allocators.c

// copyright 2023 zamfofex
// license: AGPLv3 or later

#include <mimimi/allocators.h>
#include <mimimi/compound-behaviors.h>
 
struct mimimi_temporary_allocator
{
	struct mimimi_allocator *allocator;
	int count;
	void **allocated;
};

static void *mimimi_temporary_allocate(void *data, unsigned int size)
{
	struct mimimi_temporary_allocator *temporary_allocator = data;
	struct mimimi_allocator *allocator = temporary_allocator->allocator;
	
	void *value = mimimi_allocate(allocator, size);
	
	temporary_allocator->allocated = mimimi_reallocate(allocator, temporary_allocator->allocated, (temporary_allocator->count + 1) * sizeof *temporary_allocator->allocated);
	temporary_allocator->allocated[temporary_allocator->count] = value;
	temporary_allocator->count++;
	
	return value;
}

static void *mimimi_temporary_reallocate(void *data, void *value, unsigned int size)
{
	struct mimimi_temporary_allocator *temporary_allocator = data;
	struct mimimi_allocator *allocator = temporary_allocator->allocator;
	
	if (value == allocator->null)
		return mimimi_temporary_allocate(data, size);
	
	int i = 0;
	while (temporary_allocator->allocated[i] != value) i++;
	
	value = mimimi_reallocate(allocator, value, size);
	temporary_allocator->allocated[i] = value;
	
	return value;
}

static void mimimi_temporary_deallocate(void *data, void *value)
{
	struct mimimi_temporary_allocator *temporary_allocator = data;
	struct mimimi_allocator *allocator = temporary_allocator->allocator;
	
	int i = 0;
	while (temporary_allocator->allocated[i] != value) i++;
	
	for (int j = i + 1 ; j < temporary_allocator->count ; j++)
		temporary_allocator->allocated[j - 1] = temporary_allocator->allocated[j];
	
	temporary_allocator->count--;
	if (temporary_allocator->count == 0)
		mimimi_deallocate(allocator, temporary_allocator->allocated),
		temporary_allocator->allocated = allocator->null;
	else
		temporary_allocator->allocated = mimimi_reallocate(allocator, temporary_allocator->allocated, temporary_allocator->count * sizeof *temporary_allocator->allocated);
	
	mimimi_deallocate(temporary_allocator->allocator, value);
}

struct mimimi_allocator *mimimi_temporary_allocator(struct mimimi_allocator *allocator)
{
	struct mimimi_temporary_allocator *temporary_allocator = mimimi_allocate(allocator, sizeof *temporary_allocator);
	temporary_allocator->allocator = allocator;
	temporary_allocator->count = 0;
	temporary_allocator->allocated = allocator->null;
	
	struct mimimi_allocator *result = mimimi_allocate(allocator, sizeof *result);
	result->allocate = &mimimi_temporary_allocate;
	result->deallocate = &mimimi_temporary_deallocate;
	result->reallocate = &mimimi_temporary_reallocate;
	result->null = allocator->null;
	result->data = temporary_allocator;
	
	return result;
}

void mimimi_finish_temporary_allocator(struct mimimi_allocator *result)
{
	struct mimimi_temporary_allocator *temporary_allocator = result->data;
	struct mimimi_allocator *allocator = temporary_allocator->allocator;
	
	for (int i = 0 ; i < temporary_allocator->count ; i++)
		mimimi_deallocate(allocator, temporary_allocator->allocated[i]);
	if (temporary_allocator->count != 0)
		mimimi_deallocate(allocator, temporary_allocator->allocated);
	mimimi_deallocate(allocator, temporary_allocator);
	mimimi_deallocate(allocator, result);
}

static void mimimi_compound_allocator_finish(void *data)
{
	mimimi_finish_temporary_allocator(data);
}

struct mimimi_allocator *mimimi_compound_allocator(struct mimimi_behavior *compound, struct mimimi_allocator *allocator)
{
	struct mimimi_allocator *temporary_allocator = mimimi_temporary_allocator(allocator);
	mimimi_compound(compound, mimimi_finalizer(temporary_allocator, &mimimi_compound_allocator_finish, allocator));
	return temporary_allocator;
}