From 3a6db0ec5566561bc194d4870648be812a7d989e Mon Sep 17 00:00:00 2001 From: Tobias Boege Date: Sat, 13 Sep 2014 03:01:37 +0000 Subject: [PATCH] [GB.DATA] * NEW: Graph and GraphMatrix work now. Graph implementations in Gambas are as powerful as native ones. git-svn-id: svn://localhost/gambas/trunk@6468 867c0c6c-44f3-4631-809d-bfa615b0a4ec --- main/lib/data/TODO | 25 +- main/lib/data/c_avltree.c | 3 +- main/lib/data/c_graph.c | 430 ++++++++++++++++++++++++---------- main/lib/data/c_graph.h | 35 ++- main/lib/data/c_graphmatrix.c | 308 ++++++++++++++---------- main/lib/data/c_graphmatrix.h | 3 +- main/lib/data/c_list.c | 6 +- main/lib/data/main.c | 10 +- 8 files changed, 560 insertions(+), 260 deletions(-) diff --git a/main/lib/data/TODO b/main/lib/data/TODO index 44fe326f0..fd28e71d2 100644 --- a/main/lib/data/TODO +++ b/main/lib/data/TODO @@ -26,9 +26,9 @@ AvlTree: * NEW: Add a Copy() method to return a deep copy of an AvlTree. * NEW: Split() is a new method of AvlTree to return the left or right subtree of a given node or both. -* NEW: Add Insert() to insert an AvlTree into another one. -* NEW: Add PreOrder, PostOrder, Reverse and LevelOrder virtual properties to - specify the enumeration flavour. +* NEW: Add Insert() to insert an AvlTree into another one. (See a thread on + stackoverflow about an O(log n) algorithm for that.) +* NEW: Add the Reverse virtual property to traver in reverse in-order. Trie: * BUG: Maintain lexicographical order in Trie. @@ -37,3 +37,22 @@ Graph: * Write down the hidden methods and their signatures * Set down the relationships between methods; which default implementation calls what; what is minimum needed to implement a fully-functional Graph + +RedBlackTree: +* NEW: RedBlackTree class. + +SearchTree: +* NEW: SearchTree is the base class of all search trees. + +PrioQueue: +* NEW: Re-implement PrioQueue using a RedBlackTree. + -> contain structures (key, time, value) where key is the key and time + is a logical timestamp (rbtree->clock++). If key1 == key2, then compare + the unique insertion timestamps. +* OPT: Don't have Integer priority parameters. Consistently use + GB.CompVariant() to compare elements. This is at least as mighty as + integer priorities, but better encapsulated. + +- First: Graph, PrioSet, Trie. +- Use libtree to provide some trees (if possible). +- General, navigatable tree class. diff --git a/main/lib/data/c_avltree.c b/main/lib/data/c_avltree.c index 0f36ad666..3dd1f40ac 100644 --- a/main/lib/data/c_avltree.c +++ b/main/lib/data/c_avltree.c @@ -766,8 +766,7 @@ GB_DESC CAvlTree[] = { #if 0 GB_DESC CAvlTreeSplit[] = { - GB_DECLARE(".AvlTree.Split", 0), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".AvlTree.Split"), GB_PROPERTY_READ("Left", "AvlTree", AvlTreeSplit_Left), GB_PROPERTY_READ("Right", "AvlTree", AvlTreeSplit_Right), diff --git a/main/lib/data/c_graph.c b/main/lib/data/c_graph.c index bcf213dc4..ca0a4feff 100644 --- a/main/lib/data/c_graph.c +++ b/main/lib/data/c_graph.c @@ -21,15 +21,30 @@ #define __C_GRAPH_C -#include +#include #include "gambas.h" #include "c_graph.h" -typedef struct { - GB_BASE ob; - GB_VARIANT_VALUE tag; -} CGRAPH; +static GB_HASHTABLE interfaces; + +BEGIN_METHOD_VOID(Graph_init) + + GB.HashTable.New(&interfaces, GB_COMP_BINARY); + +END_METHOD + +static void enum_func(void *x) +{ + GB.Free(&x); +} + +BEGIN_METHOD_VOID(Graph_exit) + + GB.HashTable.Enum(interfaces, (GB_HASHTABLE_ENUM_FUNC) enum_func); + GB.HashTable.Free(&interfaces); + +END_METHOD BEGIN_METHOD_VOID(Graph_NoMethod) @@ -54,11 +69,73 @@ BEGIN_METHOD(Graph_call, GB_BOOLEAN d; GB_BOOLEAN w) END_METHOD +#define get_func(func, arg, ret, need) \ +do { \ + GB_FUNCTION f; \ + \ + err = #func; \ + if (GB.GetFunction(&f, _object, #func, arg, ret)) { \ + if (need) \ + goto error; \ + else /* Clear error */ \ + GB.Error(NULL); \ + desc->func = NULL; \ + } else { \ + desc->func = f.desc; \ + } \ +} while(0) + +GRAPH_DESC *get_desc(void *_object) +{ + GRAPH_DESC *desc; + const char *err; + + GB.Alloc((void **) &desc, sizeof(*desc)); + get_func(_getVertex, "s", NULL, 0); + get_func(_getEdge, "ss", NULL, 0); + get_func(_nextVertex, NULL, "s", 0); + get_func(_nextEdge, NULL, "String[]", 0); + get_func(_countVertices, NULL, "i", 0); + get_func(_countEdges, NULL, "i", 0); + get_func(_nextInEdge, NULL, "String[]", 0); + get_func(_nextOutEdge, NULL, "String[]", 0); + get_func(_nextAdjacent, NULL, "s", 0); + get_func(_vertexProperty, ".", "b", 0); + get_func(_edgeProperty, ".", "b", 0); + get_func(_vertexUnknown, ".", "v", 0); + get_func(_edgeUnknown, ".", "v", 0); + return desc; + +error: + GB.Error("Method \"&1\" not found", err); + GB.Free((void **) &desc); + return NULL; +} + #define THIS ((CGRAPH *) _object) +BEGIN_METHOD_VOID(Graph_new) + + GRAPH_DESC *desc; + char *name = GB.GetClassName(THIS); + size_t len = GB.StringLength(name); + + if (GB.HashTable.Get(interfaces, name, len, (void **) &desc)) { + desc = get_desc(THIS); + GB.HashTable.Add(interfaces, name, len, desc); + } + THIS->desc = desc; + THIS->vertex = NULL; + GB.Array.New(&THIS->edge, GB_T_STRING, 2); + THIS->tag.type = GB_T_NULL; + +END_METHOD + BEGIN_METHOD_VOID(Graph_free) GB.StoreVariant(NULL, &THIS->tag); + GB.Unref(&THIS->edge); + GB.FreeString(&THIS->vertex); END_METHOD @@ -72,15 +149,63 @@ BEGIN_PROPERTY(Graph_Tag) END_PROPERTY +#define SET_VERTEX() \ +do { \ + GB.FreeString(&THIS->vertex); \ + THIS->vertex = GB.NewString(STRING(vert), LENGTH(vert));\ +} while (0) + +#define SET_VERTEX_P() \ +do { \ + GB.FreeString(&THIS->vertex); \ + THIS->vertex = GB.NewString(PSTRING(), PLENGTH()); \ +} while (0) + +#define SET_EDGE() \ +do { \ + GB.StoreString(ARG(src), GB.Array.Get(THIS->edge, 0)); \ + GB.StoreString(ARG(dst), GB.Array.Get(THIS->edge, 1)); \ +} while (0) + +#define SET_EDGE_P() \ +do { \ + GB.StoreObject(VPROP(GB_OBJECT), &THIS->edge); \ +} while (0) + +BEGIN_PROPERTY(Graph_Vertex) + + if (READ_PROPERTY) { + GB.ReturnString(THIS->vertex); + return; + } + SET_VERTEX_P(); + +END_PROPERTY + +BEGIN_PROPERTY(Graph_Edge) + + if (READ_PROPERTY) { + GB.ReturnObject(THIS->edge); + return; + } + SET_EDGE_P(); + +END_PROPERTY + GB_DESC CGraph[] = { GB_DECLARE("Graph", sizeof(CGRAPH)), GB_NOT_CREATABLE(), + GB_STATIC_METHOD("_init", NULL, Graph_init, NULL), + GB_STATIC_METHOD("_exit", NULL, Graph_exit, NULL), + GB_STATIC_METHOD("_call", "Graph", Graph_call, "[(Directed)b(Weighted)b]"), + GB_METHOD("_new", NULL, Graph_new, NULL), GB_METHOD("_free", NULL, Graph_free, NULL), - GB_METHOD("_getVertex", "_Graph_Vertex", Graph_NoMethod, "(Vertex)s"), - GB_METHOD("_getEdge", "_Graph_Edge", Graph_NoMethod, "(Src)s(Dst)s"), + /* Graph */ + GB_METHOD("_getVertex", ".Graph.Vertex", Graph_NoMethod, "(Vertex)s"), + GB_METHOD("_getEdge", ".Graph.Edge", Graph_NoMethod, "(Src)s(Dst)s"), GB_METHOD("_nextVertex", "s", Graph_NoMethod, NULL), GB_METHOD("_nextEdge", "String[]", Graph_NoMethod, NULL), @@ -88,30 +213,40 @@ GB_DESC CGraph[] = { GB_METHOD("_countVertices", "i", Graph_NoMethod, NULL), GB_METHOD("_countEdges", "i", Graph_NoMethod, NULL), - GB_METHOD("Add", "_Graph_Vertex", Graph_NoMethod, "(Name)s"), + /* Vertex */ + GB_METHOD("_nextInEdge", "String[]", Graph_NoMethod, NULL), + GB_METHOD("_nextOutEdge", "String[]", Graph_NoMethod, NULL), + + /* Public */ + GB_METHOD("Add", ".Graph.Vertex", Graph_NoMethod, "(Name)s"), GB_METHOD("Remove", NULL, Graph_NoMethod, "(Vertex)s"), - GB_METHOD("Connect", "_Graph_Edge", Graph_NoMethod, "(Src)s(Dst)s"), + GB_METHOD("Connect", ".Graph.Edge", Graph_NoMethod, "(Src)s(Dst)s"), GB_METHOD("Disconnect", NULL, Graph_NoMethod, "(Src)s(Dst)s"), GB_PROPERTY("Tag", "v", Graph_Tag), + GB_PROPERTY("_Vertex", "s", Graph_Vertex), + GB_PROPERTY("_Edge", "String[]", Graph_Edge), + GB_PROPERTY_SELF("Vertices", ".Graph.Vertices"), GB_PROPERTY_SELF("Edges", ".Graph.Edges"), + GB_PROPERTY_SELF("InEdges", ".Graph.InEdges"), + GB_PROPERTY_SELF("OutEdges", ".Graph.OutEdges"), + GB_PROPERTY_SELF("Adjacent", ".Graph.Adjacent"), + GB_END_DECLARE }; /* * Call another method/property of this class and fail if not found. */ -#define CALL_GRAPH(func, narg, arg, ret) \ +#define CALL_GRAPH(func, narg) \ do { \ GB_FUNCTION f; \ \ - if (GB.GetFunction(&f, _object, func, arg, ret)) { \ - GB.Error("Method " func " not found"); \ - return; \ - } \ + f.desc = THIS->desc->func; \ + f.object = THIS; \ GB.Call(&f, narg, 0); \ } while (0) @@ -130,154 +265,72 @@ do { \ * Try to call another method/property of this class. If found, return * afterwards. If not, continue. */ -#define TRY_CALL_GRAPH(func, narg, arg, ret) \ +#define TRY_CALL_GRAPH(func, narg) \ do { \ - GB_FUNCTION f; \ - \ - if (!GB.GetFunction(&f, _object, func, arg, ret)) { \ - GB.Call(&f, narg, 0); \ + if (THIS->desc->func) { \ + CALL_GRAPH(func, narg); \ return; \ } \ } while (0) BEGIN_METHOD_VOID(GraphVertices_next) - CALL_GRAPH("_nextVertex", 0, NULL, "s"); + CALL_GRAPH(_nextVertex, 0); END_METHOD BEGIN_METHOD(GraphVertices_get, GB_STRING vert) - GB.Push(1, GB_T_STRING, STRING(vert), LENGTH(vert)); - CALL_GRAPH("_getVertex", 1, "s", NULL); + SET_VERTEX(); + GB.ReturnSelf(THIS); END_METHOD BEGIN_PROPERTY(GraphVertices_Count) - TRY_CALL_GRAPH("_countVertices", 0, NULL, "i"); - - /* Default: enumerate the vertices, counting */ + CALL_GRAPH(_countVertices, 0); + /* Default: enumerate the vertices, counting. Then use + * TRY_CALL_GRAPH. */ END_PROPERTY GB_DESC CGraphVertices[] = { - GB_DECLARE(".Graph.Vertices", 0), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".Graph.Vertices"), GB_METHOD("_next", "s", GraphVertices_next, NULL), - GB_METHOD("_get", "_Graph_Vertex", GraphVertices_get, "(Vertex)s"), + GB_METHOD("_get", ".Graph.Vertex", GraphVertices_get, "(Vertex)s"), GB_PROPERTY_READ("Count", "i", GraphVertices_Count), GB_END_DECLARE }; -BEGIN_PROPERTY(GraphVertex_InDegree) - - /* Default: enumerate */ - -END_PROPERTY - -BEGIN_PROPERTY(GraphVertex_OutDegree) - - /* Default: enumerate */ - -END_PROPERTY - -GB_DESC CGraphVertex[] = { - GB_DECLARE("_Graph_Vertex", 0), - GB_VIRTUAL_CLASS(), - - GB_METHOD("_nextInEdge", "String[]", Graph_NoMethod, NULL), - GB_METHOD("_nextOutEdge", "String[]", Graph_NoMethod, NULL), - GB_METHOD("_nextAdjacent", "s", Graph_NoMethod, NULL), - - GB_PROPERTY_READ("InDegree", "i", GraphVertex_InDegree), - GB_PROPERTY_READ("OutDegree", "i", GraphVertex_OutDegree), - GB_PROPERTY("Name", "s", Graph_NoProperty), - GB_PROPERTY("Value", "v", Graph_NoProperty), - - GB_PROPERTY_SELF("InEdges", ".Vertex.InEdges"), - GB_PROPERTY_SELF("OutEdges", ".Vertex.OutEdges"), - GB_PROPERTY_SELF("Adjacent", ".Vertex.Adjacent"), - - GB_END_DECLARE -}; - -BEGIN_METHOD_VOID(VertexInEdges_next) - - CALL_GRAPH("_nextInEdge", 0, NULL, "String[]"); - -END_METHOD - -GB_DESC CVertexInEdges[] = { - GB_DECLARE(".Vertex.InEdges", 0), - GB_VIRTUAL_CLASS(), - - GB_METHOD("_next", "String[]", VertexInEdges_next, NULL), - - GB_END_DECLARE -}; - -BEGIN_METHOD_VOID(VertexOutEdges_next) - - CALL_GRAPH("_nextOutEdge", 0, NULL, "String[]"); - -END_METHOD - -GB_DESC CVertexOutEdges[] = { - GB_DECLARE(".Vertex.OutEdges", 0), - GB_VIRTUAL_CLASS(), - - GB_METHOD("_next", "String[]", VertexOutEdges_next, NULL), - - GB_END_DECLARE -}; - -BEGIN_METHOD_VOID(VertexAdjacent_next) - - CALL_GRAPH("_nextAdjacent", 0, NULL, "s"); - -END_METHOD - -GB_DESC CVertexAdjacent[] = { - GB_DECLARE(".Vertex.Adjacent", 0), - GB_VIRTUAL_CLASS(), - - GB_METHOD("_next", "s", VertexAdjacent_next, NULL), - - GB_END_DECLARE -}; - BEGIN_METHOD_VOID(GraphEdges_next) - CALL_GRAPH("_nextEdge", 0, NULL, "String[]"); + CALL_GRAPH(_nextEdge, 0); END_METHOD BEGIN_METHOD(GraphEdges_get, GB_STRING src; GB_STRING dst) - GB.Push(2, GB_T_STRING, STRING(src), LENGTH(src), - GB_T_STRING, STRING(dst), LENGTH(dst)); - CALL_GRAPH("_getEdge", 2, "ss", NULL); + SET_EDGE(); + GB.ReturnSelf(THIS); END_METHOD BEGIN_PROPERTY(GraphEdges_Count) - TRY_CALL_GRAPH("_countEdges", 0, NULL, "i"); - - /* Default: enumerate the edges, counting */ + CALL_GRAPH(_countEdges, 0); + /* Default: enumerate the edges, counting. Then use + * TRY_CALL_GRAPH. */ END_PROPERTY GB_DESC CGraphEdges[] = { - GB_DECLARE(".Graph.Edges", 0), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".Graph.Edges"), GB_METHOD("_next", "String[]", GraphEdges_next, NULL), - GB_METHOD("_get", "_Graph_Edge", GraphEdges_get, "(Src)s(Dst)s"), + GB_METHOD("_get", ".Graph.Edge", GraphEdges_get, "(Src)s(Dst)s"), GB_METHOD("Exist", "b", Graph_NoMethod, "(Src)s(Dst)s"), GB_PROPERTY_READ("Count", "i", GraphEdges_Count), @@ -285,16 +338,147 @@ GB_DESC CGraphEdges[] = { GB_END_DECLARE }; -GB_DESC CGraphEdge[] = { - GB_DECLARE("_Graph_Edge", 0), - GB_VIRTUAL_CLASS(), +BEGIN_METHOD(GraphInEdges_get, GB_STRING vert) - GB_PROPERTY_READ("Src", "s", Graph_NoProperty), - GB_PROPERTY_READ("Dst", "s", Graph_NoProperty), - GB_PROPERTY("Weight", "f", Graph_NoProperty), + SET_VERTEX(); + GB.ReturnSelf(THIS); - GB_PROPERTY_READ("Source", "s", Graph_NoProperty), - GB_PROPERTY_READ("Destination", "s", Graph_NoProperty), +END_METHOD + +BEGIN_METHOD_VOID(GraphInEdges_next) + + CALL_GRAPH(_nextInEdge, 0); + +END_METHOD + +GB_DESC CGraphInEdges[] = { + GB_DECLARE_VIRTUAL(".Graph.InEdges"), + + GB_METHOD("_get", ".Graph.InEdges", GraphInEdges_get, "(Vertex)s"), + GB_METHOD("_next", "String[]", GraphInEdges_next, NULL), + + GB_END_DECLARE +}; + +BEGIN_METHOD(GraphOutEdges_get, GB_STRING vert) + + SET_VERTEX(); + GB.ReturnSelf(THIS); + +END_METHOD + +BEGIN_METHOD_VOID(GraphOutEdges_next) + + CALL_GRAPH(_nextOutEdge, 0); + +END_METHOD + +GB_DESC CGraphOutEdges[] = { + GB_DECLARE_VIRTUAL(".Graph.OutEdges"), + + GB_METHOD("_get", ".Graph.OutEdges", GraphOutEdges_get, "(Vertex)s"), + GB_METHOD("_next", "String[]", GraphOutEdges_next, NULL), + + GB_END_DECLARE +}; + +BEGIN_METHOD(GraphAdjacent_get, GB_STRING vert) + + SET_VERTEX(); + GB.ReturnSelf(THIS); + +END_METHOD + +BEGIN_METHOD_VOID(GraphAdjacent_next) + + CALL_GRAPH(_nextAdjacent, 0); + +END_METHOD + +GB_DESC CGraphAdjacent[] = { + GB_DECLARE_VIRTUAL(".Graph.Adjacent"), + + GB_METHOD("_get", ".Graph.Adjacent", GraphAdjacent_get, "(Vertex)s"), + GB_METHOD("_next", "s", GraphAdjacent_next, NULL), + + GB_END_DECLARE +}; + +BEGIN_PROPERTY(GraphVertex_InDegree) + + /* Call ??? */ + /* Default: enumerate */ + assert(0); + +END_PROPERTY + +BEGIN_PROPERTY(GraphVertex_OutDegree) + + /* Call ??? */ + /* Default: enumerate */ + assert(0); + +END_PROPERTY + +BEGIN_METHOD_VOID(GraphVertex_property) + + CALL_GRAPH(_vertexProperty, GB.NParam()); + +END_METHOD + +BEGIN_METHOD_VOID(GraphVertex_unknown) + + CALL_GRAPH(_vertexUnknown, GB.NParam()); + +END_METHOD + +GB_DESC CGraphVertex[] = { + GB_DECLARE_VIRTUAL(".Graph.Vertex"), + + GB_PROPERTY_READ("InDegree", "i", GraphVertex_InDegree), + GB_PROPERTY_READ("OutDegree", "i", GraphVertex_OutDegree), + + GB_METHOD("_property", "b", GraphVertex_property, "."), + GB_METHOD("_unknown", "v", GraphVertex_unknown, "."), + + GB_END_DECLARE +}; + +BEGIN_PROPERTY(GraphEdge_Src) + + GB.ReturnString(GB.Array.Get(THIS->edge, 0)); + +END_PROPERTY + +BEGIN_PROPERTY(GraphEdge_Dst) + + GB.ReturnString(GB.Array.Get(THIS->edge, 1)); + +END_PROPERTY + +BEGIN_METHOD_VOID(GraphEdge_property) + + CALL_GRAPH(_edgeProperty, GB.NParam()); + +END_METHOD + +BEGIN_METHOD_VOID(GraphEdge_unknown) + + CALL_GRAPH(_edgeUnknown, GB.NParam()); + +END_METHOD + +GB_DESC CGraphEdge[] = { + GB_DECLARE_VIRTUAL(".Graph.Edge"), + + GB_PROPERTY_READ("Src", "s", GraphEdge_Src), + GB_PROPERTY_READ("Dst", "s", GraphEdge_Dst), + + GB_PROPERTY_READ("Source", "s", GraphEdge_Src), + GB_PROPERTY_READ("Destination", "s", GraphEdge_Dst), + + GB_METHOD("_property", "b", GraphEdge_property, "."), + GB_METHOD("_unknown", "v", GraphEdge_unknown, "."), GB_END_DECLARE }; diff --git a/main/lib/data/c_graph.h b/main/lib/data/c_graph.h index 5a72d5384..c893e7374 100644 --- a/main/lib/data/c_graph.h +++ b/main/lib/data/c_graph.h @@ -26,9 +26,40 @@ extern GB_INTERFACE GB; +typedef struct { + void *_getVertex; + void *_getEdge; + + void *_nextVertex; + void *_nextEdge; + + void *_countVertices; + void *_countEdges; + + void *_nextInEdge; + void *_nextOutEdge; + void *_nextAdjacent; + + void *_vertexProperty; + void *_edgeProperty; + + void *_vertexUnknown; + void *_edgeUnknown; +} GRAPH_DESC; + +typedef struct { + GB_BASE ob; + GRAPH_DESC *desc; + char *vertex; + GB_ARRAY edge; + GB_VARIANT_VALUE tag; +} CGRAPH; + +extern GRAPH_DESC *get_desc(void *_object); + #ifndef __C_GRAPH_C -extern GB_DESC CGraph[], CGraphVertices[], CGraphVertex[], CVertexInEdges[], - CVertexOutEdges[], CVertexAdjacent[], CGraphEdges[], +extern GB_DESC CGraph[], CGraphVertices[], CGraphEdges[], CGraphInEdges[], + CGraphOutEdges[], CGraphAdjacent[], CGraphVertex[], CGraphEdge[]; #endif diff --git a/main/lib/data/c_graphmatrix.c b/main/lib/data/c_graphmatrix.c index e9d3b8980..338bad2e2 100644 --- a/main/lib/data/c_graphmatrix.c +++ b/main/lib/data/c_graphmatrix.c @@ -21,10 +21,10 @@ #define __C_GRAPHMATRIX_C -#include #include #include "gambas.h" +#include "c_graph.h" #include "c_graphmatrix.h" #define E_NOVERTEX "Vertex does not exist" @@ -45,22 +45,28 @@ typedef struct { char *name; } VERT; -/* Used as virtual object selector or in enumeration states */ -union vertex_edge { +/* Virtual object selector or part of enumeration state */ +union virt { unsigned int vertex; struct { - unsigned int src; - unsigned int dst; - } edge; + unsigned int src, dst; + }; }; typedef struct { - GB_BASE ob; + CGRAPH base; int directed : 1; int weighted : 1; GB_HASHTABLE names; VERT *matrix; - union vertex_edge v; + /* + * NOTE: This field is used by the "true" virtual object portions of + * this class: GraphMatrix.Vertices[x] and GraphMatrix.Edges[x, y]. + * + * In the enumerators (InEdges, OutEdges, Adjacent), we must use the + * "current" vertex/edge which is stored within ->base. + */ + union virt v; void *gsl_matrix; /* Cache gb.gsl Matrix object of this */ } CMATRIX; @@ -71,7 +77,7 @@ BEGIN_METHOD(Matrix_new, GB_BOOLEAN d; GB_BOOLEAN w) THIS->directed = VARGOPT(d, 0); THIS->weighted = VARGOPT(w, 0); THIS->v.vertex = -1; - THIS->v.edge.src = THIS->v.edge.dst = -1; + THIS->v.src = THIS->v.dst = -1; GB.HashTable.New(&THIS->names, GB_COMP_NOCASE); GB.NewArray(&THIS->matrix, sizeof(*THIS->matrix), 0); THIS->gsl_matrix = NULL; @@ -105,6 +111,12 @@ static unsigned int get_vertex(CMATRIX *mat, const char *str, size_t len) return (unsigned int) vert; } +static unsigned int get_cur_vertex(CMATRIX *mat) +{ + return get_vertex(mat, mat->base.vertex, + GB.StringLength(mat->base.vertex)); +} + BEGIN_METHOD(Matrix_getVertex, GB_STRING vert) unsigned int vert = get_vertex(THIS, STRING(vert), LENGTH(vert)); @@ -131,14 +143,13 @@ BEGIN_METHOD(Matrix_getEdge, GB_STRING src; GB_STRING dst) GB.Error(E_NOEDGE); return; } - THIS->v.edge.src = src; - THIS->v.edge.dst = dst; + THIS->v.src = src; THIS->v.dst = dst; GB.ReturnSelf(THIS); END_METHOD struct enum_state { - union vertex_edge cur; + union virt v; GB_ARRAY e; }; @@ -146,11 +157,11 @@ BEGIN_METHOD_VOID(Matrix_nextVertex) struct enum_state *state = GB.GetEnum(); - if (state->cur.vertex == GB.Count(THIS->matrix)) { + if (state->v.vertex == GB.Count(THIS->matrix)) { GB.StopEnum(); return; } - GB.ReturnString(THIS->matrix[state->cur.vertex++].name); + GB.ReturnString(THIS->matrix[state->v.vertex++].name); END_METHOD @@ -182,7 +193,7 @@ static int next_edge(CMATRIX *mat, unsigned int *srcp, unsigned int *dstp) BEGIN_METHOD_VOID(Matrix_nextEdge) struct enum_state *state = GB.GetEnum(); - unsigned int src = state->cur.edge.src, dst = state->cur.edge.dst; + unsigned int src = state->v.src, dst = state->v.dst; if (!state->e) { GB.Array.New(&state->e, GB_T_STRING, 2); @@ -198,7 +209,7 @@ BEGIN_METHOD_VOID(Matrix_nextEdge) GB.Unref(&state->e); return; } - state->cur.edge.src = src; state->cur.edge.dst = dst; + state->v.src = src; state->v.dst = dst; found:; GB_STRING str; @@ -234,6 +245,115 @@ BEGIN_METHOD_VOID(Matrix_countEdges) END_METHOD +static int next_edge_vertical(CMATRIX *mat, unsigned int *srcp, + unsigned int *dstp) +{ + unsigned int src = *srcp, dst = *dstp; + unsigned int count = GB.Count(mat->matrix); + + do { + src = (src + 1) % count; + if (!src) + dst++; + if (dst >= count) + return -1; + } while (!mat->matrix[src].edges[dst].set); + *srcp = src; + *dstp = dst; + return 0; +} + +BEGIN_METHOD_VOID(Matrix_nextInEdge) + + struct enum_state *state = GB.GetEnum(); + unsigned int src = state->v.src, dst = THIS->v.vertex; + + if (!state->e) { + dst = THIS->v.vertex = get_cur_vertex(THIS); + GB.Array.New(&state->e, GB_T_STRING, 2); + GB.Ref(state->e); + if (THIS->matrix[src].edges[dst].set) + goto found; + } + if (next_edge_vertical(THIS, &src, &dst) || dst != THIS->v.vertex) { + GB.StopEnum(); + GB.Unref(&state->e); + return; + } + state->v.src = src; +found:; + GB_STRING str; + + str.type = GB_T_STRING; + + str.value.addr = THIS->matrix[src].name; + str.value.start = 0; + str.value.len = GB.StringLength(str.value.addr); + GB.StoreString(&str, GB.Array.Get(state->e, 0)); + + str.value.addr = THIS->matrix[dst].name; + str.value.len = GB.StringLength(str.value.addr); + GB.StoreString(&str, GB.Array.Get(state->e, 1)); + GB.ReturnObject(state->e); + +END_METHOD + +BEGIN_METHOD_VOID(Matrix_nextOutEdge) + + struct enum_state *state = GB.GetEnum(); + unsigned int src = THIS->v.vertex, dst = state->v.dst; + + if (!state->e) { + src = THIS->v.vertex = get_cur_vertex(THIS); + GB.Array.New(&state->e, GB_T_STRING, 2); + GB.Ref(state->e); + if (THIS->matrix[src].edges[dst].set) + goto found; + } + if (next_edge(THIS, &src, &dst) || src != THIS->v.vertex) { + GB.StopEnum(); + GB.Unref(&state->e); + return; + } + state->v.dst = dst; +found:; + GB_STRING str; + + str.type = GB_T_STRING; + + str.value.addr = THIS->matrix[src].name; + str.value.start = 0; + str.value.len = GB.StringLength(str.value.addr); + GB.StoreString(&str, GB.Array.Get(state->e, 0)); + + str.value.addr = THIS->matrix[dst].name; + str.value.len = GB.StringLength(str.value.addr); + GB.StoreString(&str, GB.Array.Get(state->e, 1)); + GB.ReturnObject(state->e); + +END_METHOD + +BEGIN_METHOD_VOID(Matrix_nextAdjacent) + + struct enum_state *state = GB.GetEnum(); + unsigned int src = THIS->v.vertex, dst = state->v.dst; + + if (!state->e) { + src = THIS->v.vertex = get_cur_vertex(THIS); + state->e = (void *) 1; + if (THIS->matrix[src].edges[dst].set) + goto found; + } + if (next_edge(THIS, &src, &dst) || src != THIS->v.vertex) { + GB.StopEnum(); + return; + } + state->v.dst = dst; +found: + GB.ReturnString(THIS->matrix[dst].name); + +END_METHOD + /* TODO: This is used in Add() and Remove() to completely delete the gb.gsl * matrix. We could also enlarge/shrink it accordingly... */ static void invalidate_gsl_matrix(CMATRIX *mat) @@ -315,27 +435,24 @@ BEGIN_METHOD(Matrix_Remove, GB_STRING vert) END_METHOD -/**G - * A newly created edge has weight 1. You can use the return value of this - * method to change it. - */ -BEGIN_METHOD(Matrix_Connect, GB_STRING src; GB_STRING dst) +BEGIN_METHOD(Matrix_Connect, GB_STRING src; GB_STRING dst; GB_FLOAT w) unsigned int src = get_vertex(THIS, STRING(src), LENGTH(src)), dst = get_vertex(THIS, STRING(dst), LENGTH(dst)); + float w = VARGOPT(w, 1); if (src == -1 || dst == -1) { GB.Error(E_NOVERTEX); return; } THIS->matrix[src].edges[dst].set = 1; - THIS->matrix[src].edges[dst].weight = 1; - THIS->v.edge.src = src; THIS->v.edge.dst = dst; + THIS->matrix[src].edges[dst].weight = w; + THIS->v.src = src; THIS->v.dst = dst; update_gsl_matrix(THIS, src, dst); /* Duplicate if the graph is undirected */ if (!THIS->directed && src != dst) { THIS->matrix[dst].edges[src].set = 1; - THIS->matrix[dst].edges[src].weight = 1; + THIS->matrix[dst].edges[src].weight = w; update_gsl_matrix(THIS, dst, src); } @@ -408,8 +525,8 @@ GB_DESC CGraphMatrix[] = { GB_METHOD("_new", NULL, Matrix_new, "[(Directed)b(Weighted)b]"), GB_METHOD("_free", NULL, Matrix_free, NULL), - GB_METHOD("_getVertex", "_Matrix_Vertex", Matrix_getVertex, "(Vertex)s"), - GB_METHOD("_getEdge", "_Matrix_Edge", Matrix_getEdge, "(Src)s(Dst)s"), + GB_METHOD("_getVertex", ".Matrix.Vertex", Matrix_getVertex, "(Vertex)s"), + GB_METHOD("_getEdge", ".Matrix.Edge", Matrix_getEdge, "(Src)s(Dst)s"), GB_METHOD("_nextVertex", "s", Matrix_nextVertex, NULL), GB_METHOD("_nextEdge", "String[]", Matrix_nextEdge, NULL), @@ -417,11 +534,18 @@ GB_DESC CGraphMatrix[] = { GB_METHOD("_countVertices", "i", Matrix_countVertices, NULL), GB_METHOD("_countEdges", "i", Matrix_countEdges, NULL), - GB_METHOD("Add", "_Matrix_Vertex", Matrix_Add, "(Name)s"), + GB_METHOD("_nextInEdge", "String[]", Matrix_nextInEdge, NULL), + GB_METHOD("_nextOutEdge", "String[]", Matrix_nextOutEdge, NULL), + GB_METHOD("_nextAdjacent", "s", Matrix_nextAdjacent, NULL), + + GB_METHOD("Add", ".Matrix.Vertex", Matrix_Add, "(Name)s"), GB_METHOD("Remove", NULL, Matrix_Remove, "(Vertex)s"), - GB_METHOD("Connect", "_Matrix_Edge", Matrix_Connect, "(Src)s(Dst)s"), + GB_METHOD("Connect", ".Matrix.Edge", Matrix_Connect, "(Src)s(Dst)s[(Weight)f]"), GB_METHOD("Disconnect", NULL, Matrix_Disconnect, "(Src)s(Dst)s"), + GB_PROPERTY_SELF("Vertices", ".Matrix.Vertices"), + GB_PROPERTY_SELF("Edges", ".Matrix.Edges"), + /* * Require gb.gsl. */ @@ -431,97 +555,38 @@ GB_DESC CGraphMatrix[] = { GB_END_DECLARE }; -static int next_edge_vertical(CMATRIX *mat, unsigned int *srcp, - unsigned int *dstp) -{ - unsigned int src = *srcp, dst = *dstp; - unsigned int count = GB.Count(mat->matrix); +BEGIN_METHOD(MatrixVertices_get, GB_STRING vert) - do { - src = (src + 1) % count; - if (!src) - dst++; - if (dst >= count) - return -1; - } while (!mat->matrix[src].edges[dst].set); - *srcp = src; - *dstp = dst; - return 0; -} - -BEGIN_METHOD_VOID(MatrixVertex_nextInEdge) - - struct enum_state *state = GB.GetEnum(); - unsigned int src = state->cur.edge.src, dst = THIS->v.vertex; - - if (!state->e) { - GB.Array.New(&state->e, GB_T_STRING, 2); - GB.Ref(state->e); - if (THIS->matrix[src].edges[dst].set) - goto found; - } - if (next_edge_vertical(THIS, &src, &dst) || dst != THIS->v.vertex) { - GB.StopEnum(); - GB.Unref(&state->e); - return; - } - state->cur.edge.src = src; -found:; - GB_STRING str; - - str.type = GB_T_STRING; - - str.value.addr = THIS->matrix[src].name; - str.value.start = 0; - str.value.len = GB.StringLength(str.value.addr); - GB.StoreString(&str, GB.Array.Get(state->e, 0)); - - str.value.addr = THIS->matrix[dst].name; - str.value.len = GB.StringLength(str.value.addr); - GB.StoreString(&str, GB.Array.Get(state->e, 1)); - GB.ReturnObject(state->e); + THIS->v.vertex = get_vertex(THIS, STRING(vert), LENGTH(vert)); + GB.ReturnSelf(THIS); END_METHOD -BEGIN_METHOD_VOID(MatrixVertex_nextOutEdge) +GB_DESC CMatrixVertices[] = { + GB_DECLARE_VIRTUAL(".Matrix.Vertices"), + GB_INHERITS(".Graph.Vertices"), - struct enum_state *state = GB.GetEnum(); - unsigned int src = THIS->v.vertex, dst = state->cur.edge.dst; + GB_METHOD("_get", ".Matrix.Vertex", MatrixVertices_get, "(Vertex)s"), - if (!state->e) { - GB.Array.New(&state->e, GB_T_STRING, 2); - GB.Ref(state->e); - if (THIS->matrix[src].edges[dst].set) - goto found; - } - if (next_edge(THIS, &src, &dst) || src != THIS->v.vertex) { - GB.StopEnum(); - GB.Unref(&state->e); - return; - } - state->cur.edge.dst = dst; -found:; - GB_STRING str; + GB_END_DECLARE +}; - str.type = GB_T_STRING; +BEGIN_METHOD(MatrixEdges_get, GB_STRING src; GB_STRING dst) - str.value.addr = THIS->matrix[src].name; - str.value.start = 0; - str.value.len = GB.StringLength(str.value.addr); - GB.StoreString(&str, GB.Array.Get(state->e, 0)); - - str.value.addr = THIS->matrix[dst].name; - str.value.len = GB.StringLength(str.value.addr); - GB.StoreString(&str, GB.Array.Get(state->e, 1)); - GB.ReturnObject(state->e); + THIS->v.src = get_vertex(THIS, STRING(src), LENGTH(src)); + THIS->v.dst = get_vertex(THIS, STRING(dst), LENGTH(dst)); + GB.ReturnSelf(THIS); END_METHOD -BEGIN_METHOD_VOID(MatrixVertex_nextAdjacent) +GB_DESC CMatrixEdges[] = { + GB_DECLARE_VIRTUAL(".Matrix.Edges"), + GB_INHERITS(".Graph.Edges"), - /* TODO */ + GB_METHOD("_get", ".Matrix.Edge", MatrixEdges_get, "(Src)s(Dst)s"), -END_METHOD + GB_END_DECLARE +}; BEGIN_PROPERTY(MatrixVertex_InDegree) @@ -547,11 +612,18 @@ END_PROPERTY BEGIN_PROPERTY(MatrixVertex_Name) + char *name = THIS->matrix[THIS->v.vertex].name; + if (READ_PROPERTY) { - GB.ReturnString(THIS->matrix[THIS->v.vertex].name); + GB.ReturnString(name); return; } - /* delete old name from ->names, then register new one */ + GB.HashTable.Remove(THIS->names, name, GB.StringLength(name)); + GB.FreeString(&THIS->matrix[THIS->v.vertex].name); + THIS->matrix[THIS->v.vertex].name = + GB.NewString(PSTRING(), PLENGTH()); + GB.HashTable.Add(THIS->names, PSTRING(), PLENGTH(), + (void *) (intptr_t) THIS->v.vertex); END_PROPERTY @@ -566,13 +638,8 @@ BEGIN_PROPERTY(MatrixVertex_Value) END_METHOD GB_DESC CMatrixVertex[] = { - GB_DECLARE("_Matrix_Vertex", 0), - GB_INHERITS("_Graph_Vertex"), - GB_VIRTUAL_CLASS(), - - GB_METHOD("_nextInEdge", "String[]", MatrixVertex_nextInEdge, NULL), - GB_METHOD("_nextOutEdge", "String[]", MatrixVertex_nextOutEdge, NULL), - GB_METHOD("_nextAdjacent", "s", MatrixVertex_nextAdjacent, NULL), + GB_DECLARE_VIRTUAL(".Matrix.Vertex"), + GB_INHERITS(".Graph.Vertex"), GB_PROPERTY_READ("InDegree", "i", MatrixVertex_InDegree), GB_PROPERTY_READ("OutDegree", "i", MatrixVertex_OutDegree), @@ -584,7 +651,7 @@ GB_DESC CMatrixVertex[] = { BEGIN_PROPERTY(MatrixEdge_Src) - int src = THIS->v.edge.src; + int src = THIS->v.src; GB.ReturnString(THIS->matrix[src].name); @@ -592,7 +659,7 @@ END_PROPERTY BEGIN_PROPERTY(MatrixEdge_Dst) - int dst = THIS->v.edge.dst; + int dst = THIS->v.dst; GB.ReturnString(THIS->matrix[dst].name); @@ -600,7 +667,7 @@ END_PROPERTY BEGIN_PROPERTY(MatrixEdge_Weight) - int src = THIS->v.edge.src, dst = THIS->v.edge.dst; + int src = THIS->v.src, dst = THIS->v.dst; if (READ_PROPERTY) { GB.ReturnFloat(THIS->matrix[src].edges[dst].weight); @@ -613,9 +680,8 @@ BEGIN_PROPERTY(MatrixEdge_Weight) END_PROPERTY GB_DESC CMatrixEdge[] = { - GB_DECLARE("_Matrix_Edge", 0), - GB_INHERITS("_Graph_Edge"), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".Matrix.Edge"), + GB_INHERITS(".Graph.Edge"), GB_PROPERTY_READ("Src", "s", MatrixEdge_Src), GB_PROPERTY_READ("Dst", "s", MatrixEdge_Dst), diff --git a/main/lib/data/c_graphmatrix.h b/main/lib/data/c_graphmatrix.h index e15a763f1..fa1309e80 100644 --- a/main/lib/data/c_graphmatrix.h +++ b/main/lib/data/c_graphmatrix.h @@ -27,7 +27,8 @@ extern GB_INTERFACE GB; #ifndef __C_GRAPHMATRIX_C -extern GB_DESC CGraphMatrix[], CMatrixVertex[], CMatrixEdge[]; +extern GB_DESC CGraphMatrix[], CMatrixVertices[], CMatrixEdges[], + CMatrixVertex[], CMatrixEdge[]; #endif #endif /* __C_GRAPHMATRIX_H */ diff --git a/main/lib/data/c_list.c b/main/lib/data/c_list.c index bdff0cf3b..124dd34ce 100644 --- a/main/lib/data/c_list.c +++ b/main/lib/data/c_list.c @@ -1310,8 +1310,7 @@ GB_DESC CList[] = { }; GB_DESC CListBackwards[] = { - GB_DECLARE(".List.Backwards", 0), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".List.Backwards"), GB_METHOD("_next", "v", ListBackwards_next, NULL), @@ -1349,8 +1348,7 @@ BEGIN_PROPERTY(ListItem_IsValid) END_PROPERTY GB_DESC CListItem[] = { - GB_DECLARE(".List.Item", 0), - GB_VIRTUAL_CLASS(), + GB_DECLARE_VIRTUAL(".List.Item"), GB_METHOD("Append", NULL, ListItem_Append, "(Value)v"), GB_METHOD("Prepend", NULL, ListItem_Prepend, "(Value)v"), diff --git a/main/lib/data/main.c b/main/lib/data/main.c index 0dc6490f6..071105a2d 100644 --- a/main/lib/data/main.c +++ b/main/lib/data/main.c @@ -51,14 +51,16 @@ GB_DESC *GB_CLASSES[] EXPORT = { CGraph, CGraphVertices, - CGraphVertex, - CVertexInEdges, - CVertexOutEdges, - CVertexAdjacent, CGraphEdges, + CGraphInEdges, + CGraphOutEdges, + CGraphAdjacent, + CGraphVertex, CGraphEdge, CGraphMatrix, + CMatrixVertices, + CMatrixEdges, CMatrixVertex, CMatrixEdge,