[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
This commit is contained in:
Tobias Boege 2014-09-13 03:01:37 +00:00
parent 6deb7f5ce6
commit 3a6db0ec55
8 changed files with 560 additions and 260 deletions

View File

@ -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.

View File

@ -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),

View File

@ -21,15 +21,30 @@
#define __C_GRAPH_C
#include <stdio.h>
#include <assert.h>
#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
};

View File

@ -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

View File

@ -21,10 +21,10 @@
#define __C_GRAPHMATRIX_C
#include <stdio.h>
#include <assert.h>
#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),

View File

@ -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 */

View File

@ -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"),

View File

@ -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,