|
@@ -0,0 +1,262 @@
|
|
|
|
+#ifndef _PY_GRAPH_MOD_H
|
|
|
|
+#define _PY_GRAPH_MOD_H
|
|
|
|
+
|
|
|
|
+#define PY_SSIZE_T_CLEAN
|
|
|
|
+
|
|
|
|
+#include <Python.h>
|
|
|
|
+#include <structmember.h>
|
|
|
|
+
|
|
|
|
+#include "graph.h"
|
|
|
|
+#include "triple_obj.h"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+typedef struct {
|
|
|
|
+ PyObject_HEAD
|
|
|
|
+ LSUP_Graph *ob_struct;
|
|
|
|
+} GraphObject;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+Graph_init (GraphObject *self, PyObject *args, PyObject *kwargs)
|
|
|
|
+{
|
|
|
|
+ unsigned char store_type;
|
|
|
|
+
|
|
|
|
+ if (!PyArg_ParseTuple (args, "b", &store_type))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ self->ob_struct = LSUP_graph_new ((LSUP_store_type)store_type);
|
|
|
|
+ if (!self->ob_struct) {
|
|
|
|
+ PyErr_SetString (PyExc_ValueError, "Could not create graph.");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+Graph_dealloc (GraphObject *self)
|
|
|
|
+{
|
|
|
|
+ LSUP_graph_free (self->ob_struct);
|
|
|
|
+ Py_TYPE (self)->tp_free ((PyObject *) self);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static PyObject *
|
|
|
|
+Graph_get_size (GraphObject *self, void *closure)
|
|
|
|
+{
|
|
|
|
+ size_t gr_size = LSUP_graph_size (self->ob_struct);
|
|
|
|
+ PyObject *size = PyLong_FromSize_t (gr_size);
|
|
|
|
+
|
|
|
|
+ Py_INCREF (size);
|
|
|
|
+ return size;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * FIXME This should be deleted and the setter set to NULL or omitted, but
|
|
|
|
+ * in doing so Python 3.8 raises a SystemError: bad call flags. See
|
|
|
|
+ * https://bugs.python.org/issue39884 No resolution is clear yet.
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+Graph_set_size (GraphObject *self, PyObject value, void *closure)
|
|
|
|
+{ return -1; }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static PyObject *
|
|
|
|
+Graph_get_uri (GraphObject *self, void *closure)
|
|
|
|
+{
|
|
|
|
+ PyObject *uri = PyUnicode_FromString (
|
|
|
|
+ LSUP_graph_uri (self->ob_struct)->data);
|
|
|
|
+
|
|
|
|
+ Py_INCREF (uri);
|
|
|
|
+ return uri;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+Graph_set_uri (GraphObject *self, PyObject *uri, void *closure)
|
|
|
|
+{
|
|
|
|
+ if (PyUnicode_READY (uri) != 0) return -1; // TODO redundant?
|
|
|
|
+ if (PyUnicode_KIND (uri) != PyUnicode_1BYTE_KIND) return -1;
|
|
|
|
+
|
|
|
|
+ LSUP_rc rc = LSUP_graph_set_uri (self->ob_struct, PyUnicode_DATA (uri));
|
|
|
|
+
|
|
|
|
+ return rc == LSUP_OK ? 0 : -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static PyGetSetDef Graph_getsetters[] = {
|
|
|
|
+ {
|
|
|
|
+ .name = "__len__",
|
|
|
|
+ .get = (getter) Graph_get_size,
|
|
|
|
+ .set = (setter) Graph_set_size,
|
|
|
|
+ .doc = "Number of triples in the graph.",
|
|
|
|
+ //.closure = NULL,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "uri", (getter) Graph_get_uri, (setter) Graph_set_uri,
|
|
|
|
+ "Graph URI.", NULL
|
|
|
|
+ },
|
|
|
|
+ {NULL}
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static PyObject *
|
|
|
|
+Graph_copy (PyTypeObject *cls, PyObject *src)
|
|
|
|
+{
|
|
|
|
+ if (! PyObject_TypeCheck (src, cls)) return NULL;
|
|
|
|
+
|
|
|
|
+ GraphObject *res = (GraphObject *) cls->tp_alloc(cls, 0);
|
|
|
|
+ if (!res) return NULL;
|
|
|
|
+
|
|
|
|
+ res->ob_struct = LSUP_graph_copy (((GraphObject *) src)->ob_struct);
|
|
|
|
+
|
|
|
|
+ Py_INCREF(res);
|
|
|
|
+ return (PyObject *) res;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* TODO implement LSUP_graph_equals
|
|
|
|
+static PyObject *
|
|
|
|
+Graph_richcmp (PyObject *gr1, PyObject *gr2, int op)
|
|
|
|
+{
|
|
|
|
+ if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED;
|
|
|
|
+
|
|
|
|
+ PyObject *res = NULL;
|
|
|
|
+
|
|
|
|
+ LSUP_Graph *t1 = ((GraphObject *) gr1)->ob_struct;
|
|
|
|
+ LSUP_Graph *t2 = ((GraphObject *) gr2)->ob_struct;
|
|
|
|
+
|
|
|
|
+ if (LSUP_graph_equals (t1, t2) && op == Py_EQ) Py_RETURN_TRUE;
|
|
|
|
+ Py_RETURN_FALSE;
|
|
|
|
+ }
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* TODO Implement mdbstore bool ops
|
|
|
|
+static inline PyObject *
|
|
|
|
+Graph_bool_op (
|
|
|
|
+ PyTypeObject *cls, LSUP_bool_op op, PyObject *gr1, PyObject *gr2)
|
|
|
|
+{
|
|
|
|
+ if (! PyObject_TypeCheck (gr1, cls) || ! PyObject_TypeCheck (gr2, cls))
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ GraphObject *res = (GraphObject *) cls->tp_alloc (cls, 0);
|
|
|
|
+ if (!res) return NULL;
|
|
|
|
+
|
|
|
|
+ res->ob_struct = LSUP_graph_bool_op (
|
|
|
|
+ op, ((GraphObject *) gr1)->ob_struct,
|
|
|
|
+ ((GraphObject *) gr2)->ob_struct);
|
|
|
|
+
|
|
|
|
+ Py_INCREF(res);
|
|
|
|
+ return (PyObject *) res;
|
|
|
|
+}
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int Graph_add (PyObject *self, PyObject *triples)
|
|
|
|
+{
|
|
|
|
+ // Triple may be any iterable.
|
|
|
|
+ if (! PyIter_Check (triples)) return -1;
|
|
|
|
+
|
|
|
|
+ PyObject *trp_obj = NULL;
|
|
|
|
+ int rc = 0;
|
|
|
|
+ size_t i;
|
|
|
|
+ LSUP_SerTriple *sspo = STRP_DUMMY;
|
|
|
|
+ LSUP_GraphIterator *it = LSUP_graph_add_stream_init (
|
|
|
|
+ ((GraphObject *)self)->ob_struct);
|
|
|
|
+
|
|
|
|
+ for (i = 0; (trp_obj = PyIter_Next (triples)); i++) {
|
|
|
|
+ if (!PyObject_TypeCheck (trp_obj, &TripleType)) {
|
|
|
|
+ rc = -1;
|
|
|
|
+ goto finalize;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TRACE ("Inserting triple #%lu\n", i);
|
|
|
|
+
|
|
|
|
+ LSUP_triple_serialize (((TripleObject *)trp_obj)->ob_struct, sspo);
|
|
|
|
+ LSUP_rc db_rc = LSUP_graph_add_stream_iter (it, sspo);
|
|
|
|
+
|
|
|
|
+ if (db_rc == LSUP_OK) rc = LSUP_OK;
|
|
|
|
+ if (UNLIKELY (db_rc < 0)) {
|
|
|
|
+ rc = -1;
|
|
|
|
+ goto finalize;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ LSUP_striple_free (sspo);
|
|
|
|
+
|
|
|
|
+finalize:
|
|
|
|
+ LSUP_graph_add_stream_done (it);
|
|
|
|
+ LSUP_striple_free (sspo);
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int Graph_remove (PyObject *self, PyObject *s, PyObject *p, PyObject *o)
|
|
|
|
+{
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static PyObject *Graph_lookup (
|
|
|
|
+ PyObject *self, PyObject *s, PyObject *p, PyObject *o)
|
|
|
|
+{
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static PyMethodDef Graph_methods[] = {
|
|
|
|
+ {"copy", (PyCFunction) Graph_copy, METH_CLASS, "Copy a graph."},
|
|
|
|
+ {"add", (PyCFunction) Graph_add, METH_O, "Add triples to a graph."},
|
|
|
|
+ {
|
|
|
|
+ "remove", (PyCFunction) Graph_remove, METH_VARARGS,
|
|
|
|
+ "Remove triples from a graph by matching a pattern."
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "lookup", (PyCFunction) Graph_lookup, METH_VARARGS,
|
|
|
|
+ "Look triples in a graph by matching a pattern."
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* TODO Implement mdbstore bool ops
|
|
|
|
+static inline PyObject *Graph_bool_and (
|
|
|
|
+ PyTypeObject *cls, PyObject *gr1, PyObject *gr2)
|
|
|
|
+{ return Graph_bool_op (cls, LSUP_BOOL_INTERSECTION, gr1, gr2); }
|
|
|
|
+
|
|
|
|
+static inline PyObject *Graph_bool_or (
|
|
|
|
+ PyTypeObject *cls, PyObject *gr1, PyObject *gr2)
|
|
|
|
+{ return Graph_bool_op (cls, LSUP_BOOL_UNION, gr1, gr2); }
|
|
|
|
+
|
|
|
|
+static inline PyObject *Graph_bool_subtract (
|
|
|
|
+ PyTypeObject *cls, PyObject *gr1, PyObject *gr2)
|
|
|
|
+{ return Graph_bool_op (cls, LSUP_BOOL_SUBTRACTION, gr1, gr2); }
|
|
|
|
+
|
|
|
|
+static inline PyObject *Graph_bool_xor (
|
|
|
|
+ PyTypeObject *cls, PyObject *gr1, PyObject *gr2)
|
|
|
|
+{ return Graph_bool_op (cls, LSUP_BOOL_XOR, gr1, gr2); }
|
|
|
|
+
|
|
|
|
+static PyNumberMethods Graph_number_methods = {
|
|
|
|
+ .nb_and = (binaryfunc) Graph_bool_and,
|
|
|
|
+ .nb_or = (binaryfunc) Graph_bool_or,
|
|
|
|
+ .nb_subtract = (binaryfunc) Graph_bool_subtract,
|
|
|
|
+ .nb_xor = (binaryfunc) Graph_bool_xor,
|
|
|
|
+};
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+PyTypeObject GraphType = {
|
|
|
|
+ PyVarObject_HEAD_INIT(NULL, 0)
|
|
|
|
+ .tp_name = "graph.Graph",
|
|
|
|
+ .tp_doc = "RDF graph",
|
|
|
|
+ .tp_basicsize = sizeof(GraphObject),
|
|
|
|
+ .tp_itemsize = 0,
|
|
|
|
+ .tp_flags = Py_TPFLAGS_DEFAULT,
|
|
|
|
+ .tp_new = PyType_GenericNew,
|
|
|
|
+ .tp_init = (initproc) Graph_init,
|
|
|
|
+ .tp_dealloc = (destructor) Graph_dealloc,
|
|
|
|
+ .tp_methods = Graph_methods,
|
|
|
|
+ .tp_getset = Graph_getsetters,
|
|
|
|
+ //.tp_richcompare = Graph_richcmp, TODO implement LSUP_graph_equals
|
|
|
|
+ //.tp_as_number = &Graph_number_methods,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#endif
|