@@ -97,20 +97,36 @@ namespace cpp2py {
97
97
98
98
// default version is that the type is wrapped.
99
99
// Will be specialized for type which are just converted.
100
- template <typename T> struct py_converter {
100
+ template <typename TUREF> struct py_converter {
101
+
102
+ using T = std::decay_t <TUREF>;
103
+ static constexpr bool is_ref = std::is_reference_v<TUREF>;
101
104
102
105
typedef struct {
103
106
PyObject_HEAD;
104
107
T *_c;
108
+ PyObject *parent = nullptr ;
105
109
} py_type;
106
110
107
111
using is_wrapped_type = void ; // to recognize
108
112
109
- template <typename U> static PyObject *c2py (U &&x) {
113
+ template <typename U> static PyObject *c2py (U &&x, PyObject *parent = nullptr ) {
110
114
PyTypeObject *p = get_type_ptr (typeid (T));
111
115
if (p == nullptr ) return NULL ;
112
116
py_type *self = (py_type *)p->tp_alloc (p, 0 );
113
- if (self != NULL ) { self->_c = new T{std::forward<U>(x)}; }
117
+ if (self != NULL ) {
118
+ if constexpr (is_ref && wrapped_members_as_shared_refs) {
119
+ // Keep parent alive for lifetime of self
120
+ if (parent != nullptr ) {
121
+ self->parent = parent;
122
+ Py_INCREF (parent);
123
+ self->_c = &x;
124
+ return (PyObject *)self;
125
+ }
126
+ }
127
+ // Create heap copy of x to guarantee lifetime
128
+ self->_c = new T{std::forward<U>(x)};
129
+ }
114
130
return (PyObject *)self;
115
131
}
116
132
@@ -128,7 +144,7 @@ namespace cpp2py {
128
144
if (p == nullptr ) return false ;
129
145
if (PyObject_TypeCheck (ob, p)) {
130
146
if (((py_type *)ob)->_c != NULL ) return true ;
131
- auto err = std::string{" Severe internal error : Python object of " } + p->tp_name + " has a _c NULL pointer !!" ;
147
+ auto err = std::string{" Severe internal error : Python object of " } + p->tp_name + " has a _c NULL pointer !!" ;
132
148
if (raise_exception) PyErr_SetString (PyExc_TypeError, err.c_str ());
133
149
return false ;
134
150
}
@@ -138,6 +154,12 @@ namespace cpp2py {
138
154
}
139
155
};
140
156
157
+ // is_wrapped<T> if py_converter has been reimplemented.
158
+ template <typename T, class = void > struct is_wrapped : std::false_type {};
159
+ template <typename T> struct is_wrapped <T, typename py_converter<T>::is_wrapped_type> : std::true_type {};
160
+
161
+ template <typename T> constexpr bool is_wrapped_v = is_wrapped<T>::value;
162
+
141
163
// helpers for better error message
142
164
// some class (e.g. range !) only have ONE conversion, i.e. C -> Py, but not both
143
165
// we need to distinguish
@@ -149,9 +171,15 @@ namespace cpp2py {
149
171
struct does_have_a_converterC2Py <T, __std17::void_t <decltype (py_converter<std::decay_t <T>>::c2py(std::declval<T>()))>> : std::true_type {};
150
172
151
173
// We only use these functions in the code, not directly the converter
152
- template <typename T> static PyObject *convert_to_python (T &&x) {
174
+ template <typename T> static PyObject *convert_to_python (T &&x, PyObject *parent = nullptr ) {
153
175
static_assert (does_have_a_converterC2Py<T>::value, " The type does not have a converter from C++ to Python" );
154
- return py_converter<std::decay_t <T>>::c2py (std::forward<T>(x));
176
+ PyObject *r;
177
+ if constexpr (is_wrapped_v<std::decay_t <T>>) {
178
+ r = py_converter<T>::c2py (std::forward<T>(x), parent);
179
+ } else { // Converted type
180
+ r = py_converter<std::decay_t <T>>::c2py (std::forward<T>(x));
181
+ }
182
+ return r;
155
183
}
156
184
template <typename T> static bool convertible_from_python (PyObject *ob, bool raise_exception) {
157
185
return py_converter<T>::is_convertible (ob, raise_exception);
@@ -169,12 +197,6 @@ namespace cpp2py {
169
197
*
170
198
*/
171
199
172
- // is_wrapped<T> if py_converter has been reimplemented.
173
- template <typename T, class = void > struct is_wrapped : std::false_type {};
174
- template <typename T> struct is_wrapped <T, typename py_converter<T>::is_wrapped_type> : std::true_type {};
175
-
176
- template <typename T> constexpr bool is_wrapped_v = is_wrapped<T>::value;
177
-
178
200
template <typename T> static auto convert_from_python (PyObject *ob) -> decltype(py_converter<T>::py2c(ob)) {
179
201
static_assert (does_have_a_converterPy2C<T>::value, " The type does not have a converter from Python to C++" );
180
202
return py_converter<T>::py2c (ob);
0 commit comments