event-sequence-transformation/graph.c

202 lines
4.3 KiB
C

#include <stdio.h>
#include "graph.h"
static void
graph_channel_list_resize(GraphChannelList * lst, size_t target)
{
if (target > lst->length) {
GraphChannel **new_elements = T_REALLOC(lst->elements, target, GraphChannel*);
if (!new_elements) {
return;
}
memset(&new_elements[lst->length], 0, (target - lst->length) * sizeof(GraphChannel*));
lst->elements = new_elements;
}
lst->length = target;
}
inline static void
graph_channel_list_ensure(GraphChannelList * lst, size_t idx)
{
size_t min_length = idx + 1;
if (lst->length < min_length) {
graph_channel_list_resize(lst, min_length);
}
if (lst->length < min_length) {
perror("Failed to resize graph channel list");
exit(1);
}
}
static bool
channel_handle_event(EventPositionBase * self, EventNode * event)
{
GraphChannel *ch = DOWNCAST(GraphChannel, EventPositionBase, self);
if (event->data.ttl == 0) {
event_destroy(event);
return true;
}
event->data.ttl--;
if (event->data.ttl == 0) {
event_destroy(event);
return true;
}
GraphNode * target = ch->end;
if (!target) {
event_destroy(event);
return true;
}
event->position = &target->as_EventPositionBase;
event->input_index = ch->idx_end;
target->as_EventPositionBase.waiting_new_event = false;
return true; // Changes were made
}
void
graph_channel_init(GraphChannel * ch, GraphNode * start, size_t start_idx, GraphNode * end, size_t end_idx)
{
if (start) {
graph_channel_list_ensure(&start->outputs, start_idx);
GraphChannel ** old_ch = &start->outputs.elements[start_idx];
if (*old_ch) {
if ((*old_ch)->start == start && (*old_ch)->idx_start == start_idx) {
(*old_ch)->start = NULL;
// TODO on orphaned check
}
}
*old_ch = ch;
}
if (end) {
graph_channel_list_ensure(&end->inputs, end_idx);
GraphChannel ** old_ch = &end->inputs.elements[end_idx];
if (*old_ch) {
if ((*old_ch)->end == end && (*old_ch)->idx_end == end_idx) {
(*old_ch)->end = NULL;
// TODO on orphaned check
}
}
*old_ch = ch;
}
ch->start = start;
ch->end = end;
ch->idx_start = start_idx;
ch->idx_end = end_idx;
ch->as_EventPositionBase.handle_event = &channel_handle_event;
ch->as_EventPositionBase.waiting_new_event = false;
}
GraphNode *
graph_node_new(GraphNodeSpecification * spec, GraphNodeConfig * config, InitializationEnvironment * env)
{
if (!spec || !spec->create) {
return NULL;
}
return spec->create(spec, config, env);
}
void
graph_node_delete(GraphNode * self)
{
if (!self) {
return;
}
for (size_t i = 0; i < self->inputs.length; ++i) {
GraphChannel *ch = self->inputs.elements[i];
if (ch && ch->end == self) {
ch->end = NULL;
if (!ch->start && !ch->end) {
// free(ch); // TODO on orphaned
}
}
self->inputs.elements[i] = NULL;
}
for (size_t i = 0; i < self->outputs.length; ++i) {
GraphChannel *ch = self->outputs.elements[i];
if (ch && ch->start == self) {
ch->start = NULL;
if (!ch->start && !ch->end) {
// free(ch); // TODO on orphaned
}
}
self->outputs.elements[i] = NULL;
}
graph_channel_list_deinit(&self->inputs);
graph_channel_list_deinit(&self->outputs);
GraphNodeSpecification *spec = self->specification;
if (!spec || !spec->destroy) {
return;
}
spec->destroy(spec, self);
}
void
graph_node_register_io(GraphNode * self, ProcessingState * state)
{
if (!self) {
return;
}
GraphNodeSpecification *spec = self->specification;
if (!spec || !spec->register_io) {
return;
}
spec->register_io(spec, self, state);
}
void
graph_channel_list_init(GraphChannelList * lst)
{
lst->length = 0;
lst->elements = NULL;
}
void
graph_channel_list_deinit(GraphChannelList * lst)
{
if (lst->elements) {
free(lst->elements);
lst->elements = NULL;
}
lst->length = 0;
}
ssize_t
graph_node_broadcast_forward_event(const GraphNode * source, EventNode * event)
{
if (!event) {
return -1;
}
if (!source) {
event_destroy(event);
return -1;
}
size_t count = source->outputs.length;
if (!count) {
event_destroy(event);
return 0;
}
if (count > 1) {
count = event_replicate(event, count - 1) + 1;
}
size_t succeses = count;
for (size_t i = 0; i < count; ++i) {
EventPositionBase *output = &source->outputs.elements[i]->as_EventPositionBase;
if (!output) {
--succeses;
EventNode *orphaned = event;
event = orphaned->next;
event_destroy(orphaned);
continue;
}
event->position = output;
event = event->next;
}
return succeses;
}