@@ -10,27 +10,31 @@ enum class DataType {
1010 None,
1111 Int,
1212 Double,
13- String
13+ String,
14+ PyObject
1415};
1516
1617typedef struct {
1718 PyObject_HEAD
1819 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;
2021 DataType data_type;
2122} GraphNode;
2223
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));
2529}
2630
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+
3035 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* >();
3237 self->data_type = DataType::None;
33- if (!self) return NULL ;
3438
3539 static char * kwlist[] = { " name" , " data" , NULL };
3640 const char * name;
@@ -57,8 +61,9 @@ static PyObject* GraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwd
5761 self->data = std::string (s);
5862 self->data_type = DataType::String;
5963 } 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);
6267 }
6368
6469 return reinterpret_cast <PyObject*>(self);
@@ -80,15 +85,28 @@ static PyObject* GraphNode_str(GraphNode* self) {
8085 case DataType::String:
8186 repr += " '" + std::get<std::string>(self->data ) + " '" ;
8287 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+ }
8399 }
100+
84101 repr += " )" ;
85102 return PyUnicode_FromString (repr.c_str ());
86103}
87104
88105static 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 ) {
90108 return PyUnicode_FromString (self->name .c_str ());
91- } else if (closure == ( void *) " data" ) {
109+ } else if (strcmp (attr, " data" ) == 0 ) {
92110 switch (self->data_type ) {
93111 case DataType::None:
94112 Py_RETURN_NONE;
@@ -98,25 +116,32 @@ static PyObject* GraphNode_get(GraphNode* self, void *closure) {
98116 return PyFloat_FromDouble (std::get<double >(self->data ));
99117 case DataType::String:
100118 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 );
101122 }
102123 }
103124 Py_RETURN_NONE;
104125}
105126
106127static int GraphNode_set (GraphNode* self, PyObject *value, void *closure) {
128+ const char * attr = reinterpret_cast <const char *>(closure);
107129 if (!value) {
108130 PyErr_SetString (PyExc_ValueError, " Cannot delete attributes" );
109131 return -1 ;
110132 }
111133
112- if (closure == ( void *) " name" ) {
134+ if (strcmp (attr, " name" ) == 0 ) {
113135 if (!PyUnicode_Check (value)) {
114136 PyErr_SetString (PyExc_TypeError, " name must be a string" );
115137 return -1 ;
116138 }
117139 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+
120145 if (value == Py_None) {
121146 self->data = std::monostate{};
122147 self->data_type = DataType::None;
@@ -130,8 +155,9 @@ static int GraphNode_set(GraphNode* self, PyObject *value, void *closure) {
130155 self->data = std::string (PyUnicode_AsUTF8 (value));
131156 self->data_type = DataType::String;
132157 } 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;
135161 }
136162 } else {
137163 PyErr_SetString (PyExc_AttributeError, " Unknown attribute" );
0 commit comments