Skip to content

Commit c77c0e1

Browse files
Prerak Singhczgdp1807
Prerak Singh
authored andcommitted
added cpp backend for graph utilities
1 parent eb5fab1 commit c77c0e1

10 files changed

+644
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#ifndef ADJACENCY_LIST_GRAPH_NODE_HPP
2+
#define ADJACENCY_LIST_GRAPH_NODE_HPP
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
#include <string>
7+
#include <unordered_map>
8+
#include "GraphNode.hpp"
9+
10+
extern PyTypeObject AdjacencyListGraphNodeType;
11+
12+
typedef struct {
13+
PyObject_HEAD
14+
std::string name;
15+
PyObject* data;
16+
std::unordered_map<std::string, PyObject*> adjacent;
17+
} AdjacencyListGraphNode;
18+
19+
static void AdjacencyListGraphNode_dealloc(AdjacencyListGraphNode* self) {
20+
Py_XDECREF(self->data);
21+
for (auto& pair : self->adjacent) {
22+
Py_XDECREF(pair.second);
23+
}
24+
self->adjacent.~unordered_map<std::string, PyObject*>();
25+
Py_TYPE(self)->tp_free(reinterpret_cast<PyTypeObject*>(self));
26+
}
27+
28+
static PyObject* AdjacencyListGraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
29+
AdjacencyListGraphNode* self;
30+
self = reinterpret_cast<AdjacencyListGraphNode*>(type)->tp_alloc(type, 0);
31+
if (!self) return NULL;
32+
new (&self->adjacent) std::unordered_map<std::string, PyObject*>();
33+
34+
static char* kwlist[] = { "name", "data", "adjacency_list", NULL };
35+
const char* name;
36+
PyObject* data = Py_None;
37+
PyObject* adjacency_list = Py_None;
38+
39+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|OO", kwlist, &name, &data, &adjacency_list)) {
40+
PyErr_SetString(PyExc_ValueError, "Invalid arguments: Expected (str, object, list)");
41+
return NULL;
42+
}
43+
44+
self->name = std::string(name);
45+
Py_INCREF(data);
46+
self->data = data;
47+
48+
if (PyList_Check(adjacency_list)) {
49+
Py_ssize_t size = PyList_Size(adjacency_list);
50+
for (Py_ssize_t i = 0; i < size; i++) {
51+
PyObject* node = PyList_GetItem(adjacency_list, i);
52+
53+
54+
if (PyType_Ready(&AdjacencyListGraphNodeType) < 0) {
55+
PyErr_SetString(PyExc_RuntimeError, "Failed to initialize AdjacencyListGraphNodeType");
56+
return NULL;
57+
}
58+
59+
if (!PyObject_IsInstance(node, (PyObject*)&AdjacencyListGraphNodeType)) {
60+
PyErr_SetString(PyExc_TypeError, "Adjacency list must contain only AdjacencyListGraphNode instances");
61+
return NULL;
62+
}
63+
64+
const char* adj_name = (reinterpret_cast<AdjacencyListGraphNode*>(node))->name.c_str();
65+
std::string str = std::string(adj_name);
66+
Py_INCREF(node);
67+
self->adjacent[str] = node;
68+
}
69+
}
70+
71+
return reinterpret_cast<PyObject*>(self);
72+
}
73+
74+
static PyObject* AdjacencyListGraphNode_add_adjacent_node(AdjacencyListGraphNode* self, PyObject* args) {
75+
const char* name;
76+
PyObject* data = Py_None;
77+
if (!PyArg_ParseTuple(args, "s|O", &name, &data)) {
78+
PyErr_SetString(PyExc_ValueError, "Invalid arguments: Expected (str, object)");
79+
return NULL;
80+
}
81+
82+
if (self->adjacent.find(name) == self->adjacent.end()) {
83+
PyObject* new_node = PyObject_CallFunction(reinterpret_cast<PyObject*>(&AdjacencyListGraphNodeType), "sO", name, data);
84+
if (!new_node) {
85+
PyErr_SetString(PyExc_RuntimeError, "Failed to create adjacent node");
86+
return NULL;
87+
}
88+
self->adjacent[name] = new_node;
89+
Py_INCREF(new_node);
90+
} else {
91+
Py_XDECREF(self->adjacent[name]);
92+
Py_INCREF(data);
93+
self->adjacent[name] = data;
94+
}
95+
Py_RETURN_NONE;
96+
}
97+
98+
static PyObject* AdjacencyListGraphNode_remove_adjacent_node(AdjacencyListGraphNode* self, PyObject* args) {
99+
const char* name;
100+
if (!PyArg_ParseTuple(args, "s", &name)) {
101+
PyErr_SetString(PyExc_ValueError, "Invalid arguments: Expected (str)");
102+
return NULL;
103+
}
104+
105+
auto it = self->adjacent.find(name);
106+
if (it != self->adjacent.end()) {
107+
Py_XDECREF(it->second);
108+
self->adjacent.erase(it);
109+
Py_RETURN_NONE;
110+
} else {
111+
PyErr_SetString(PyExc_ValueError, "Node is not adjacent");
112+
return NULL;
113+
}
114+
}
115+
116+
static PyObject* AdjacencyListGraphNode_get_name(AdjacencyListGraphNode* self, void* closure) {
117+
return PyUnicode_FromString(self->name.c_str());
118+
}
119+
120+
static int AdjacencyListGraphNode_set_name(AdjacencyListGraphNode* self, PyObject* value, void* closure) {
121+
if (!PyUnicode_Check(value)) {
122+
PyErr_SetString(PyExc_TypeError, "name must be a string");
123+
return -1;
124+
}
125+
self->name = PyUnicode_AsUTF8(value);
126+
return 0;
127+
}
128+
129+
static PyObject* AdjacencyListGraphNode_get_data(AdjacencyListGraphNode* self, void* closure) {
130+
Py_INCREF(self->data);
131+
return self->data;
132+
}
133+
134+
static int AdjacencyListGraphNode_set_data(AdjacencyListGraphNode* self, PyObject* value, void* closure) {
135+
Py_XDECREF(self->data);
136+
Py_INCREF(value);
137+
self->data = value;
138+
return 0;
139+
}
140+
141+
static PyObject* AdjacencyListGraphNode_get_adjacent(AdjacencyListGraphNode* self, void* closure) {
142+
PyObject* py_dict = PyDict_New();
143+
if (!py_dict) return NULL;
144+
145+
for (const auto& pair : self->adjacent) {
146+
PyDict_SetItemString(py_dict, pair.first.c_str(), pair.second);
147+
}
148+
149+
return py_dict;
150+
}
151+
152+
static int AdjacencyListGraphNode_set_adjacent(AdjacencyListGraphNode* self, PyObject* value, void* closure) {
153+
if (!PyDict_Check(value)) {
154+
PyErr_SetString(PyExc_TypeError, "adjacent must be a dictionary");
155+
return -1;
156+
}
157+
158+
self->adjacent.clear();
159+
160+
PyObject *key, *val;
161+
Py_ssize_t pos = 0;
162+
while (PyDict_Next(value, &pos, &key, &val)) {
163+
if (!PyUnicode_Check(key) || !PyObject_IsInstance(val, (PyObject*)&AdjacencyListGraphNodeType)) {
164+
PyErr_SetString(PyExc_TypeError, "Keys must be strings and values must be AdjacencyListGraphNode instances");
165+
return -1;
166+
}
167+
168+
const char* key_str = PyUnicode_AsUTF8(key);
169+
Py_INCREF(val);
170+
self->adjacent[key_str] = val;
171+
}
172+
173+
return 0;
174+
}
175+
176+
static PyGetSetDef AdjacencyListGraphNode_getsetters[] = {
177+
{"name", (getter)AdjacencyListGraphNode_get_name, (setter)AdjacencyListGraphNode_set_name, "Get or set node name", NULL},
178+
{"data", (getter)AdjacencyListGraphNode_get_data, (setter)AdjacencyListGraphNode_set_data, "Get or set node data", NULL},
179+
{"adjacent", (getter)AdjacencyListGraphNode_get_adjacent, (setter)AdjacencyListGraphNode_set_adjacent, "Get or set adjacent nodes", NULL},
180+
{NULL}
181+
};
182+
183+
184+
static PyMethodDef AdjacencyListGraphNode_methods[] = {
185+
{"add_adjacent_node", (PyCFunction)AdjacencyListGraphNode_add_adjacent_node, METH_VARARGS, "Add adjacent node"},
186+
{"remove_adjacent_node", (PyCFunction)AdjacencyListGraphNode_remove_adjacent_node, METH_VARARGS, "Remove adjacent node"},
187+
{NULL}
188+
};
189+
190+
PyTypeObject AdjacencyListGraphNodeType = {
191+
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyListGraphNode",
192+
/* tp_basicsize */ sizeof(AdjacencyListGraphNode),
193+
/* tp_itemsize */ 0,
194+
/* tp_dealloc */ (destructor)AdjacencyListGraphNode_dealloc,
195+
/* tp_print */ 0,
196+
/* tp_getattr */ 0,
197+
/* tp_setattr */ 0,
198+
/* tp_reserved */ 0,
199+
/* tp_repr */ 0,
200+
/* tp_as_number */ 0,
201+
/* tp_as_sequence */ 0,
202+
/* tp_as_mapping */ 0,
203+
/* tp_hash */ 0,
204+
/* tp_call */ 0,
205+
/* tp_str */ 0,
206+
/* tp_getattro */ 0,
207+
/* tp_setattro */ 0,
208+
/* tp_as_buffer */ 0,
209+
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
210+
/* tp_doc */ "Node Data Structure for an Adjacency List Graph",
211+
/* tp_traverse */ 0,
212+
/* tp_clear */ 0,
213+
/* tp_richcompare */ 0,
214+
/* tp_weaklistoffset */ 0,
215+
/* tp_iter */ 0,
216+
/* tp_iternext */ 0,
217+
/* tp_methods */ AdjacencyListGraphNode_methods,
218+
/* tp_members */ 0,
219+
/* tp_getset */ AdjacencyListGraphNode_getsetters,
220+
/* tp_base */ &GraphNodeType,
221+
/* tp_dict */ 0,
222+
/* tp_descr_get */ 0,
223+
/* tp_descr_set */ 0,
224+
/* tp_dictoffset */ 0,
225+
/* tp_init */ 0,
226+
/* tp_alloc */ 0,
227+
/* tp_new */ AdjacencyListGraphNode_new,
228+
};
229+
230+
231+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#ifndef ADJACENCY_MATRIX_GRAPH_NODE_HPP
2+
#define ADJACENCY_MATRIX_GRAPH_NODE_HPP
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
#include <string>
7+
#include "GraphNode.hpp"
8+
9+
typedef struct {
10+
GraphNode super;
11+
} AdjacencyMatrixGraphNode;
12+
13+
static void AdjacencyMatrixGraphNode_dealloc(AdjacencyMatrixGraphNode* self){
14+
Py_XDECREF(self->super.data);
15+
Py_TYPE(self)->tp_free(reinterpret_cast<PyTypeObject*>(self));
16+
}xf
17+
18+
static PyObject* AdjacencyMatrixGraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwds){
19+
PyObject* base_obj = GraphNode_new(type, args, kwds);
20+
if (!base_obj) {
21+
return NULL;
22+
}
23+
24+
AdjacencyMatrixGraphNode* self = reinterpret_cast<AdjacencyMatrixGraphNode*>(base_obj);
25+
26+
return reinterpret_cast<PyObject*>(self);
27+
}
28+
29+
PyTypeObject AdjacencyMatrixGraphNodeType = {
30+
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AdjacencyMatrixGraphNode",
31+
/* tp_basicsize */ sizeof(AdjacencyMatrixGraphNode),
32+
/* tp_itemsize */ 0,
33+
/* tp_dealloc */ (destructor)AdjacencyMatrixGraphNode_dealloc,
34+
/* tp_print */ 0,
35+
/* tp_getattr */ 0,
36+
/* tp_setattr */ 0,
37+
/* tp_reserved */ 0,
38+
/* tp_repr */ 0,
39+
/* tp_as_number */ 0,
40+
/* tp_as_sequence */ 0,
41+
/* tp_as_mapping */ 0,
42+
/* tp_hash */ 0,
43+
/* tp_call */ 0,
44+
/* tp_str */ 0,
45+
/* tp_getattro */ 0,
46+
/* tp_setattro */ 0,
47+
/* tp_as_buffer */ 0,
48+
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
49+
/* tp_doc */ "Node Data Structure for an Adjacency Matrix Graph",
50+
/* tp_traverse */ 0,
51+
/* tp_clear */ 0,
52+
/* tp_richcompare */ 0,
53+
/* tp_weaklistoffset */ 0,
54+
/* tp_iter */ 0,
55+
/* tp_iternext */ 0,
56+
/* tp_methods */ 0,
57+
/* tp_members */ 0,
58+
/* tp_getset */ 0,
59+
/* tp_base */ &GraphNodeType,
60+
/* tp_dict */ 0,
61+
/* tp_descr_get */ 0,
62+
/* tp_descr_set */ 0,
63+
/* tp_dictoffset */ 0,
64+
/* tp_init */ 0,
65+
/* tp_alloc */ 0,
66+
/* tp_new */ AdjacencyMatrixGraphNode_new,
67+
};
68+
69+
#endif

0 commit comments

Comments
 (0)