@@ -10,29 +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- self->name .~basic_string ();
25- self->data .~decltype (self->data)();
26- 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));
2729}
2830
29- static PyObject* GraphNode_new (PyTypeObject* type, PyObject* args, PyObject* kwds){
30- GraphNode* self;
31- 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+
3235 new (&self->name ) std::string ();
33- 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* >();
3437 self->data_type = DataType::None;
35- if (!self) return NULL ;
3638
3739 static char * kwlist[] = { " name" , " data" , NULL };
3840 const char * name;
@@ -59,8 +61,9 @@ static PyObject* GraphNode_new(PyTypeObject* type, PyObject* args, PyObject* kwd
5961 self->data = std::string (s);
6062 self->data_type = DataType::String;
6163 } else {
62- PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" );
63- return NULL ;
64+ self->data = data;
65+ self->data_type = DataType::PyObject;
66+ Py_INCREF (data);
6467 }
6568
6669 return reinterpret_cast <PyObject*>(self);
@@ -82,15 +85,28 @@ static PyObject* GraphNode_str(GraphNode* self) {
8285 case DataType::String:
8386 repr += " '" + std::get<std::string>(self->data ) + " '" ;
8487 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+ }
8599 }
100+
86101 repr += " )" ;
87102 return PyUnicode_FromString (repr.c_str ());
88103}
89104
90105static PyObject* GraphNode_get (GraphNode* self, void *closure) {
91- if (closure == (void *)" name" ) {
106+ const char * attr = reinterpret_cast <const char *>(closure);
107+ if (strcmp (attr, " name" ) == 0 ) {
92108 return PyUnicode_FromString (self->name .c_str ());
93- } else if (closure == ( void *) " data" ) {
109+ } else if (strcmp (attr, " data" ) == 0 ) {
94110 switch (self->data_type ) {
95111 case DataType::None:
96112 Py_RETURN_NONE;
@@ -100,25 +116,32 @@ static PyObject* GraphNode_get(GraphNode* self, void *closure) {
100116 return PyFloat_FromDouble (std::get<double >(self->data ));
101117 case DataType::String:
102118 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 );
103122 }
104123 }
105124 Py_RETURN_NONE;
106125}
107126
108127static int GraphNode_set (GraphNode* self, PyObject *value, void *closure) {
128+ const char * attr = reinterpret_cast <const char *>(closure);
109129 if (!value) {
110130 PyErr_SetString (PyExc_ValueError, " Cannot delete attributes" );
111131 return -1 ;
112132 }
113133
114- if (closure == ( void *) " name" ) {
134+ if (strcmp (attr, " name" ) == 0 ) {
115135 if (!PyUnicode_Check (value)) {
116136 PyErr_SetString (PyExc_TypeError, " name must be a string" );
117137 return -1 ;
118138 }
119139 self->name = PyUnicode_AsUTF8 (value);
120- }
121- 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+
122145 if (value == Py_None) {
123146 self->data = std::monostate{};
124147 self->data_type = DataType::None;
@@ -132,8 +155,9 @@ static int GraphNode_set(GraphNode* self, PyObject *value, void *closure) {
132155 self->data = std::string (PyUnicode_AsUTF8 (value));
133156 self->data_type = DataType::String;
134157 } else {
135- PyErr_SetString (PyExc_TypeError, " data must be int, float, str, or None" );
136- return -1 ;
158+ Py_INCREF (value);
159+ self->data = value;
160+ self->data_type = DataType::PyObject;
137161 }
138162 } else {
139163 PyErr_SetString (PyExc_AttributeError, " Unknown attribute" );
0 commit comments