Mirai's Miscellaneous Misadventures

M24 / core / behaviors.c

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

#include <mimimi/behaviors.h>
#include <mimimi/compound-behaviors.h>
#include <mimimi/chapters.h>
#include <mimimi/allocators.h>

struct mimimi_compound_behavior
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	int count;
	struct mimimi_behavior **behaviors;
};

static void mimimi_compound_behave(void *data)
{
	struct mimimi_compound_behavior *compound = data;
	for (int i = 0 ; i < compound->count ; i++)
	{
		struct mimimi_behavior *behavior = compound->behaviors[i];
		(*behavior->behave)(behavior->data);
	}
}

static void mimimi_compound_finish(void *data)
{
	struct mimimi_compound_behavior *compound = data;
	for (int i = 0 ; i < compound->count ; i++)
	{
		struct mimimi_behavior *behavior = compound->behaviors[i];
		(*behavior->finish)(behavior->data);
	}
	
	(*compound->allocator->deallocate)(compound->behaviors);
	(*compound->allocator->deallocate)(compound->behavior);
	(*compound->allocator->deallocate)(compound);
}

struct mimimi_behavior *mimimi_compound_behavior(struct mimimi_allocator *allocator)
{
	struct mimimi_compound_behavior *data = (*allocator->allocate)(sizeof *data);
	data->allocator = allocator;
	
	data->behavior = (*allocator->allocate)(sizeof *data->behavior);
	data->behavior->behave = &mimimi_compound_behave;
	data->behavior->finish = &mimimi_compound_finish;
	data->behavior->data = data;
	
	data->count = 0;
	data->behaviors = allocator->null;
	
	return data->behavior;
}

void mimimi_compound(struct mimimi_behavior *behavior, struct mimimi_behavior *other)
{
	struct mimimi_compound_behavior *compound = behavior->data;
	
	compound->count++;
	compound->behaviors = (*compound->allocator->reallocate)(compound->behaviors, compound->count * sizeof *compound->behaviors);
	compound->behaviors[compound->count - 1] = other;
}

void mimimi_compound_remove(struct mimimi_behavior *behavior, struct mimimi_behavior *other)
{
	struct mimimi_compound_behavior *compound = behavior->data;
	for (int i = 0 ; i < compound->count ; i++)
	{
		struct mimimi_behavior *behavior = compound->behaviors[i];
		if (behavior == other)
		{
			compound->count--;
			for (int j = i ; j < compound->count ; j++)
				compound->behaviors[j] = compound->behaviors[j + 1];
			
			if (compound->count == 0)
				(*compound->allocator->deallocate)(compound->behaviors);
			else
				compound->behaviors = (*compound->allocator->reallocate)(compound->behaviors, compound->count * sizeof *compound->behaviors);
			break;
		}
	}
}

char mimimi_compound_empty(struct mimimi_behavior *behavior)
{
	struct mimimi_compound_behavior *compound = behavior->data;
	if (compound->count == 0) return 1;
	else return 0;
}

void mimimi_ignore(void *data) { }

static struct mimimi_behavior mimimi_noop_value = {&mimimi_ignore, &mimimi_ignore};
struct mimimi_behavior *mimimi_noop = &mimimi_noop_value;

struct mimimi_function
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_behavior *other;
};

static void mimimi_function_behave(void *data)
{
	struct mimimi_function *function = data;
	(*function->other->behave)(function->other->data);
}

static void mimimi_function_finish(void *data)
{
	struct mimimi_function *function = data;
	(*function->other->finish)(function->other->data);
	(*function->allocator->deallocate)(function->other);
	(*function->allocator->deallocate)(function->behavior);
	(*function->allocator->deallocate)(function);
}

struct mimimi_behavior *mimimi_function(void *data, void (*behave)(void *data), struct mimimi_allocator *allocator)
{
	struct mimimi_function *function = (*allocator->allocate)(sizeof *function);
	function->allocator = allocator;
	
	function->other = (*allocator->allocate)(sizeof *function->other);
	function->other->behave = behave;
	function->other->finish = &mimimi_ignore;
	function->other->data = data;
	
	function->behavior = (*allocator->allocate)(sizeof *function->behavior);
	function->behavior->behave = &mimimi_function_behave;
	function->behavior->finish = &mimimi_function_finish;
	function->behavior->data = function;
	
	return function->behavior;
}

struct mimimi_behavior *mimimi_finalizer(void *data, void (*finish)(void *data), struct mimimi_allocator *allocator)
{
	struct mimimi_function *function = (*allocator->allocate)(sizeof *function);
	function->allocator = allocator;
	
	function->other = (*allocator->allocate)(sizeof *function->other);
	function->other->behave = &mimimi_ignore;
	function->other->finish = finish;
	function->other->data = data;
	
	function->behavior = (*allocator->allocate)(sizeof *function->behavior);
	function->behavior->behave = &mimimi_function_behave;
	function->behavior->finish = &mimimi_function_finish;
	function->behavior->data = function;
	
	return function->behavior;
}

struct mimimi_behavior *mimimi_allocator_behavior(void **data, unsigned int size, struct mimimi_allocator *allocator)
{
	*data = (*allocator->allocate)(size);
	return mimimi_finalizer(*data, allocator->deallocate, allocator);
}

void *mimimi_compound_allocate(struct mimimi_behavior *compound, unsigned int size, struct mimimi_allocator *allocator)
{
	void *data;
	mimimi_compound(compound, mimimi_allocator_behavior(&data, size, allocator));
	return data;
}