Skip to content

Commit bf9e98b

Browse files
committed
feat: add NodeType enum and tags
1 parent e05269a commit bf9e98b

File tree

10 files changed

+34
-14
lines changed

10 files changed

+34
-14
lines changed

pydatastructs/graphs/_backend/cpp/AdjacencyList.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,12 @@ static PyObject* AdjacencyListGraph_new(PyTypeObject* type, PyObject* args, PyOb
6262
Py_ssize_t num_args = PyTuple_Size(args);
6363
for (Py_ssize_t i = 0; i < num_args; ++i) {
6464
PyObject* node_obj = PyTuple_GetItem(args, i);
65-
if (!PyObject_IsInstance(node_obj, (PyObject*)&AdjacencyListGraphNodeType)) {
65+
AdjacencyListGraphNode* node = reinterpret_cast<AdjacencyListGraphNode*>(node_obj);
66+
if (node->type_tag != NodeType::AdjacencyListGraphNode) {
6667
PyErr_SetString(PyExc_TypeError, "All arguments must be AdjacencyListGraphNode instances");
6768
return NULL;
6869
}
6970

70-
AdjacencyListGraphNode* node = reinterpret_cast<AdjacencyListGraphNode*>(node_obj);
71-
7271
if (self->node_map.find(node->name) != self->node_map.end()) {
7372
PyErr_Format(PyExc_ValueError, "Duplicate node with name '%s'", node->name.c_str());
7473
return NULL;
@@ -107,13 +106,12 @@ static PyObject* AdjacencyListGraph_add_vertex(AdjacencyListGraph* self, PyObjec
107106
return NULL;
108107
}
109108

110-
if (!PyObject_IsInstance(node_obj, (PyObject*)&AdjacencyListGraphNodeType)) {
109+
AdjacencyListGraphNode* node = reinterpret_cast<AdjacencyListGraphNode*>(node_obj);
110+
if (node->type_tag != NodeType::AdjacencyListGraphNode) {
111111
PyErr_SetString(PyExc_TypeError, "Object is not an AdjacencyListGraphNode");
112112
return NULL;
113113
}
114114

115-
AdjacencyListGraphNode* node = reinterpret_cast<AdjacencyListGraphNode*>(node_obj);
116-
117115
if (self->node_map.find(node->name) != self->node_map.end()) {
118116
PyErr_SetString(PyExc_ValueError, "Node with this name already exists");
119117
return NULL;

pydatastructs/graphs/_backend/cpp/AdjacencyMatrix.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ static PyObject* AdjacencyMatrixGraph_new(PyTypeObject* type, PyObject* args, Py
6666
Py_ssize_t len = PyTuple_Size(vertices);
6767
for (Py_ssize_t i = 0; i < len; ++i) {
6868
PyObject* item = PyTuple_GetItem(vertices, i);
69-
if (!PyObject_TypeCheck(item, &AdjacencyMatrixGraphNodeType)) {
69+
AdjacencyMatrixGraphNode* node = reinterpret_cast<AdjacencyMatrixGraphNode*>(item);
70+
if (node->super.type_tag != NodeType::AdjacencyMatrixGraphNode) {
7071
PyErr_SetString(PyExc_TypeError, "All elements must be AdjacencyMatrixGraphNode instances");
7172
Py_DECREF(self);
7273
return NULL;
7374
}
7475
Py_INCREF(item);
75-
AdjacencyMatrixGraphNode* node = reinterpret_cast<AdjacencyMatrixGraphNode*>(item);
7676
std::string name =(reinterpret_cast<GraphNode*>(node))->name;
7777
self->nodes.push_back(node);
7878
self->node_map[name] = node;

pydatastructs/graphs/_backend/cpp/Algorithms.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static PyObject* breadth_first_search_adjacency_list(PyObject* self, PyObject* a
4040

4141
for (const auto& [adj_name, adj_obj] : node->adjacent) {
4242
if (visited.count(adj_name)) continue;
43-
if (!PyObject_IsInstance(adj_obj, (PyObject*)&AdjacencyListGraphNodeType)) continue;
43+
if (reinterpret_cast<AdjacencyListGraphNode*>(adj_obj)->type_tag != NodeType::AdjacencyListGraphNode) continue;
4444

4545
AdjacencyListGraphNode* adj_node = reinterpret_cast<AdjacencyListGraphNode*>(adj_obj);
4646

pydatastructs/utils/_backend/cpp/AdjacencyListGraphNode.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern PyTypeObject AdjacencyListGraphNodeType;
1212

1313
typedef struct {
1414
PyObject_HEAD
15+
NodeType type_tag;
1516
std::string name;
1617
int internal_id;
1718
std::variant<std::monostate, int64_t, double, std::string, PyObject *> data;
@@ -34,6 +35,7 @@ static void AdjacencyListGraphNode_dealloc(AdjacencyListGraphNode* self) {
3435
static PyObject* AdjacencyListGraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
3536
AdjacencyListGraphNode* self = PyObject_New(AdjacencyListGraphNode, &AdjacencyListGraphNodeType);
3637
if (!self) return NULL;
38+
self->type_tag = NodeType::AdjacencyListGraphNode;
3739
new (&self->adjacent) std::unordered_map<std::string, PyObject*>();
3840
new (&self->name) std::string();
3941
new (&self->data) std::variant<std::monostate, int64_t, double, std::string, PyObject*>();

pydatastructs/utils/_backend/cpp/AdjacencyMatrixGraphNode.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static PyObject* AdjacencyMatrixGraphNode_new(PyTypeObject* type, PyObject* args
2323
}
2424

2525
AdjacencyMatrixGraphNode* self = reinterpret_cast<AdjacencyMatrixGraphNode*>(base_obj);
26+
self->super.type_tag = NodeType::AdjacencyMatrixGraphNode;
2627

2728
return reinterpret_cast<PyObject*>(self);
2829
}

pydatastructs/utils/_backend/cpp/GraphEdge.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern PyTypeObject GraphEdgeType;
1212

1313
typedef struct {
1414
PyObject_HEAD
15+
NodeType type_tag;
1516
PyObject* source;
1617
PyObject* target;
1718
std::variant<std::monostate, int64_t, double, std::string> value;
@@ -27,6 +28,7 @@ static void GraphEdge_dealloc(GraphEdge* self) {
2728
static PyObject* GraphEdge_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
2829
GraphEdge* self = PyObject_New(GraphEdge, &GraphEdgeType);
2930
if (!self) return NULL;
31+
self->type_tag = NodeType::GraphEdge;
3032

3133
new (&self->value) std::variant<std::monostate, int64_t, double, std::string>();
3234
self->value_type = DataType::None;

pydatastructs/utils/_backend/cpp/GraphNode.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <Python.h>
66
#include <string>
77
#include <variant>
8+
#include "Node.hpp"
89

910
enum class DataType {
1011
None,
@@ -16,6 +17,7 @@ enum class DataType {
1617

1718
typedef struct {
1819
PyObject_HEAD
20+
NodeType type_tag;
1921
std::string name;
2022
int internal_id;
2123
std::variant<std::monostate, int64_t, double, std::string, PyObject *> data;
@@ -32,6 +34,7 @@ static void GraphNode_dealloc(GraphNode* self) {
3234
static PyObject* GraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
3335
GraphNode* self = reinterpret_cast<GraphNode*>(type->tp_alloc(type, 0));
3436
if (!self) return NULL;
37+
self->type_tag = NodeType::GraphNode;
3538

3639
new (&self->name) std::string();
3740
new (&self->data) std::variant<std::monostate, int64_t, double, std::string, PyObject*>();

pydatastructs/utils/_backend/cpp/Node.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@
66
#include <structmember.h>
77
#include "utils.hpp"
88

9+
enum class NodeType {
10+
Node,
11+
TreeNode,
12+
GraphNode,
13+
AdjacencyListGraphNode,
14+
AdjacencyMatrixGraphNode,
15+
GraphEdge
16+
};
17+
918
typedef struct {
1019
PyObject_HEAD
20+
NodeType type_tag;
1121
} Node;
1222
// Node is an abstract class representing a Node
1323

@@ -16,7 +26,7 @@ static void Node_dealloc(Node *self) {
1626
}
1727

1828

19-
static PyTypeObject NodeType = {
29+
static PyTypeObject NodeObjectType = {
2030
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "Node",
2131
/* tp_basicsize */ sizeof(Node),
2232
/* tp_itemsize */ 0,

pydatastructs/utils/_backend/cpp/TreeNode.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
typedef struct {
1111
PyObject_HEAD
12+
NodeType type_tag;
1213
PyObject* key;
1314
PyObject* data; // can store None or a number
1415
PyObject* left; // can store None or a number
@@ -29,6 +30,9 @@ static void TreeNode_dealloc(TreeNode *self) {
2930
static PyObject* TreeNode___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) {
3031
TreeNode *self;
3132
self = reinterpret_cast<TreeNode*>(type->tp_alloc(type, 0));
33+
if (!self)
34+
return NULL;
35+
self->type_tag = NodeType::TreeNode;
3236

3337
// Assume that arguments are in the order below. Python code is such that this is true.
3438
self->key = PyObject_GetItem(args, PyZero);
@@ -100,7 +104,7 @@ static PyTypeObject TreeNodeType = {
100104
/* tp_methods */ 0,
101105
/* tp_members */ TreeNode_PyMemberDef,
102106
/* tp_getset */ 0,
103-
/* tp_base */ &NodeType, // Class Node is the base class
107+
/* tp_base */ &NodeObjectType, // Class Node is the base class
104108
/* tp_dict */ 0,
105109
/* tp_descr_get */ 0,
106110
/* tp_descr_set */ 0,

pydatastructs/utils/_backend/cpp/nodes.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ PyMODINIT_FUNC PyInit__nodes(void) {
1414
Py_Initialize();
1515
PyObject *nodes = PyModule_Create(&nodes_struct);
1616

17-
if (PyType_Ready(&NodeType) < 0) {
17+
if (PyType_Ready(&NodeObjectType) < 0) {
1818
return NULL;
1919
}
20-
Py_INCREF(&NodeType);
21-
PyModule_AddObject(nodes, "Node", reinterpret_cast<PyObject*>(&NodeType));
20+
Py_INCREF(&NodeObjectType);
21+
PyModule_AddObject(nodes, "Node", reinterpret_cast<PyObject*>(&NodeObjectType));
2222

2323
if (PyType_Ready(&TreeNodeType) < 0) {
2424
return NULL;

0 commit comments

Comments
 (0)