202 lines
4.3 KiB
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;
|
|
}
|