Mirai's Miscellaneous Misadventures
M36 / 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);
}
if (compound->count != 0)
mimimi_deallocate(compound->allocator, compound->behaviors);
mimimi_deallocate(compound->allocator, compound->behavior);
mimimi_deallocate(compound->allocator, compound);
}
struct mimimi_behavior *mimimi_compound_behavior(struct mimimi_allocator *allocator)
{
struct mimimi_compound_behavior *data = mimimi_allocate(allocator, sizeof *data);
data->allocator = allocator;
data->behavior = mimimi_allocate(allocator, 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 = mimimi_reallocate(compound->allocator, 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)
mimimi_deallocate(compound->allocator, compound->behaviors);
else
compound->behaviors = mimimi_reallocate(compound->allocator, 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;
}
static void mimimi_ignore(void *data) { (void) data; }
static struct mimimi_behavior mimimi_noop_value = {&mimimi_ignore, &mimimi_ignore, 0};
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);
mimimi_deallocate(function->allocator, function->other);
mimimi_deallocate(function->allocator, function->behavior);
mimimi_deallocate(function->allocator, function);
}
struct mimimi_behavior *mimimi_function(void *data, void (*behave)(void *data), struct mimimi_allocator *allocator)
{
struct mimimi_function *function = mimimi_allocate(allocator, sizeof *function);
function->allocator = allocator;
function->other = mimimi_allocate(allocator, sizeof *function->other);
function->other->behave = behave;
function->other->finish = &mimimi_ignore;
function->other->data = data;
function->behavior = mimimi_allocate(allocator, 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 = mimimi_allocate(allocator, sizeof *function);
function->allocator = allocator;
function->other = mimimi_allocate(allocator, sizeof *function->other);
function->other->behave = &mimimi_ignore;
function->other->finish = finish;
function->other->data = data;
function->behavior = mimimi_allocate(allocator, sizeof *function->behavior);
function->behavior->behave = &mimimi_function_behave;
function->behavior->finish = &mimimi_function_finish;
function->behavior->data = function;
return function->behavior;
}
void *mimimi_compound_allocate(struct mimimi_behavior *compound, unsigned int size, struct mimimi_allocator *allocator)
{
struct mimimi_allocator *compound_allocator = mimimi_compound_allocator(compound, allocator);
return mimimi_allocate(compound_allocator, size);
}
struct mimimi_choice
{
struct mimimi_allocator *allocator;
struct mimimi_behavior *behavior;
unsigned 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);
mimimi_deallocate(choice->allocator, choice->behavior);
mimimi_deallocate(choice->allocator, choice);
}
struct mimimi_behavior *mimimi_choice(unsigned char *predicate, struct mimimi_behavior *nonzero, struct mimimi_behavior *zero, struct mimimi_allocator *allocator)
{
struct mimimi_choice *choice = mimimi_allocate(allocator, sizeof *choice);
choice->allocator = allocator;
choice->predicate = predicate;
choice->nonzero = nonzero;
choice->zero = zero;
choice->behavior = mimimi_allocate(allocator, 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);
mimimi_deallocate(throttle->allocator, throttle->behavior);
mimimi_deallocate(throttle->allocator, 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 = mimimi_allocate(allocator, sizeof *throttle);
throttle->allocator = allocator;
throttle->underlying = underlying;
throttle->time = time;
throttle->countdown = 0;
throttle->behavior = mimimi_allocate(allocator, 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;
}