@@ -19,6 +19,10 @@ typedef struct {
19
19
std::vector<AdjacencyListGraphNode *> nodes;
20
20
std::unordered_map<std::string, GraphEdge*> edges;
21
21
std::unordered_map<std::string, AdjacencyListGraphNode*> node_map;
22
+ std::unordered_map<int , AdjacencyListGraphNode*> id_map;
23
+ std::unordered_map<int , std::string> id_to_name;
24
+ std::unordered_map<std::string, int > name_to_id;
25
+ int next_id;
22
26
23
27
} AdjacencyListGraph;
24
28
@@ -34,6 +38,9 @@ static void AdjacencyListGraph_dealloc(AdjacencyListGraph* self) {
34
38
self->edges .clear ();
35
39
36
40
self->node_map .clear ();
41
+ self->id_map .clear ();
42
+ self->id_to_name .clear ();
43
+ self->name_to_id .clear ();
37
44
38
45
Py_TYPE (self)->tp_free (reinterpret_cast <PyObject*>(self));
39
46
}
@@ -46,38 +53,38 @@ static PyObject* AdjacencyListGraph_new(PyTypeObject* type, PyObject* args, PyOb
46
53
new (&self->nodes ) std::vector<AdjacencyListGraphNode*>();
47
54
new (&self->edges ) std::unordered_map<std::string, GraphEdge*>();
48
55
new (&self->node_map ) std::unordered_map<std::string, AdjacencyListGraphNode*>();
56
+ new (&self->id_map ) std::unordered_map<int , AdjacencyListGraphNode*>();
57
+ new (&self->id_to_name ) std::unordered_map<int , std::string>();
58
+ new (&self->name_to_id ) std::unordered_map<std::string, int >();
59
+
60
+ self->next_id = 0 ;
49
61
50
62
Py_ssize_t num_args = PyTuple_Size (args);
51
63
for (Py_ssize_t i = 0 ; i < num_args; ++i) {
52
64
PyObject* node_obj = PyTuple_GetItem (args, i);
53
65
if (!PyObject_IsInstance (node_obj, (PyObject*)&AdjacencyListGraphNodeType)) {
54
66
PyErr_SetString (PyExc_TypeError, " All arguments must be AdjacencyListGraphNode instances" );
55
-
56
- self->nodes .~vector ();
57
- self->edges .~unordered_map ();
58
- self->node_map .~unordered_map ();
59
- Py_TYPE (self)->tp_free (reinterpret_cast <PyObject*>(self));
60
67
return NULL ;
61
68
}
62
69
63
70
AdjacencyListGraphNode* node = reinterpret_cast <AdjacencyListGraphNode*>(node_obj);
64
71
65
72
if (self->node_map .find (node->name ) != self->node_map .end ()) {
66
73
PyErr_Format (PyExc_ValueError, " Duplicate node with name '%s'" , node->name .c_str ());
67
-
68
- self->nodes .~vector ();
69
- self->edges .~unordered_map ();
70
- self->node_map .~unordered_map ();
71
- Py_TYPE (self)->tp_free (reinterpret_cast <PyObject*>(self));
72
74
return NULL ;
73
75
}
74
76
77
+ node->internal_id = self->next_id ++;
78
+
75
79
Py_INCREF (node);
76
80
self->nodes .push_back (node);
77
81
self->node_map [node->name ] = node;
82
+ self->id_map [node->internal_id ] = node;
83
+ self->id_to_name [node->internal_id ] = node->name ;
84
+ self->name_to_id [node->name ] = node->internal_id ;
78
85
}
79
- PyObject* impl_str = PyUnicode_FromString (" adjacency_list" );
80
86
87
+ PyObject* impl_str = PyUnicode_FromString (" adjacency_list" );
81
88
if (PyObject_SetAttrString (reinterpret_cast <PyObject*>(self), " _impl" , impl_str) < 0 ) {
82
89
Py_DECREF (impl_str);
83
90
PyErr_SetString (PyExc_RuntimeError, " Failed to set _impl attribute" );
@@ -112,9 +119,14 @@ static PyObject* AdjacencyListGraph_add_vertex(AdjacencyListGraph* self, PyObjec
112
119
return NULL ;
113
120
}
114
121
122
+ node->internal_id = self->next_id ++;
123
+
115
124
Py_INCREF (node);
116
125
self->nodes .push_back (node);
117
126
self->node_map [node->name ] = node;
127
+ self->id_map [node->internal_id ] = node;
128
+ self->id_to_name [node->internal_id ] = node->name ;
129
+ self->name_to_id [node->name ] = node->internal_id ;
118
130
119
131
Py_RETURN_NONE;
120
132
}
@@ -126,17 +138,15 @@ static PyObject* AdjacencyListGraph_is_adjacent(AdjacencyListGraph* self, PyObje
126
138
if (!PyArg_ParseTuple (args, " ss" , &node1_name_c, &node2_name_c))
127
139
return NULL ;
128
140
129
- std::string node1_name (node1_name_c);
130
- std::string node2_name (node2_name_c);
131
-
132
- auto it1 = self->node_map .find (node1_name);
133
- if (it1 == self->node_map .end ()) {
141
+ auto it1 = self->name_to_id .find (node1_name_c);
142
+ if (it1 == self->name_to_id .end ()) {
134
143
PyErr_SetString (PyExc_KeyError, " node1 not found" );
135
144
return NULL ;
136
145
}
137
- AdjacencyListGraphNode* node1 = it1->second ;
146
+ int id1 = it1->second ;
147
+ AdjacencyListGraphNode* node1 = self->id_map [id1];
138
148
139
- if (node1->adjacent .find (node2_name ) != node1->adjacent .end ()) {
149
+ if (node1->adjacent .find (node2_name_c ) != node1->adjacent .end ()) {
140
150
Py_RETURN_TRUE;
141
151
} else {
142
152
Py_RETURN_FALSE;
@@ -156,13 +166,13 @@ static PyObject* AdjacencyListGraph_neighbors(AdjacencyListGraph* self, PyObject
156
166
if (!PyArg_ParseTuple (args, " s" , &node_name_c))
157
167
return NULL ;
158
168
159
- std::string node_name (node_name_c);
160
- auto it = self->node_map .find (node_name);
161
- if (it == self->node_map .end ()) {
169
+ auto it = self->name_to_id .find (node_name_c);
170
+ if (it == self->name_to_id .end ()) {
162
171
PyErr_SetString (PyExc_KeyError, " Node not found" );
163
172
return NULL ;
164
173
}
165
- AdjacencyListGraphNode* node = it->second ;
174
+ int id = it->second ;
175
+ AdjacencyListGraphNode* node = self->id_map [id];
166
176
167
177
PyObject* neighbors_list = PyList_New (0 );
168
178
if (!neighbors_list) return NULL ;
@@ -180,23 +190,27 @@ static PyObject* AdjacencyListGraph_remove_vertex(AdjacencyListGraph* self, PyOb
180
190
if (!PyArg_ParseTuple (args, " s" , &name_c))
181
191
return NULL ;
182
192
183
- std::string name (name_c);
184
- auto it = self->node_map .find (name);
185
- if (it == self->node_map .end ()) {
193
+ auto it = self->name_to_id .find (name_c);
194
+ if (it == self->name_to_id .end ()) {
186
195
PyErr_SetString (PyExc_KeyError, " Node not found" );
187
196
return NULL ;
188
197
}
189
198
190
- AdjacencyListGraphNode* node_to_remove = it->second ;
199
+ int id = it->second ;
200
+ AdjacencyListGraphNode* node_to_remove = self->id_map [id];
201
+ std::string name = node_to_remove->name ;
191
202
192
203
auto & nodes_vec = self->nodes ;
193
204
nodes_vec.erase (std::remove (nodes_vec.begin (), nodes_vec.end (), node_to_remove), nodes_vec.end ());
194
205
195
- self->node_map .erase (it);
206
+ self->node_map .erase (name);
207
+ self->id_map .erase (id);
208
+ self->name_to_id .erase (name);
209
+ self->id_to_name .erase (id);
196
210
197
211
Py_XDECREF (node_to_remove);
198
212
199
- for (auto & node_pair : self->node_map ) {
213
+ for (auto & node_pair : self->id_map ) {
200
214
AdjacencyListGraphNode* node = node_pair.second ;
201
215
auto adj_it = node->adjacent .find (name);
202
216
if (adj_it != node->adjacent .end ()) {
@@ -207,17 +221,11 @@ static PyObject* AdjacencyListGraph_remove_vertex(AdjacencyListGraph* self, PyOb
207
221
208
222
for (auto it = self->edges .begin (); it != self->edges .end (); ) {
209
223
const std::string& key = it->first ;
210
-
211
- bool involves_node = false ;
212
224
size_t underscore = key.find (' _' );
213
- if (underscore != std::string::npos) {
214
- std::string source = key.substr (0 , underscore);
215
- std::string target = key.substr (underscore + 1 );
216
- if (source == name || target == name)
217
- involves_node = true ;
218
- }
225
+ std::string src = key.substr (0 , underscore);
226
+ std::string dst = key.substr (underscore + 1 );
219
227
220
- if (involves_node ) {
228
+ if (src == name || dst == name ) {
221
229
Py_XDECREF (it->second );
222
230
it = self->edges .erase (it);
223
231
} else {
0 commit comments