Mirai's Miscellaneous Misadventures
M26 / core / behaviors.c
#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;
}
struct mimimi_choice
{
struct mimimi_allocator *allocator;
struct mimimi_behavior *behavior;
char *predicate;
struct mimimi_behavior *nonzero;
struct mimimi_behavior *zero;
};
static void mimimi_choose(void *data)
{
struct mimimi_choice *choice = data;
struct mimimi_behavior *nonzero = choice->nonzero;
struct mimimi_behavior *zero = choice->zero;
if (*choice->predicate == 0)
(*zero->behave)(zero->data);
else
(*nonzero->behave)(nonzero->data);
}
static void mimimi_choice_finish(void *data)
{
struct mimimi_choice *choice = data;
(*choice->nonzero->finish)(choice->nonzero->data);
(*choice->zero->finish)(choice->zero->data);
(*choice->allocator->deallocate)(choice->behavior);
(*choice->allocator->deallocate)(choice);
}
struct mimimi_behavior *mimimi_choice(char *predicate, struct mimimi_behavior *nonzero, struct mimimi_behavior *zero, struct mimimi_allocator *allocator)
{
struct mimimi_choice *choice = (*allocator->allocate)(sizeof *choice);
choice->allocator = allocator;
choice->predicate = predicate;
choice->nonzero = nonzero;
choice->zero = zero;
choice->behavior = (*allocator->allocate)(sizeof *choice->behavior);
choice->behavior->behave = &mimimi_choose;
choice->behavior->finish = &mimimi_choice_finish;
choice->behavior->data = choice;
return choice->behavior;
}
struct mimimi_throttle
{
struct mimimi_allocator *allocator;
struct mimimi_behavior *behavior;
struct mimimi_behavior *underlying;
int time;
int countdown;
};
static void mimimi_throttle_behave(void *data)
{
struct mimimi_throttle *throttle = data;
if (throttle->countdown == 0)
{
throttle->countdown = throttle->time;
(*throttle->underlying->behave)(throttle->underlying->data);
}
}
static void mimimi_throttle_finish(void *data)
{
struct mimimi_throttle *throttle = data;
(*throttle->underlying->finish)(throttle->underlying->data);
(*throttle->allocator->deallocate)(throttle->behavior);
(*throttle->allocator->deallocate)(throttle);
}
static void mimimi_countdown(void *data)
{
int *n = data;
if (*n != 0) n[0]--;
}
struct mimimi_behavior *mimimi_throttle(struct mimimi_behavior *compound, struct mimimi_behavior *underlying, int time, struct mimimi_allocator *allocator)
{
struct mimimi_throttle *throttle = (*allocator->allocate)(sizeof *throttle);
throttle->allocator = allocator;
throttle->underlying = underlying;
throttle->time = time;
throttle->countdown = 0;
throttle->behavior = (*allocator->allocate)(sizeof *throttle->behavior);
throttle->behavior->behave = &mimimi_throttle_behave;
throttle->behavior->finish = &mimimi_throttle_finish;
throttle->behavior->data = throttle;
mimimi_compound(compound, mimimi_function(&throttle->countdown, mimimi_countdown, allocator));
return throttle->behavior;
}