@@ -10,27 +10,31 @@ enum class DataType {
10
10
None,
11
11
Int,
12
12
Double,
13
- String
13
+ String,
14
+ PyObject
14
15
};
15
16
16
17
typedef struct {
17
18
PyObject_HEAD
18
19
std::string name;
19
- std::variant<std::monostate, int64_t , double , std::string> data;
20
+ std::variant<std::monostate, int64_t , double , std::string, PyObject* > data;
20
21
DataType data_type;
21
22
} GraphNode;
22
23
23
- static void GraphNode_dealloc (GraphNode* self){
24
- Py_TYPE (self)->tp_free (reinterpret_cast <PyTypeObject*>(self));
24
+ static void GraphNode_dealloc (GraphNode* self) {
25
+ if (self->data_type == DataType::PyObject) {
26
+ Py_XDECREF (std::get<PyObject*>(self->data ));
27
+ }
28
+ Py_TYPE (self)->tp_free (reinterpret_cast <PyObject*>(self));
25
29
}
26
30
27
- static PyObject* GraphNode_new (PyTypeObject* type, PyObject* args, PyObject* kwds){
28
- GraphNode* self;
29
- self = reinterpret_cast <GraphNode*>(type->tp_alloc (type,0 ));
31
+ static PyObject* GraphNode_new (PyTypeObject* type, PyObject* args, PyObject* kwds) {
32
+ GraphNode* self = reinterpret_cast <GraphNode*>(type->tp_alloc (type, 0 ));
33
+ if (!self) return NULL ;
34
+
30
35
new (&self->name ) std::string ();
31
- new (&self->data ) std::variant<std::monostate, int64_t , double , std::string>();
36
+ new (&self->data ) std::variant<std::monostate, int64_t , double , std::string, PyObject* >();
32
37
self->data_type = DataType::None;
33
- if (!self) return NULL ;
34
38
35
39
static char * kwlist[] = { " name" , " data" , NULL };
36
40
const char * name;
@@ -57,8 +61,9 @@ static PyObject* GraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwd
57
61
self->data = std::string (s);
58
62
self->data_type = DataType::String;
59
63
} else {
60
- PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" );
61
- return NULL ;
64
+ self->data = data;
65
+ self->data_type = DataType::PyObject;
66
+ Py_INCREF (data);
62
67
}
63
68
64
69
return reinterpret_cast <PyObject*>(self);
@@ -80,15 +85,28 @@ static PyObject* GraphNode_str(GraphNode* self) {
80
85
case DataType::String:
81
86
repr += " '" + std::get<std::string>(self->data ) + " '" ;
82
87
break ;
88
+ case DataType::PyObject: {
89
+ PyObject* repr_obj = PyObject_Repr (std::get<PyObject*>(self->data ));
90
+ if (repr_obj) {
91
+ const char * repr_cstr = PyUnicode_AsUTF8 (repr_obj);
92
+ repr += repr_cstr ? repr_cstr : " <unprintable>" ;
93
+ Py_DECREF (repr_obj);
94
+ } else {
95
+ repr += " <error in repr>" ;
96
+ }
97
+ break ;
98
+ }
83
99
}
100
+
84
101
repr += " )" ;
85
102
return PyUnicode_FromString (repr.c_str ());
86
103
}
87
104
88
105
static PyObject* GraphNode_get (GraphNode* self, void *closure) {
89
- if (closure == (void *)" name" ) {
106
+ const char * attr = reinterpret_cast <const char *>(closure);
107
+ if (strcmp (attr, " name" ) == 0 ) {
90
108
return PyUnicode_FromString (self->name .c_str ());
91
- } else if (closure == ( void *) " data" ) {
109
+ } else if (strcmp (attr, " data" ) == 0 ) {
92
110
switch (self->data_type ) {
93
111
case DataType::None:
94
112
Py_RETURN_NONE;
@@ -98,25 +116,32 @@ static PyObject* GraphNode_get(GraphNode* self, void *closure) {
98
116
return PyFloat_FromDouble (std::get<double >(self->data ));
99
117
case DataType::String:
100
118
return PyUnicode_FromString (std::get<std::string>(self->data ).c_str ());
119
+ case DataType::PyObject:
120
+ Py_INCREF (std::get<PyObject*>(self->data ));
121
+ return std::get<PyObject*>(self->data );
101
122
}
102
123
}
103
124
Py_RETURN_NONE;
104
125
}
105
126
106
127
static int GraphNode_set (GraphNode* self, PyObject *value, void *closure) {
128
+ const char * attr = reinterpret_cast <const char *>(closure);
107
129
if (!value) {
108
130
PyErr_SetString (PyExc_ValueError, " Cannot delete attributes" );
109
131
return -1 ;
110
132
}
111
133
112
- if (closure == ( void *) " name" ) {
134
+ if (strcmp (attr, " name" ) == 0 ) {
113
135
if (!PyUnicode_Check (value)) {
114
136
PyErr_SetString (PyExc_TypeError, " name must be a string" );
115
137
return -1 ;
116
138
}
117
139
self->name = PyUnicode_AsUTF8 (value);
118
- }
119
- else if (closure == (void *)" data" ) {
140
+ } else if (strcmp (attr, " data" ) == 0 ) {
141
+ if (self->data_type == DataType::PyObject) {
142
+ Py_XDECREF (std::get<PyObject*>(self->data ));
143
+ }
144
+
120
145
if (value == Py_None) {
121
146
self->data = std::monostate{};
122
147
self->data_type = DataType::None;
@@ -130,8 +155,9 @@ static int GraphNode_set(GraphNode* self, PyObject *value, void *closure) {
130
155
self->data = std::string (PyUnicode_AsUTF8 (value));
131
156
self->data_type = DataType::String;
132
157
} else {
133
- PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" );
134
- return -1 ;
158
+ Py_INCREF (value);
159
+ self->data = value;
160
+ self->data_type = DataType::PyObject;
135
161
}
136
162
} else {
137
163
PyErr_SetString (PyExc_AttributeError, " Unknown attribute" );
0 commit comments