summaryrefslogtreecommitdiff
path: root/graphics/pgf/base/source/InterfaceFromC.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/pgf/base/source/InterfaceFromC.c
Initial commit
Diffstat (limited to 'graphics/pgf/base/source/InterfaceFromC.c')
-rw-r--r--graphics/pgf/base/source/InterfaceFromC.c1189
1 files changed, 1189 insertions, 0 deletions
diff --git a/graphics/pgf/base/source/InterfaceFromC.c b/graphics/pgf/base/source/InterfaceFromC.c
new file mode 100644
index 0000000000..b5606f2f39
--- /dev/null
+++ b/graphics/pgf/base/source/InterfaceFromC.c
@@ -0,0 +1,1189 @@
+
+// Own header:
+#include <pgf/gd/interface/c/InterfaceFromC.h>
+
+// Lua stuff:
+#include <lauxlib.h>
+
+// C stuff:
+#include <stdlib.h>
+#include <string.h>
+
+
+// Remove once Lua Link Bug is fixed:
+//
+// The following is a hack to avoid a problem with the Lua lib being linked twice.
+// When this happens, two version of "dummynode" exist in Lua and we must ensure that
+// we never create a table using such a dummynode while using a second lib.
+// The following should later be set to 0 and replaced everywhere, once this is fixed.
+#define MIN_HASH_SIZE_FIX 1
+
+
+
+// Help functions
+
+static void set_field (lua_State* L, const char* what, const char* where)
+{
+ if (what) {
+ lua_pushstring(L, what);
+ lua_setfield(L, -2, where);
+ }
+}
+
+
+static void init_vertex_array(pgfgd_Vertex_array* a, int count)
+{
+ a->length = count;
+ a->array = (pgfgd_Vertex**) calloc(count, sizeof(pgfgd_Vertex*));
+}
+
+static void init_edge_array(pgfgd_Edge_array* a, int count)
+{
+ a->length = count;
+ a->array = (pgfgd_Edge**) calloc(count, sizeof(pgfgd_Edge*));
+}
+
+static void init_arcs_array(pgfgd_Arc_array* arcs, int length)
+{
+ arcs->length = length;
+ arcs->tails = (int*) calloc(length, sizeof(int));
+ arcs->heads = (int*) calloc(length, sizeof(int));
+}
+
+static void init_path(pgfgd_Path* a, int count)
+{
+ a->length = count;
+ a->coordinates = (pgfgd_Coordinate*) calloc(count, sizeof(pgfgd_Coordinate));
+ a->strings = (char**) calloc(count, sizeof(char*));
+}
+
+static void clear_path(pgfgd_Path* p)
+{
+ int i;
+ for (i=0; i < p->length; i++)
+ free(p->strings[i]);
+
+ free(p->strings);
+ free(p->coordinates);
+
+ p->length = 0;
+ p->strings = 0;
+ p->coordinates = 0;
+}
+
+
+
+// Option handling
+
+struct pgfgd_OptionTable {
+ lua_State* state;
+
+ int kind;
+ int index;
+};
+
+// These are the indices of the parameters during a run of the main
+// algorithm:
+#define GRAPH_INDEX 1
+#define VERTICES_INDEX 2
+#define EDGES_INDEX 3
+#define ALGORITHM_INDEX 4
+
+// This is the index of a special table mapping vertices back to the
+// index they have. It is created in the C code, but stays on the
+// stack during the computations.
+#define BACKINDEX_STORAGE_INDEX 5
+
+// These are the positions of different upvalues for the C closure of
+// a C algorithm.
+#define FUNCTION_UPVALUE 1
+#define USER_UPVALUE 2
+#define DIGRAPH_OBJECT_UPVALUE 3
+
+
+static pgfgd_OptionTable* make_option_table(lua_State* L, int kind, int index)
+{
+ pgfgd_OptionTable* t = (pgfgd_OptionTable*) malloc(sizeof(pgfgd_OptionTable));
+
+ t->state = L;
+ t->kind = kind;
+ t->index = index;
+
+ return t;
+}
+
+static void push_option_table(pgfgd_OptionTable* t)
+{
+ switch (t->kind) {
+ case GRAPH_INDEX:
+ lua_getfield(t->state, GRAPH_INDEX, "options");
+ break;
+ case VERTICES_INDEX:
+ lua_rawgeti(t->state, VERTICES_INDEX, t->index);
+ lua_getfield(t->state, -1, "options");
+ lua_replace(t->state, -2);
+ break;
+ case EDGES_INDEX:
+ lua_rawgeti(t->state, EDGES_INDEX, t->index);
+ lua_getfield(t->state, -1, "options");
+ lua_replace(t->state, -2);
+ break;
+ }
+}
+
+int pgfgd_isset(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int is_nil = lua_isnil(t->state, -1);
+ lua_pop(t->state, 2);
+ return !is_nil;
+}
+
+int pgfgd_isnumber(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int is_number = lua_isnumber(t->state, -1);
+ lua_pop(t->state, 2);
+ return is_number;
+}
+
+int pgfgd_isboolean(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int is_bool = lua_isboolean(t->state, -1);
+ lua_pop(t->state, 2);
+ return is_bool;
+}
+
+int pgfgd_isstring(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int is_string = lua_isstring(t->state, -1);
+ lua_pop(t->state, 2);
+ return is_string;
+}
+
+int pgfgd_isuser(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int is_user = lua_isuserdata(t->state, -1);
+ lua_pop(t->state, 2);
+ return is_user;
+}
+
+
+double pgfgd_tonumber(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ double d = lua_tonumber(t->state, -1);
+ lua_pop(t->state, 2);
+ return d;
+}
+
+int pgfgd_toboolean(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ int d = lua_toboolean(t->state, -1);
+ lua_pop(t->state, 2);
+ return d;
+}
+
+char* pgfgd_tostring(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ const char* s = lua_tostring(t->state, -1);
+ char* copy = strcpy((char*) malloc(strlen(s)+1), s);
+ lua_pop(t->state, 2);
+ return copy;
+}
+
+void* pgfgd_touser(pgfgd_OptionTable* t, const char* key)
+{
+ push_option_table(t);
+ lua_getfield(t->state, -1, key);
+ void* d = lua_touserdata(t->state, -1);
+ lua_pop(t->state, 2);
+ return d;
+}
+
+
+// Handling algorithms
+
+struct pgfgd_SyntacticDigraph_internals {
+ lua_State* state;
+};
+
+static char* make_string_from(lua_State* L, const char* name)
+{
+ lua_getfield(L, -1, name);
+ if (lua_isnil(L, -1)) {
+ // Field not set; return emtpy string.
+ lua_pop(L, 1);
+ return (char*) calloc(1, sizeof(char));
+ }
+ else {
+ const char* s = lua_tostring(L, -1);
+ char* copy = strcpy((char*) malloc(strlen(s)+1), s);
+ lua_pop(L, 1);
+ return copy;
+ }
+}
+
+static void make_coordinate(lua_State* L, pgfgd_Coordinate* c)
+{
+ lua_getfield(L, -1, "x");
+ c->x = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ c->y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+}
+
+static pgfgd_Path* make_empty_path(lua_State* L)
+{
+ return (pgfgd_Path*) calloc(1, sizeof(pgfgd_Path));
+}
+
+static pgfgd_Path* make_path(lua_State* L)
+{
+ /* Path object must be on top of stack. */
+ pgfgd_Path* p = make_empty_path(L);
+
+ // Fill path:
+ int path_length = lua_rawlen(L, -1);
+ if (path_length > 0) {
+ init_path(p, path_length);
+ int i;
+ for (i = 0; i < path_length; i++) {
+ lua_rawgeti(L, -1, i+1);
+ if (lua_isstring(L, -1)) {
+ const char* s = lua_tostring(L, -1);
+ p->strings[i] = strcpy((char*) malloc(strlen(s)+1), s);
+ } else {
+ lua_getfield(L, -1, "x");
+ p->coordinates[i].x = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ p->coordinates[i].y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ }
+ }
+
+ return p;
+}
+
+static void construct_digraph(lua_State* L, pgfgd_SyntacticDigraph* d)
+{
+ d->internals = (pgfgd_SyntacticDigraph_internals*) calloc(1, sizeof(pgfgd_SyntacticDigraph_internals));
+ d->internals->state = L;
+
+ // Create the options table:
+ d->options = make_option_table(L, GRAPH_INDEX, 0);
+
+ // Create the vertex table
+ init_vertex_array(&d->vertices, lua_rawlen(L, VERTICES_INDEX));
+
+ // Create the vertices
+ int i;
+ for (i=0; i<d->vertices.length; i++) {
+ pgfgd_Vertex* v = (pgfgd_Vertex*) calloc(1, sizeof(pgfgd_Vertex));
+
+ // Push the vertex onto the Lua stack:
+ lua_rawgeti(L, VERTICES_INDEX, i+1);
+
+ // Fill v with information:
+ v->name = make_string_from(L, "name");
+ v->shape = make_string_from(L, "shape");
+ v->kind = make_string_from(L, "kind");
+
+ // Options:
+ v->options = make_option_table(L, VERTICES_INDEX, i+1);
+
+ // Index:
+ v->array_index = i;
+
+ // Setup pos field
+ lua_getfield(L, -1, "pos");
+ make_coordinate(L, &v->pos);
+ lua_pop(L, 1);
+
+ // Setup path array:
+ lua_getfield(L, -1, "path");
+ v->path = make_path(L);
+ lua_pop(L, 1);
+
+ // Pop the vertex
+ lua_pop(L, 1);
+
+ d->vertices.array[i] = v;
+ }
+
+ // Construct the edges:
+ init_edge_array(&d->syntactic_edges, lua_rawlen(L, EDGES_INDEX));
+
+ int edge_index;
+ for (edge_index = 0; edge_index < d->syntactic_edges.length; edge_index++) {
+ pgfgd_Edge* e = (pgfgd_Edge*) calloc(1, sizeof(pgfgd_Edge));
+
+ lua_rawgeti(L, EDGES_INDEX, edge_index+1);
+
+ e->direction = make_string_from(L, "direction");
+ e->options = make_option_table(L, EDGES_INDEX, edge_index+1);
+
+ // Index:
+ e->array_index = edge_index;
+
+ // Compute the tail vertex index:
+ lua_getfield(L, -1, "tail");
+ lua_gettable(L, VERTICES_INDEX);
+ e->tail = d->vertices.array[lua_tointeger(L, -1) - 1];
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "head");
+ lua_gettable(L, VERTICES_INDEX);
+ e->head = d->vertices.array[lua_tointeger(L, -1) - 1];
+ lua_pop(L, 1);
+
+ // Fill path:
+ e->path = make_empty_path(L);
+ e->path->length = -1; // Means that a default path should be created.
+
+ // Pop the edge form the Lua stack:
+ lua_pop(L, 1);
+
+ d->syntactic_edges.array[edge_index] = e;
+ }
+}
+
+
+static void sync_digraph(lua_State* L, pgfgd_SyntacticDigraph* d)
+{
+ // Writes back the computed position information to the digraph:
+ int i;
+ for (i=0; i<d->vertices.length; i++) {
+
+ // Push pos field of vertex:
+ lua_rawgeti(L, VERTICES_INDEX, i+1);
+ lua_getfield(L, -1, "pos");
+
+ // Set x and y coordinates:
+ pgfgd_Vertex* v = d->vertices.array[i];
+ lua_pushnumber(L, v->pos.x);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, v->pos.y);
+ lua_setfield(L, -2, "y");
+
+ // pop pos and vertex
+ lua_pop(L, 2);
+ }
+
+ // Write back the paths
+
+ int tos = lua_gettop(L);
+
+ // First, get "Coordinate.new" as a "local"
+ lua_getglobal(L, "require");
+ lua_pushstring(L, "pgf.gd.model.Path");
+ lua_call(L, 1, 1);
+ int Path_index = lua_gettop(L);
+
+ lua_getglobal(L, "require");
+ lua_pushstring(L, "pgf.gd.model.Coordinate");
+ lua_call(L, 1, 1);
+ lua_getfield(L, -1, "new");
+
+ int Coordinate_new_index = lua_gettop(L);
+
+ for (i=0; i < d->syntactic_edges.length; i++) {
+ pgfgd_Edge* e = d->syntactic_edges.array[i];
+
+ lua_rawgeti(L, EDGES_INDEX, i+1);
+
+ if (e->path->length == -1) {
+ // Create default path
+ pgfgd_path_append_moveto_tail(e);
+ pgfgd_path_append_lineto_head(e);
+ }
+
+ lua_createtable(L, e->path->length ? e->path->length : 1, MIN_HASH_SIZE_FIX);
+ lua_pushvalue(L, Path_index);
+ lua_setmetatable(L, -2);
+
+ int j;
+ for (j=0; j<e->path->length; j++) {
+ if (e->path->strings[j]) {
+ lua_pushstring(L, e->path->strings[j]);
+ lua_rawseti(L, -2, j+1);
+ } else {
+ lua_pushvalue(L, Coordinate_new_index);
+ lua_pushnumber(L, e->path->coordinates[j].x);
+ lua_pushnumber(L, e->path->coordinates[j].y);
+ lua_call(L, 2, 1);
+
+ lua_rawseti(L, -2, j+1);
+ }
+ }
+
+ lua_setfield(L, -2, "path");
+ lua_pop(L, 1); // The edge object
+ }
+
+ lua_settop(L, tos); // Cleanup
+}
+
+
+static void free_digraph(pgfgd_SyntacticDigraph* digraph)
+{
+ int i;
+ for (i=0; i < digraph->vertices.length; i++) {
+ pgfgd_Vertex* v = digraph->vertices.array[i];
+
+ clear_path(v->path);
+ free(v->path);
+ free(v->name);
+ free(v->shape);
+ free(v->kind);
+ free(v->options);
+ free(v->incoming.array);
+ free(v->outgoing.array);
+ free(v);
+ }
+
+ for (i=0; i < digraph->syntactic_edges.length; i++) {
+ pgfgd_Edge* e = digraph->syntactic_edges.array[i];
+
+ clear_path(e->path);
+ free(e->path);
+ free(e->direction);
+ free(e->options);
+ free(e);
+ }
+
+ free(digraph->vertices.array);
+ free(digraph->syntactic_edges.array);
+ free(digraph->options);
+ free(digraph->internals);
+ free(digraph);
+}
+
+static int algorithm_dispatcher(lua_State* L)
+{
+ // Create the back index table. It will be at index BACKINDEX_STORAGE_INDEX
+ lua_createtable(L, 0, MIN_HASH_SIZE_FIX);
+
+ // The actual function is stored in an upvalue.
+ pgfgd_SyntacticDigraph* digraph = (pgfgd_SyntacticDigraph*) calloc(1, sizeof(pgfgd_SyntacticDigraph));
+
+ construct_digraph(L, digraph);
+
+ pgfgd_algorithm_fun fun = lua_touserdata(L, lua_upvalueindex(FUNCTION_UPVALUE));
+ fun(digraph, lua_touserdata(L, lua_upvalueindex(USER_UPVALUE)));
+
+ sync_digraph(L, digraph);
+
+ free_digraph(digraph);
+
+ return 0;
+}
+
+
+int pgfgd_vertex_anchor(pgfgd_Vertex* v, const char* anchor, double* x, double* y)
+{
+ lua_State* L = v->options->state;
+
+ // Ok, first, find the vertex:
+ lua_rawgeti(L, VERTICES_INDEX, v->array_index+1);
+
+ // Find the anchor function:
+ lua_getfield(L, -1, "anchor");
+ lua_pushvalue(L, -2);
+ lua_pushstring(L, anchor);
+
+ // Find the anchor:
+ lua_call(L, 2, 1);
+
+ if (lua_isnil(L, -1)) {
+ // Failed. Cleanup!
+ lua_pop(L, 2);
+ *x = 0;
+ *y = 0;
+ return 0;
+ } else {
+ lua_getfield(L, -1, "x");
+ *x = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "y");
+ *y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+
+ lua_pop(L, 2);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+void pgfgd_path_clear(pgfgd_Edge* e)
+{
+ clear_path (e->path);
+}
+
+static void path_add_segment(pgfgd_Edge* edge, const char* s, int num, double a, double b, double c, double d, double e, double f)
+{
+ if (edge->path->length == -1)
+ pgfgd_path_clear(edge);
+
+ int start = edge->path->length;
+
+ edge->path->length += num + 1;
+ edge->path->strings = (char **)
+ realloc(edge->path->strings, edge->path->length*sizeof(char*));
+ edge->path->coordinates = (pgfgd_Coordinate*)
+ realloc(edge->path->coordinates, edge->path->length*sizeof(pgfgd_Coordinate));
+
+ edge->path->coordinates[start].x = 0;
+ edge->path->coordinates[start].y = 0;
+ edge->path->strings[start] = strcpy((char*) malloc(strlen(s)+1), s);
+
+ if (num > 0) {
+ edge->path->coordinates[start+1].x = a;
+ edge->path->coordinates[start+1].y = b;
+ edge->path->strings[start+1] = 0;
+ }
+
+ if (num > 1) {
+ edge->path->coordinates[start+2].x = c;
+ edge->path->coordinates[start+2].y = d;
+ edge->path->strings[start+2] = 0;
+ }
+
+ if (num > 2) {
+ edge->path->coordinates[start+3].x = e;
+ edge->path->coordinates[start+3].y = f;
+ edge->path->strings[start+3] = 0;
+ }
+}
+
+
+void pgfgd_path_append_moveto(pgfgd_Edge* e, double x, double y)
+{
+ path_add_segment(e, "moveto", 1, x, y, 0, 0, 0, 0);
+}
+
+void pgfgd_path_append_moveto_tail (pgfgd_Edge* e)
+{
+ double x, y;
+ char* tail_anchor = pgfgd_tostring(e->tail->options, "tail anchor");
+
+ pgfgd_vertex_anchor(e->tail, tail_anchor, &x, &y);
+ x += e->tail->pos.x;
+ y += e->tail->pos.y;
+
+ pgfgd_path_append_moveto(e, x, y);
+ free(tail_anchor);
+}
+
+void pgfgd_path_append_lineto(pgfgd_Edge* e, double x, double y)
+{
+ path_add_segment(e, "lineto", 1, x, y, 0, 0, 0, 0);
+}
+
+void pgfgd_path_append_lineto_head (pgfgd_Edge* e)
+{
+ double x, y;
+ char* head_anchor = pgfgd_tostring(e->head->options, "head anchor");
+
+ pgfgd_vertex_anchor(e->head, head_anchor, &x, &y);
+ x += e->head->pos.x;
+ y += e->head->pos.y;
+
+ pgfgd_path_append_lineto(e, x, y);
+ free(head_anchor);
+}
+
+void pgfgd_path_append_curveto(pgfgd_Edge* edge, double a, double b, double c, double d, double e, double f)
+{
+ path_add_segment(edge, "curveto", 3, a, b, c, d, e, f);
+}
+
+void pgfgd_path_append_closepath(pgfgd_Edge* e)
+{
+ path_add_segment(e, "closepath", 0, 0, 0, 0, 0, 0, 0);
+}
+
+
+
+// Handling digraphs
+
+struct pgfgd_Digraph {
+ lua_State* state;
+ const char* name;
+ pgfgd_SyntacticDigraph* syntactic_digraph;
+};
+
+
+pgfgd_Digraph* pgfgd_get_digraph (pgfgd_SyntacticDigraph* g, const char* graph_name)
+{
+ lua_State* L = g->internals->state;
+
+ lua_getfield(L, ALGORITHM_INDEX, graph_name);
+ if (lua_isnil(L, -1))
+ luaL_error(L, "digraph named %s not found in algorithm class", graph_name);
+ lua_pop(L, 1);
+
+ pgfgd_Digraph* new = (pgfgd_Digraph*) calloc(1, sizeof(pgfgd_Digraph));
+
+ new->state = L;
+ new->name = graph_name;
+ new->syntactic_digraph = g;
+
+ return new;
+}
+
+int pgfgd_digraph_num_vertices (pgfgd_Digraph* g)
+{
+ lua_getfield(g->state, ALGORITHM_INDEX, g->name);
+ lua_getfield(g->state, -1, "vertices");
+ int num = lua_rawlen(g->state, -1);
+ lua_pop(g->state, 2);
+
+ return num;
+}
+
+static void push_digraph_and_backindex(pgfgd_Digraph* g)
+{
+ lua_State* L = g->state;
+
+ // Get digraph
+ lua_getfield(L, ALGORITHM_INDEX, g->name);
+ int digraph_pos = lua_gettop(L);
+
+ // Get entry in back index table
+ lua_pushvalue(L, digraph_pos);
+ lua_gettable(L, BACKINDEX_STORAGE_INDEX);
+ int backtable_pos = lua_gettop(L);
+ if (lua_isnil(L, backtable_pos)) {
+ // Aha. We need to install a new table:
+ lua_pop(L, 1); // Get rid of nil
+
+ lua_createtable(L, 0, MIN_HASH_SIZE_FIX);
+
+ lua_pushvalue(L, digraph_pos); // The digraph object
+ lua_pushvalue(L, backtable_pos); // The new table
+ lua_settable(L, BACKINDEX_STORAGE_INDEX);
+
+ // Fill the table:
+ lua_getfield(L, digraph_pos, "vertices");
+ int vertex_pos = lua_gettop(L);
+ int i;
+ int n = lua_rawlen(L, -1);
+ for (i = 1; i <= n; i++) {
+ lua_rawgeti(L, vertex_pos, i);
+ lua_pushinteger(L, i);
+ lua_settable(L, backtable_pos);
+ }
+ lua_pop(L, 1);
+ }
+}
+
+static pgfgd_Arc_array* build_c_array_of_arcs_from_lua_array_of_arcs(pgfgd_Digraph* g)
+{
+ lua_State* L = g->state;
+
+ pgfgd_Arc_array* arcs = (pgfgd_Arc_array*) calloc(1, sizeof(pgfgd_Arc_array));
+
+ int array_pos = lua_gettop(L);
+
+ push_digraph_and_backindex(g);
+ int backtable_pos = lua_gettop(L);
+
+ // Get number of arcs:
+ init_arcs_array(arcs, lua_rawlen(L, array_pos));
+ int i;
+ for (i = 1; i<=arcs->length; i++) {
+ lua_rawgeti(L, array_pos, i); // Get arcs[i]
+
+ // The tail field:
+ lua_getfield(L, -1, "tail");
+ lua_gettable(L, backtable_pos);
+
+ arcs->tails[i-1] = lua_tointeger(L, -1);
+ lua_pop(L, 1); // The number
+
+ // The head field:
+ lua_getfield(L, -1, "head");
+ lua_gettable(L, backtable_pos);
+ arcs->heads[i-1] = lua_tointeger(L, -1);
+ lua_pop(L, 1); // The number
+
+ lua_pop(L, 1); // Pop arcs[i]
+ }
+
+ lua_settop(L, array_pos);
+
+ return arcs;
+}
+
+
+pgfgd_Arc_array* pgfgd_digraph_arcs (pgfgd_Digraph* g)
+{
+ lua_getfield(g->state, ALGORITHM_INDEX, g->name);
+ lua_getfield(g->state, -1, "arcs");
+
+ pgfgd_Arc_array* a = build_c_array_of_arcs_from_lua_array_of_arcs(g);
+
+ lua_pop(g->state, 2);
+
+ return a;
+}
+
+
+pgfgd_Vertex* pgfgd_digraph_syntactic_vertex (pgfgd_Digraph* g, int v)
+{
+ int tos = lua_gettop(g->state);
+ pgfgd_Vertex* return_me = 0;
+
+ lua_getfield(g->state, ALGORITHM_INDEX, g->name);
+ lua_getfield(g->state, -1, "vertices");
+ lua_rawgeti(g->state, -1, v);
+
+ lua_gettable(g->state, VERTICES_INDEX);
+ if (lua_isnumber(g->state, -1)) {
+ return_me = g->syntactic_digraph->vertices.array[lua_tointeger(g->state, -1)-1];
+ }
+
+ lua_settop(g->state, tos);
+ return return_me;
+}
+
+
+int pgfgd_digraph_isarc (pgfgd_Digraph* g, int tail, int head)
+{
+ lua_State* L = g->state;
+ int is_arc = 0;
+
+ lua_getfield(L, ALGORITHM_INDEX, g->name);
+ int digraph_pos = lua_gettop(L);
+
+ lua_getfield(L, digraph_pos, "vertices");
+ int vertices_pos = lua_gettop(L);
+
+ // Call digraph:connected(tail, head)
+ lua_pushvalue(L, lua_upvalueindex(DIGRAPH_OBJECT_UPVALUE));
+ lua_getfield(L, -1, "arc");
+ lua_pushvalue(L, digraph_pos);
+ lua_rawgeti(L, vertices_pos, tail);
+ lua_rawgeti(L, vertices_pos, head);
+ lua_call(L, 3, 1);
+
+ is_arc = !lua_isnil(L, -1);
+
+ lua_settop(L, digraph_pos-1);
+
+ return is_arc;
+}
+
+pgfgd_Arc_array* pgfgd_digraph_incoming (pgfgd_Digraph* g, int v)
+{
+ lua_State* L = g->state;
+
+ lua_getfield(L, ALGORITHM_INDEX, g->name);
+ int digraph_pos = lua_gettop(L);
+
+ lua_getfield(L, digraph_pos, "vertices");
+ int vertices_pos = lua_gettop(L);
+
+ // Call digraph:connected(tail, head)
+ lua_pushvalue(L, lua_upvalueindex(DIGRAPH_OBJECT_UPVALUE));
+ lua_getfield(L, -1, "incoming");
+ lua_pushvalue(L, digraph_pos);
+ lua_rawgeti(L, vertices_pos, v);
+ lua_call(L, 2, 1);
+
+ pgfgd_Arc_array* a = build_c_array_of_arcs_from_lua_array_of_arcs(g);
+
+ lua_settop(L, digraph_pos-1);
+
+ return a;
+}
+
+pgfgd_Arc_array* pgfgd_digraph_outgoing (pgfgd_Digraph* g, int v)
+{
+ lua_State* L = g->state;
+
+ lua_getfield(L, ALGORITHM_INDEX, g->name);
+ int digraph_pos = lua_gettop(L);
+
+ lua_getfield(L, digraph_pos, "vertices");
+ int vertices_pos = lua_gettop(L);
+
+ // Call digraph:connected(tail, head)
+ lua_pushvalue(L, lua_upvalueindex(DIGRAPH_OBJECT_UPVALUE));
+ lua_getfield(L, -1, "outgoing");
+ lua_pushvalue(L, digraph_pos);
+ lua_rawgeti(L, vertices_pos, v);
+ lua_call(L, 2, 1);
+
+ pgfgd_Arc_array* a = build_c_array_of_arcs_from_lua_array_of_arcs(g);
+
+ lua_settop(L, digraph_pos-1);
+
+ return a;
+}
+
+pgfgd_Edge_array* pgfgd_digraph_syntactic_edges (pgfgd_Digraph* g, int tail, int head)
+{
+ pgfgd_Edge_array* edges = (pgfgd_Edge_array*) calloc(1, sizeof(pgfgd_Edge_array));
+
+ // First, get the arc in the syntatic digraph.
+ lua_State* L = g->state;
+ int tos = lua_gettop(L);
+
+ lua_getfield(L, ALGORITHM_INDEX, g->name);
+ int digraph_pos = lua_gettop(L);
+
+ lua_getfield(L, digraph_pos, "vertices");
+ int vertices_pos = lua_gettop(L);
+
+ // Call digraph:arc(tail, head)
+ lua_pushvalue(L, lua_upvalueindex(DIGRAPH_OBJECT_UPVALUE));
+ int digraph_class_index = lua_gettop(L);
+
+ lua_getfield(L, digraph_class_index, "arc");
+ lua_pushvalue(L, digraph_pos);
+ lua_rawgeti(L, vertices_pos, tail);
+ lua_rawgeti(L, vertices_pos, head);
+ lua_call(L, 3, 1);
+
+ if (!lua_isnil(L, -1)) {
+ // Get syntactic_digraph of the arc:
+ lua_getfield(L, -1, "syntactic_digraph");
+
+ // Call syntactic_digraph:arc(tail, head)
+ lua_getfield(L, digraph_class_index, "arc");
+ lua_pushvalue(L, -2);
+ lua_rawgeti(L, vertices_pos, tail);
+ lua_rawgeti(L, vertices_pos, head);
+ lua_call(L, 3, 1);
+
+ if (!lua_isnil(L, -1)) {
+ lua_getfield(L, -1, "syntactic_edges");
+ int syntactic_edges_index = lua_gettop(L);
+
+ int n = lua_rawlen(L, syntactic_edges_index);
+ init_edge_array(edges, n);
+ int i;
+ for (i=1; i<=n; i++) {
+ lua_rawgeti(L, syntactic_edges_index, i);
+ lua_gettable(L, EDGES_INDEX);
+ if (!lua_isnumber(L, -1)) {
+ pgfgd_digraph_free_edge_array(edges);
+ luaL_error(L, "syntactic edge index not found");
+ }
+ int p = lua_tonumber(L, -1);
+ edges->array[i-1] = g->syntactic_digraph->syntactic_edges.array[p-1];
+ }
+ }
+ }
+
+ lua_settop(L, tos);
+
+ return edges;
+}
+
+
+
+void pgfgd_digraph_free (pgfgd_Digraph* g)
+{
+ free(g);
+}
+
+void pgfgd_digraph_free_arc_array (pgfgd_Arc_array* arcs)
+{
+ free (arcs->tails);
+ free (arcs->heads);
+ free (arcs);
+}
+
+void pgfgd_digraph_free_edge_array (pgfgd_Edge_array* edges)
+{
+ free (edges->array);
+ free (edges);
+}
+
+
+
+// Handling declarations
+
+
+struct pgfgd_Declaration {
+ const char* key;
+ const char* summary;
+ const char* type;
+ const char* initial;
+ void* initial_user;
+ const char* default_value;
+ const char* alias;
+ const char* alias_function_string;
+ const char* documentation;
+ const char* documentation_in;
+ pgfgd_algorithm_fun algorithm;
+ void* algorithm_user;
+ const char* phase;
+
+ int use_length;
+ const char** use_keys;
+ const char** use_values_strings;
+ void** use_values_user;
+
+ int examples_length;
+ const char** examples;
+
+ int pre_length;
+ const char** pre;
+
+ int post_length;
+ const char** post;
+};
+
+
+pgfgd_Declaration* pgfgd_new_key (const char* key)
+{
+ pgfgd_Declaration* d = (pgfgd_Declaration*) calloc(1, sizeof(pgfgd_Declaration));
+
+ d->key = key;
+
+ return d;
+}
+
+void pgfgd_declare(struct lua_State* state, pgfgd_Declaration* d)
+{
+ if (d && d->key) {
+ int tos = lua_gettop(state);
+
+ lua_gc(state, LUA_GCSTOP, 0); // Remove once Lua Link Bug is fixed
+
+ // Find declare function:
+ lua_getglobal(state, "require");
+ lua_pushstring(state, "pgf.gd.interface.InterfaceToAlgorithms");
+ lua_call(state, 1, 1);
+ lua_getfield(state, -1, "declare");
+
+ // Build a Lua table:
+ lua_createtable(state, 0, 11);
+
+ set_field (state, d->key, "key");
+ set_field (state, d->summary, "summary");
+ set_field (state, d->type, "type");
+ set_field (state, d->initial, "initial");
+ set_field (state, d->documentation, "documentation");
+ set_field (state, d->documentation_in, "documentation_in");
+ set_field (state, d->default_value, "default");
+ set_field (state, d->alias, "alias");
+ set_field (state, d->alias_function_string, "alias_function_string");
+ set_field (state, d->phase, "phase");
+
+ if (d->initial_user) {
+ lua_pushlightuserdata(state, d->initial_user);
+ lua_setfield(state, -2, "initial");
+ }
+
+ if (d->use_length > 0) {
+ lua_createtable(state, d->use_length, MIN_HASH_SIZE_FIX);
+ int i;
+ for (i=0; i < d->use_length; i++) {
+ lua_createtable(state, 0, 2);
+ set_field(state, d->use_keys[i], "key");
+ if (d->use_values_strings[i])
+ set_field(state, d->use_values_strings[i], "value");
+ if (d->use_values_user[i]) {
+ lua_pushlightuserdata(state, d->use_values_user[i]);
+ lua_setfield(state, -2, "value");
+ }
+ lua_rawseti(state, -2, i+1);
+ }
+ lua_setfield(state, -2, "use");
+ }
+
+ if (d->pre) {
+ lua_createtable(state, 0, d->pre_length);
+ int i;
+ for (i=0; i < d->pre_length; i++) {
+ lua_pushboolean(state, 1);
+ lua_setfield(state, -2, d->pre[i]);
+ }
+ lua_setfield(state, -2, "preconditions");
+ }
+
+ if (d->post) {
+ lua_createtable(state, 0, d->post_length);
+ int i;
+ for (i=0; i < d->post_length; i++) {
+ lua_pushboolean(state, 1);
+ lua_setfield(state, -2, d->post[i]);
+ }
+ lua_setfield(state, -2, "postconditions");
+ }
+
+ if (d->examples) {
+ lua_createtable(state, d->examples_length, MIN_HASH_SIZE_FIX);
+ int i;
+ for (i=0; i < d->examples_length; i++) {
+ lua_pushstring(state, d->examples[i]);
+ lua_rawseti(state, -2, i+1);
+ }
+ lua_setfield(state, -2, "examples");
+ }
+
+ if (d->algorithm) {
+ // The algorithm function and the user data is stored as lightuserdate upvalue
+ lua_pushlightuserdata(state, (void *) d->algorithm);
+ lua_pushlightuserdata(state, (void *) d->algorithm_user);
+
+ // Find the Digraph.arc function and store it as the second upvalue:
+ lua_getglobal(state, "require");
+ lua_pushstring(state, "pgf.gd.model.Digraph");
+ lua_call(state, 1, 1);
+
+ lua_pushcclosure(state, algorithm_dispatcher, 3);
+ lua_setfield(state, -2, "algorithm_written_in_c");
+ }
+
+ // Call the declare function:
+ lua_call(state, 1, 0);
+
+ // Cleanup:
+ lua_settop(state, tos);
+
+ lua_gc(state, LUA_GCRESTART, 0); // Remove once Lua Link Bug is fixed
+ }
+}
+
+void pgfgd_key_add_use(pgfgd_Declaration* d, const char* key, const char* value)
+{
+ d->use_length++;
+ d->use_keys = (const char **) realloc(d->use_keys, d->use_length*sizeof(const char*));
+ d->use_values_strings = (const char **) realloc(d->use_values_strings, d->use_length*sizeof(const char*));
+ d->use_values_user = (void **) realloc(d->use_values_user, d->use_length*sizeof(void*));
+
+ d->use_keys [d->use_length-1] = key;
+ d->use_values_strings[d->use_length-1] = value;
+ d->use_values_user [d->use_length-1] = 0;
+}
+
+void pgfgd_key_add_use_user(pgfgd_Declaration* d, const char* key, void* value)
+{
+ d->use_length++;
+ d->use_keys = (const char **) realloc(d->use_keys, d->use_length*sizeof(const char*));
+ d->use_values_strings = (const char **) realloc(d->use_values_strings, d->use_length*sizeof(const char*));
+ d->use_values_user = (void **) realloc(d->use_values_user, d->use_length*sizeof(void*));
+
+ d->use_keys [d->use_length-1] = key;
+ d->use_values_strings[d->use_length-1] = 0;
+ d->use_values_user [d->use_length-1] = value;
+}
+
+void pgfgd_key_add_example(pgfgd_Declaration* d, const char* s)
+{
+ d->examples_length++;
+ d->examples = (const char **) realloc(d->examples, d->examples_length*sizeof(const char*));
+
+ d->examples[d->examples_length-1] = s;
+}
+
+void pgfgd_key_add_precondition(pgfgd_Declaration* d, const char* s)
+{
+ d->pre_length++;
+ d->pre = (const char **) realloc(d->pre, d->pre_length*sizeof(const char*));
+
+ d->pre[d->pre_length-1] = s;
+}
+
+void pgfgd_key_add_postcondition(pgfgd_Declaration* d, const char* s)
+{
+ d->post_length++;
+ d->post = (const char **) realloc(d->post, d->post_length*sizeof(const char*));
+
+ d->post[d->post_length-1] = s;
+}
+
+void pgfgd_key_summary(pgfgd_Declaration* d, const char* s)
+{
+ d->summary = s;
+}
+
+void pgfgd_key_type(pgfgd_Declaration* d, const char* s)
+{
+ d->type = s;
+}
+
+void pgfgd_key_initial(pgfgd_Declaration* d, const char* s)
+{
+ d->initial = s;
+}
+
+void pgfgd_key_initial_user(pgfgd_Declaration* d, void* s)
+{
+ d->initial_user = s;
+}
+
+void pgfgd_key_default(pgfgd_Declaration* d, const char* s)
+{
+ d->default_value = s;
+}
+
+void pgfgd_key_alias(pgfgd_Declaration* d, const char* s)
+{
+ d->alias = s;
+}
+
+void pgfgd_key_alias_function(pgfgd_Declaration* d, const char* s)
+{
+ d->alias_function_string = s;
+}
+
+void pgfgd_key_documentation(pgfgd_Declaration* d, const char* s)
+{
+ d->documentation = s;
+}
+
+void pgfgd_key_documentation_in(pgfgd_Declaration* d, const char* s)
+{
+ d->documentation_in = s;
+}
+
+void pgfgd_key_phase(pgfgd_Declaration* d, const char* s)
+{
+ d->phase = s;
+}
+
+void pgfgd_key_algorithm(pgfgd_Declaration* d, pgfgd_algorithm_fun f, void* user_data)
+{
+ d->algorithm = f;
+ d->algorithm_user = user_data;
+}
+
+void pgfgd_free_key(pgfgd_Declaration* d)
+{
+ if (d) {
+ free(d->examples);
+ free(d->use_keys);
+ free(d->use_values_user);
+ free(d->use_values_strings);
+ free(d);
+ }
+}